[<prev] [next>] [<thread-prev] [day] [month] [year] [list]
Message-ID: <alpine.DEB.2.02.1506220053020.12845@promg-1n-a-dhcp378.eng.vmware.com>
Date: Mon, 22 Jun 2015 00:54:51 -0700 (PDT)
From: Shreyas Bhatewara <sbhatewara@...are.com>
To: netdev@...r.kernel.org
cc: pv-drivers@...are.com, rachel_lunnon@...rmagic.com
Subject: Re: [net-next] vmxnet3: Changes for vmxnet3 adapter version 2
(fwd)
Reposting with correct version number.
--
Make the driver understand adapter version 2.
Cc: Rachel Lunnon <rachel_lunnon@...rmagic.com>
Signed-off-by: Guolin Yang <gyang@...are.com>
Signed-off-by: Shreyas N Bhatewara <sbhatewara@...are.com>
--
diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h
index 3718d02..221a530 100644
--- a/drivers/net/vmxnet3/vmxnet3_defs.h
+++ b/drivers/net/vmxnet3/vmxnet3_defs.h
@@ -1,7 +1,7 @@
/*
* 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
* under the terms of the GNU General Public License as published by the
@@ -277,6 +277,40 @@ struct Vmxnet3_RxCompDesc {
#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] */
#define VMXNET3_RCD_TUC_SHIFT 16
#define VMXNET3_RCD_IPC_SHIFT 19
@@ -310,6 +344,7 @@ union Vmxnet3_GenericDesc {
struct Vmxnet3_RxDesc rxd;
struct Vmxnet3_TxCompDesc tcd;
struct Vmxnet3_RxCompDesc rcd;
+ struct Vmxnet3_RxCompDescExt rcdExt;
};
#define VMXNET3_INIT_GEN 1
@@ -361,6 +396,7 @@ enum {
/* completion descriptor types */
#define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */
#define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */
+#define VMXNET3_CDTYPE_RXCOMP_LRO 4 /* Rx Completion Descriptor for LRO */
enum {
VMXNET3_GOS_BITS_UNK = 0, /* unknown */
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index ab53975..da11bb5 100644
--- a/drivers/net/vmxnet3/vmxnet3_drv.c
+++ b/drivers/net/vmxnet3/vmxnet3_drv.c
@@ -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
vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
struct vmxnet3_adapter *adapter, int quota)
@@ -1174,6 +1220,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
bool skip_page_frags = false;
struct Vmxnet3_RxCompDesc *rcd;
struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
+ u16 segCnt = 0, mss = 0;
#ifdef __BIG_ENDIAN_BITFIELD
struct Vmxnet3_RxDesc rxCmdDesc;
struct Vmxnet3_RxCompDesc rxComp;
@@ -1262,7 +1309,19 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
PCI_DMA_FROMDEVICE);
rxd->addr = cpu_to_le64(rbi->dma_addr);
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 {
BUG_ON(ctx->skb == NULL && !skip_page_frags);
@@ -1311,12 +1370,40 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
skb = ctx->skb;
if (rcd->eop) {
+ u32 mtu = adapter->netdev->mtu;
skb->len += skb->data_len;
vmxnet3_rx_csum(adapter, skb,
(union Vmxnet3_GenericDesc *)rcd);
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))
__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;
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);
+ adapter->version = 1;
} else {
dev_err(&pdev->dev,
"Incompatible h/w version (0x%x) for adapter\n", ver);
err = -EBUSY;
goto err_ver;
}
+ dev_dbg(&pdev->dev, "Using device version %d\n", adapter->version);
ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS);
if (ver & 1) {
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 6bb769a..2652245 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -69,10 +69,10 @@
/*
* Version numbers
*/
-#define VMXNET3_DRIVER_VERSION_STRING "1.3.5.0-k"
+#define VMXNET3_DRIVER_VERSION_STRING "1.4.2.0-k"
/* a 32-bit int, each byte encode a verion number in VMXNET3_DRIVER_VERSION */
-#define VMXNET3_DRIVER_VERSION_NUM 0x01030500
+#define VMXNET3_DRIVER_VERSION_NUM 0x01040200
#if defined(CONFIG_PCI_MSI)
/* RSS only makes sense if MSI-X is supported. */
@@ -328,6 +328,10 @@ struct vmxnet3_adapter {
u8 __iomem *hw_addr0; /* for BAR 0 */
u8 __iomem *hw_addr1; /* for BAR 1 */
+ u8 version;
+
+ bool rxcsum;
+ bool lro;
#ifdef VMXNET3_RSS
struct UPT1_RSSConf *rss_conf;
--
To unsubscribe from this list: send the line "unsubscribe netdev" in
Powered by blists - more mailing lists