vmxnet3: Changes for vmxnet3 adapter version 2 (fwd)
Make the driver understand adapter version 2. Cc: Rachel Lunnon <rachel_lunnon@stormagic.com> Signed-off-by: Guolin Yang <gyang@vmware.com> Signed-off-by: Shreyas N Bhatewara <sbhatewara@vmware.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
parent
c41fcce997
commit
45dac1d6ea
@ -1,7 +1,7 @@
|
|||||||
/*
|
/*
|
||||||
* Linux driver for VMware's vmxnet3 ethernet NIC.
|
* Linux driver for VMware's vmxnet3 ethernet NIC.
|
||||||
*
|
*
|
||||||
* Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
|
* Copyright (C) 2008-2015, VMware, Inc. All Rights Reserved.
|
||||||
*
|
*
|
||||||
* This program is free software; you can redistribute it and/or modify it
|
* This program is free software; you can redistribute it and/or modify it
|
||||||
* under the terms of the GNU General Public License as published by the
|
* under the terms of the GNU General Public License as published by the
|
||||||
@ -277,6 +277,40 @@ struct Vmxnet3_RxCompDesc {
|
|||||||
#endif /* __BIG_ENDIAN_BITFIELD */
|
#endif /* __BIG_ENDIAN_BITFIELD */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct Vmxnet3_RxCompDescExt {
|
||||||
|
__le32 dword1;
|
||||||
|
u8 segCnt; /* Number of aggregated packets */
|
||||||
|
u8 dupAckCnt; /* Number of duplicate Acks */
|
||||||
|
__le16 tsDelta; /* TCP timestamp difference */
|
||||||
|
__le32 dword2;
|
||||||
|
#ifdef __BIG_ENDIAN_BITFIELD
|
||||||
|
u32 gen:1; /* generation bit */
|
||||||
|
u32 type:7; /* completion type */
|
||||||
|
u32 fcs:1; /* Frame CRC correct */
|
||||||
|
u32 frg:1; /* IP Fragment */
|
||||||
|
u32 v4:1; /* IPv4 */
|
||||||
|
u32 v6:1; /* IPv6 */
|
||||||
|
u32 ipc:1; /* IP Checksum Correct */
|
||||||
|
u32 tcp:1; /* TCP packet */
|
||||||
|
u32 udp:1; /* UDP packet */
|
||||||
|
u32 tuc:1; /* TCP/UDP Checksum Correct */
|
||||||
|
u32 mss:16;
|
||||||
|
#else
|
||||||
|
u32 mss:16;
|
||||||
|
u32 tuc:1; /* TCP/UDP Checksum Correct */
|
||||||
|
u32 udp:1; /* UDP packet */
|
||||||
|
u32 tcp:1; /* TCP packet */
|
||||||
|
u32 ipc:1; /* IP Checksum Correct */
|
||||||
|
u32 v6:1; /* IPv6 */
|
||||||
|
u32 v4:1; /* IPv4 */
|
||||||
|
u32 frg:1; /* IP Fragment */
|
||||||
|
u32 fcs:1; /* Frame CRC correct */
|
||||||
|
u32 type:7; /* completion type */
|
||||||
|
u32 gen:1; /* generation bit */
|
||||||
|
#endif /* __BIG_ENDIAN_BITFIELD */
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
|
/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
|
||||||
#define VMXNET3_RCD_TUC_SHIFT 16
|
#define VMXNET3_RCD_TUC_SHIFT 16
|
||||||
#define VMXNET3_RCD_IPC_SHIFT 19
|
#define VMXNET3_RCD_IPC_SHIFT 19
|
||||||
@ -310,6 +344,7 @@ union Vmxnet3_GenericDesc {
|
|||||||
struct Vmxnet3_RxDesc rxd;
|
struct Vmxnet3_RxDesc rxd;
|
||||||
struct Vmxnet3_TxCompDesc tcd;
|
struct Vmxnet3_TxCompDesc tcd;
|
||||||
struct Vmxnet3_RxCompDesc rcd;
|
struct Vmxnet3_RxCompDesc rcd;
|
||||||
|
struct Vmxnet3_RxCompDescExt rcdExt;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define VMXNET3_INIT_GEN 1
|
#define VMXNET3_INIT_GEN 1
|
||||||
@ -361,6 +396,7 @@ enum {
|
|||||||
/* completion descriptor types */
|
/* completion descriptor types */
|
||||||
#define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */
|
#define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */
|
||||||
#define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */
|
#define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */
|
||||||
|
#define VMXNET3_CDTYPE_RXCOMP_LRO 4 /* Rx Completion Descriptor for LRO */
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
VMXNET3_GOS_BITS_UNK = 0, /* unknown */
|
VMXNET3_GOS_BITS_UNK = 0, /* unknown */
|
||||||
|
@ -1163,6 +1163,52 @@ vmxnet3_rx_error(struct vmxnet3_rx_queue *rq, struct Vmxnet3_RxCompDesc *rcd,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static u32
|
||||||
|
vmxnet3_get_hdr_len(struct vmxnet3_adapter *adapter, struct sk_buff *skb,
|
||||||
|
union Vmxnet3_GenericDesc *gdesc)
|
||||||
|
{
|
||||||
|
u32 hlen, maplen;
|
||||||
|
union {
|
||||||
|
void *ptr;
|
||||||
|
struct ethhdr *eth;
|
||||||
|
struct iphdr *ipv4;
|
||||||
|
struct ipv6hdr *ipv6;
|
||||||
|
struct tcphdr *tcp;
|
||||||
|
} hdr;
|
||||||
|
BUG_ON(gdesc->rcd.tcp == 0);
|
||||||
|
|
||||||
|
maplen = skb_headlen(skb);
|
||||||
|
if (unlikely(sizeof(struct iphdr) + sizeof(struct tcphdr) > maplen))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
hdr.eth = eth_hdr(skb);
|
||||||
|
if (gdesc->rcd.v4) {
|
||||||
|
BUG_ON(hdr.eth->h_proto != htons(ETH_P_IP));
|
||||||
|
hdr.ptr += sizeof(struct ethhdr);
|
||||||
|
BUG_ON(hdr.ipv4->protocol != IPPROTO_TCP);
|
||||||
|
hlen = hdr.ipv4->ihl << 2;
|
||||||
|
hdr.ptr += hdr.ipv4->ihl << 2;
|
||||||
|
} else if (gdesc->rcd.v6) {
|
||||||
|
BUG_ON(hdr.eth->h_proto != htons(ETH_P_IPV6));
|
||||||
|
hdr.ptr += sizeof(struct ethhdr);
|
||||||
|
/* Use an estimated value, since we also need to handle
|
||||||
|
* TSO case.
|
||||||
|
*/
|
||||||
|
if (hdr.ipv6->nexthdr != IPPROTO_TCP)
|
||||||
|
return sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
|
||||||
|
hlen = sizeof(struct ipv6hdr);
|
||||||
|
hdr.ptr += sizeof(struct ipv6hdr);
|
||||||
|
} else {
|
||||||
|
/* Non-IP pkt, dont estimate header length */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hlen + sizeof(struct tcphdr) > maplen)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return (hlen + (hdr.tcp->doff << 2));
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
|
vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
|
||||||
struct vmxnet3_adapter *adapter, int quota)
|
struct vmxnet3_adapter *adapter, int quota)
|
||||||
@ -1174,6 +1220,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
|
|||||||
bool skip_page_frags = false;
|
bool skip_page_frags = false;
|
||||||
struct Vmxnet3_RxCompDesc *rcd;
|
struct Vmxnet3_RxCompDesc *rcd;
|
||||||
struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
|
struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
|
||||||
|
u16 segCnt = 0, mss = 0;
|
||||||
#ifdef __BIG_ENDIAN_BITFIELD
|
#ifdef __BIG_ENDIAN_BITFIELD
|
||||||
struct Vmxnet3_RxDesc rxCmdDesc;
|
struct Vmxnet3_RxDesc rxCmdDesc;
|
||||||
struct Vmxnet3_RxCompDesc rxComp;
|
struct Vmxnet3_RxCompDesc rxComp;
|
||||||
@ -1262,7 +1309,19 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
|
|||||||
PCI_DMA_FROMDEVICE);
|
PCI_DMA_FROMDEVICE);
|
||||||
rxd->addr = cpu_to_le64(rbi->dma_addr);
|
rxd->addr = cpu_to_le64(rbi->dma_addr);
|
||||||
rxd->len = rbi->len;
|
rxd->len = rbi->len;
|
||||||
|
if (adapter->version == 2 &&
|
||||||
|
rcd->type == VMXNET3_CDTYPE_RXCOMP_LRO) {
|
||||||
|
struct Vmxnet3_RxCompDescExt *rcdlro;
|
||||||
|
rcdlro = (struct Vmxnet3_RxCompDescExt *)rcd;
|
||||||
|
|
||||||
|
segCnt = rcdlro->segCnt;
|
||||||
|
BUG_ON(segCnt <= 1);
|
||||||
|
mss = rcdlro->mss;
|
||||||
|
if (unlikely(segCnt <= 1))
|
||||||
|
segCnt = 0;
|
||||||
|
} else {
|
||||||
|
segCnt = 0;
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
BUG_ON(ctx->skb == NULL && !skip_page_frags);
|
BUG_ON(ctx->skb == NULL && !skip_page_frags);
|
||||||
|
|
||||||
@ -1311,12 +1370,40 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
|
|||||||
|
|
||||||
skb = ctx->skb;
|
skb = ctx->skb;
|
||||||
if (rcd->eop) {
|
if (rcd->eop) {
|
||||||
|
u32 mtu = adapter->netdev->mtu;
|
||||||
skb->len += skb->data_len;
|
skb->len += skb->data_len;
|
||||||
|
|
||||||
vmxnet3_rx_csum(adapter, skb,
|
vmxnet3_rx_csum(adapter, skb,
|
||||||
(union Vmxnet3_GenericDesc *)rcd);
|
(union Vmxnet3_GenericDesc *)rcd);
|
||||||
skb->protocol = eth_type_trans(skb, adapter->netdev);
|
skb->protocol = eth_type_trans(skb, adapter->netdev);
|
||||||
|
if (!rcd->tcp || !adapter->lro)
|
||||||
|
goto not_lro;
|
||||||
|
|
||||||
|
if (segCnt != 0 && mss != 0) {
|
||||||
|
skb_shinfo(skb)->gso_type = rcd->v4 ?
|
||||||
|
SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
|
||||||
|
skb_shinfo(skb)->gso_size = mss;
|
||||||
|
skb_shinfo(skb)->gso_segs = segCnt;
|
||||||
|
} else if (segCnt != 0 || skb->len > mtu) {
|
||||||
|
u32 hlen;
|
||||||
|
|
||||||
|
hlen = vmxnet3_get_hdr_len(adapter, skb,
|
||||||
|
(union Vmxnet3_GenericDesc *)rcd);
|
||||||
|
if (hlen == 0)
|
||||||
|
goto not_lro;
|
||||||
|
|
||||||
|
skb_shinfo(skb)->gso_type =
|
||||||
|
rcd->v4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
|
||||||
|
if (segCnt != 0) {
|
||||||
|
skb_shinfo(skb)->gso_segs = segCnt;
|
||||||
|
skb_shinfo(skb)->gso_size =
|
||||||
|
DIV_ROUND_UP(skb->len -
|
||||||
|
hlen, segCnt);
|
||||||
|
} else {
|
||||||
|
skb_shinfo(skb)->gso_size = mtu - hlen;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
not_lro:
|
||||||
if (unlikely(rcd->ts))
|
if (unlikely(rcd->ts))
|
||||||
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci);
|
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci);
|
||||||
|
|
||||||
@ -3041,14 +3128,19 @@ vmxnet3_probe_device(struct pci_dev *pdev,
|
|||||||
goto err_alloc_pci;
|
goto err_alloc_pci;
|
||||||
|
|
||||||
ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS);
|
ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS);
|
||||||
if (ver & 1) {
|
if (ver & 2) {
|
||||||
|
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 2);
|
||||||
|
adapter->version = 2;
|
||||||
|
} else if (ver & 1) {
|
||||||
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1);
|
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1);
|
||||||
|
adapter->version = 1;
|
||||||
} else {
|
} else {
|
||||||
dev_err(&pdev->dev,
|
dev_err(&pdev->dev,
|
||||||
"Incompatible h/w version (0x%x) for adapter\n", ver);
|
"Incompatible h/w version (0x%x) for adapter\n", ver);
|
||||||
err = -EBUSY;
|
err = -EBUSY;
|
||||||
goto err_ver;
|
goto err_ver;
|
||||||
}
|
}
|
||||||
|
dev_dbg(&pdev->dev, "Using device version %d\n", adapter->version);
|
||||||
|
|
||||||
ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS);
|
ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS);
|
||||||
if (ver & 1) {
|
if (ver & 1) {
|
||||||
|
@ -328,6 +328,10 @@ struct vmxnet3_adapter {
|
|||||||
|
|
||||||
u8 __iomem *hw_addr0; /* for BAR 0 */
|
u8 __iomem *hw_addr0; /* for BAR 0 */
|
||||||
u8 __iomem *hw_addr1; /* for BAR 1 */
|
u8 __iomem *hw_addr1; /* for BAR 1 */
|
||||||
|
u8 version;
|
||||||
|
|
||||||
|
bool rxcsum;
|
||||||
|
bool lro;
|
||||||
|
|
||||||
#ifdef VMXNET3_RSS
|
#ifdef VMXNET3_RSS
|
||||||
struct UPT1_RSSConf *rss_conf;
|
struct UPT1_RSSConf *rss_conf;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user