aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/vmxnet3/vmxnet3_defs.h38
-rw-r--r--drivers/net/vmxnet3/vmxnet3_drv.c98
-rw-r--r--drivers/net/vmxnet3/vmxnet3_int.h4
3 files changed, 136 insertions, 4 deletions
diff --git a/drivers/net/vmxnet3/vmxnet3_defs.h b/drivers/net/vmxnet3/vmxnet3_defs.h
index 3718d024f638..221a53025fd0 100644
--- a/drivers/net/vmxnet3/vmxnet3_defs.h
+++ b/drivers/net/vmxnet3/vmxnet3_defs.h
@@ -1,7 +1,7 @@
1/* 1/*
2 * Linux driver for VMware's vmxnet3 ethernet NIC. 2 * Linux driver for VMware's vmxnet3 ethernet NIC.
3 * 3 *
4 * Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved. 4 * Copyright (C) 2008-2015, VMware, Inc. All Rights Reserved.
5 * 5 *
6 * This program is free software; you can redistribute it and/or modify it 6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the 7 * under the terms of the GNU General Public License as published by the
@@ -277,6 +277,40 @@ struct Vmxnet3_RxCompDesc {
277#endif /* __BIG_ENDIAN_BITFIELD */ 277#endif /* __BIG_ENDIAN_BITFIELD */
278}; 278};
279 279
280struct Vmxnet3_RxCompDescExt {
281 __le32 dword1;
282 u8 segCnt; /* Number of aggregated packets */
283 u8 dupAckCnt; /* Number of duplicate Acks */
284 __le16 tsDelta; /* TCP timestamp difference */
285 __le32 dword2;
286#ifdef __BIG_ENDIAN_BITFIELD
287 u32 gen:1; /* generation bit */
288 u32 type:7; /* completion type */
289 u32 fcs:1; /* Frame CRC correct */
290 u32 frg:1; /* IP Fragment */
291 u32 v4:1; /* IPv4 */
292 u32 v6:1; /* IPv6 */
293 u32 ipc:1; /* IP Checksum Correct */
294 u32 tcp:1; /* TCP packet */
295 u32 udp:1; /* UDP packet */
296 u32 tuc:1; /* TCP/UDP Checksum Correct */
297 u32 mss:16;
298#else
299 u32 mss:16;
300 u32 tuc:1; /* TCP/UDP Checksum Correct */
301 u32 udp:1; /* UDP packet */
302 u32 tcp:1; /* TCP packet */
303 u32 ipc:1; /* IP Checksum Correct */
304 u32 v6:1; /* IPv6 */
305 u32 v4:1; /* IPv4 */
306 u32 frg:1; /* IP Fragment */
307 u32 fcs:1; /* Frame CRC correct */
308 u32 type:7; /* completion type */
309 u32 gen:1; /* generation bit */
310#endif /* __BIG_ENDIAN_BITFIELD */
311};
312
313
280/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */ 314/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
281#define VMXNET3_RCD_TUC_SHIFT 16 315#define VMXNET3_RCD_TUC_SHIFT 16
282#define VMXNET3_RCD_IPC_SHIFT 19 316#define VMXNET3_RCD_IPC_SHIFT 19
@@ -310,6 +344,7 @@ union Vmxnet3_GenericDesc {
310 struct Vmxnet3_RxDesc rxd; 344 struct Vmxnet3_RxDesc rxd;
311 struct Vmxnet3_TxCompDesc tcd; 345 struct Vmxnet3_TxCompDesc tcd;
312 struct Vmxnet3_RxCompDesc rcd; 346 struct Vmxnet3_RxCompDesc rcd;
347 struct Vmxnet3_RxCompDescExt rcdExt;
313}; 348};
314 349
315#define VMXNET3_INIT_GEN 1 350#define VMXNET3_INIT_GEN 1
@@ -361,6 +396,7 @@ enum {
361/* completion descriptor types */ 396/* completion descriptor types */
362#define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */ 397#define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */
363#define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */ 398#define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */
399#define VMXNET3_CDTYPE_RXCOMP_LRO 4 /* Rx Completion Descriptor for LRO */
364 400
365enum { 401enum {
366 VMXNET3_GOS_BITS_UNK = 0, /* unknown */ 402 VMXNET3_GOS_BITS_UNK = 0, /* unknown */
diff --git a/drivers/net/vmxnet3/vmxnet3_drv.c b/drivers/net/vmxnet3/vmxnet3_drv.c
index ab539758bec1..da11bb5e9c7f 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,
1163} 1163}
1164 1164
1165 1165
1166static u32
1167vmxnet3_get_hdr_len(struct vmxnet3_adapter *adapter, struct sk_buff *skb,
1168 union Vmxnet3_GenericDesc *gdesc)
1169{
1170 u32 hlen, maplen;
1171 union {
1172 void *ptr;
1173 struct ethhdr *eth;
1174 struct iphdr *ipv4;
1175 struct ipv6hdr *ipv6;
1176 struct tcphdr *tcp;
1177 } hdr;
1178 BUG_ON(gdesc->rcd.tcp == 0);
1179
1180 maplen = skb_headlen(skb);
1181 if (unlikely(sizeof(struct iphdr) + sizeof(struct tcphdr) > maplen))
1182 return 0;
1183
1184 hdr.eth = eth_hdr(skb);
1185 if (gdesc->rcd.v4) {
1186 BUG_ON(hdr.eth->h_proto != htons(ETH_P_IP));
1187 hdr.ptr += sizeof(struct ethhdr);
1188 BUG_ON(hdr.ipv4->protocol != IPPROTO_TCP);
1189 hlen = hdr.ipv4->ihl << 2;
1190 hdr.ptr += hdr.ipv4->ihl << 2;
1191 } else if (gdesc->rcd.v6) {
1192 BUG_ON(hdr.eth->h_proto != htons(ETH_P_IPV6));
1193 hdr.ptr += sizeof(struct ethhdr);
1194 /* Use an estimated value, since we also need to handle
1195 * TSO case.
1196 */
1197 if (hdr.ipv6->nexthdr != IPPROTO_TCP)
1198 return sizeof(struct ipv6hdr) + sizeof(struct tcphdr);
1199 hlen = sizeof(struct ipv6hdr);
1200 hdr.ptr += sizeof(struct ipv6hdr);
1201 } else {
1202 /* Non-IP pkt, dont estimate header length */
1203 return 0;
1204 }
1205
1206 if (hlen + sizeof(struct tcphdr) > maplen)
1207 return 0;
1208
1209 return (hlen + (hdr.tcp->doff << 2));
1210}
1211
1166static int 1212static int
1167vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, 1213vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
1168 struct vmxnet3_adapter *adapter, int quota) 1214 struct vmxnet3_adapter *adapter, int quota)
@@ -1174,6 +1220,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
1174 bool skip_page_frags = false; 1220 bool skip_page_frags = false;
1175 struct Vmxnet3_RxCompDesc *rcd; 1221 struct Vmxnet3_RxCompDesc *rcd;
1176 struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx; 1222 struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
1223 u16 segCnt = 0, mss = 0;
1177#ifdef __BIG_ENDIAN_BITFIELD 1224#ifdef __BIG_ENDIAN_BITFIELD
1178 struct Vmxnet3_RxDesc rxCmdDesc; 1225 struct Vmxnet3_RxDesc rxCmdDesc;
1179 struct Vmxnet3_RxCompDesc rxComp; 1226 struct Vmxnet3_RxCompDesc rxComp;
@@ -1262,7 +1309,19 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
1262 PCI_DMA_FROMDEVICE); 1309 PCI_DMA_FROMDEVICE);
1263 rxd->addr = cpu_to_le64(rbi->dma_addr); 1310 rxd->addr = cpu_to_le64(rbi->dma_addr);
1264 rxd->len = rbi->len; 1311 rxd->len = rbi->len;
1265 1312 if (adapter->version == 2 &&
1313 rcd->type == VMXNET3_CDTYPE_RXCOMP_LRO) {
1314 struct Vmxnet3_RxCompDescExt *rcdlro;
1315 rcdlro = (struct Vmxnet3_RxCompDescExt *)rcd;
1316
1317 segCnt = rcdlro->segCnt;
1318 BUG_ON(segCnt <= 1);
1319 mss = rcdlro->mss;
1320 if (unlikely(segCnt <= 1))
1321 segCnt = 0;
1322 } else {
1323 segCnt = 0;
1324 }
1266 } else { 1325 } else {
1267 BUG_ON(ctx->skb == NULL && !skip_page_frags); 1326 BUG_ON(ctx->skb == NULL && !skip_page_frags);
1268 1327
@@ -1311,12 +1370,40 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
1311 1370
1312 skb = ctx->skb; 1371 skb = ctx->skb;
1313 if (rcd->eop) { 1372 if (rcd->eop) {
1373 u32 mtu = adapter->netdev->mtu;
1314 skb->len += skb->data_len; 1374 skb->len += skb->data_len;
1315 1375
1316 vmxnet3_rx_csum(adapter, skb, 1376 vmxnet3_rx_csum(adapter, skb,
1317 (union Vmxnet3_GenericDesc *)rcd); 1377 (union Vmxnet3_GenericDesc *)rcd);
1318 skb->protocol = eth_type_trans(skb, adapter->netdev); 1378 skb->protocol = eth_type_trans(skb, adapter->netdev);
1319 1379 if (!rcd->tcp || !adapter->lro)
1380 goto not_lro;
1381
1382 if (segCnt != 0 && mss != 0) {
1383 skb_shinfo(skb)->gso_type = rcd->v4 ?
1384 SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
1385 skb_shinfo(skb)->gso_size = mss;
1386 skb_shinfo(skb)->gso_segs = segCnt;
1387 } else if (segCnt != 0 || skb->len > mtu) {
1388 u32 hlen;
1389
1390 hlen = vmxnet3_get_hdr_len(adapter, skb,
1391 (union Vmxnet3_GenericDesc *)rcd);
1392 if (hlen == 0)
1393 goto not_lro;
1394
1395 skb_shinfo(skb)->gso_type =
1396 rcd->v4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6;
1397 if (segCnt != 0) {
1398 skb_shinfo(skb)->gso_segs = segCnt;
1399 skb_shinfo(skb)->gso_size =
1400 DIV_ROUND_UP(skb->len -
1401 hlen, segCnt);
1402 } else {
1403 skb_shinfo(skb)->gso_size = mtu - hlen;
1404 }
1405 }
1406not_lro:
1320 if (unlikely(rcd->ts)) 1407 if (unlikely(rcd->ts))
1321 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci); 1408 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci);
1322 1409
@@ -3041,14 +3128,19 @@ vmxnet3_probe_device(struct pci_dev *pdev,
3041 goto err_alloc_pci; 3128 goto err_alloc_pci;
3042 3129
3043 ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS); 3130 ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS);
3044 if (ver & 1) { 3131 if (ver & 2) {
3132 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 2);
3133 adapter->version = 2;
3134 } else if (ver & 1) {
3045 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1); 3135 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1);
3136 adapter->version = 1;
3046 } else { 3137 } else {
3047 dev_err(&pdev->dev, 3138 dev_err(&pdev->dev,
3048 "Incompatible h/w version (0x%x) for adapter\n", ver); 3139 "Incompatible h/w version (0x%x) for adapter\n", ver);
3049 err = -EBUSY; 3140 err = -EBUSY;
3050 goto err_ver; 3141 goto err_ver;
3051 } 3142 }
3143 dev_dbg(&pdev->dev, "Using device version %d\n", adapter->version);
3052 3144
3053 ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS); 3145 ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS);
3054 if (ver & 1) { 3146 if (ver & 1) {
diff --git a/drivers/net/vmxnet3/vmxnet3_int.h b/drivers/net/vmxnet3/vmxnet3_int.h
index 6bb769ae7de9..e9f1075f7d4c 100644
--- a/drivers/net/vmxnet3/vmxnet3_int.h
+++ b/drivers/net/vmxnet3/vmxnet3_int.h
@@ -328,6 +328,10 @@ struct vmxnet3_adapter {
328 328
329 u8 __iomem *hw_addr0; /* for BAR 0 */ 329 u8 __iomem *hw_addr0; /* for BAR 0 */
330 u8 __iomem *hw_addr1; /* for BAR 1 */ 330 u8 __iomem *hw_addr1; /* for BAR 1 */
331 u8 version;
332
333 bool rxcsum;
334 bool lro;
331 335
332#ifdef VMXNET3_RSS 336#ifdef VMXNET3_RSS
333 struct UPT1_RSSConf *rss_conf; 337 struct UPT1_RSSConf *rss_conf;