Skip to content

Commit 45dac1d

Browse files
Shreyas Bhatewaradavem330
authored andcommitted
vmxnet3: Changes for vmxnet3 adapter version 2 (fwd)
Make the driver understand adapter version 2. Cc: Rachel Lunnon <[email protected]> Signed-off-by: Guolin Yang <[email protected]> Signed-off-by: Shreyas N Bhatewara <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent c41fcce commit 45dac1d

File tree

3 files changed

+136
-4
lines changed

3 files changed

+136
-4
lines changed

drivers/net/vmxnet3/vmxnet3_defs.h

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
/*
22
* Linux driver for VMware's vmxnet3 ethernet NIC.
33
*
4-
* Copyright (C) 2008-2009, VMware, Inc. All Rights Reserved.
4+
* Copyright (C) 2008-2015, VMware, Inc. All Rights Reserved.
55
*
66
* This program is free software; you can redistribute it and/or modify it
77
* under the terms of the GNU General Public License as published by the
@@ -277,6 +277,40 @@ struct Vmxnet3_RxCompDesc {
277277
#endif /* __BIG_ENDIAN_BITFIELD */
278278
};
279279

280+
struct 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+
280314
/* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */
281315
#define VMXNET3_RCD_TUC_SHIFT 16
282316
#define VMXNET3_RCD_IPC_SHIFT 19
@@ -310,6 +344,7 @@ union Vmxnet3_GenericDesc {
310344
struct Vmxnet3_RxDesc rxd;
311345
struct Vmxnet3_TxCompDesc tcd;
312346
struct Vmxnet3_RxCompDesc rcd;
347+
struct Vmxnet3_RxCompDescExt rcdExt;
313348
};
314349

315350
#define VMXNET3_INIT_GEN 1
@@ -361,6 +396,7 @@ enum {
361396
/* completion descriptor types */
362397
#define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */
363398
#define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */
399+
#define VMXNET3_CDTYPE_RXCOMP_LRO 4 /* Rx Completion Descriptor for LRO */
364400

365401
enum {
366402
VMXNET3_GOS_BITS_UNK = 0, /* unknown */

drivers/net/vmxnet3/vmxnet3_drv.c

Lines changed: 95 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1163,6 +1163,52 @@ vmxnet3_rx_error(struct vmxnet3_rx_queue *rq, struct Vmxnet3_RxCompDesc *rcd,
11631163
}
11641164

11651165

1166+
static u32
1167+
vmxnet3_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+
11661212
static int
11671213
vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
11681214
struct vmxnet3_adapter *adapter, int quota)
@@ -1174,6 +1220,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
11741220
bool skip_page_frags = false;
11751221
struct Vmxnet3_RxCompDesc *rcd;
11761222
struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx;
1223+
u16 segCnt = 0, mss = 0;
11771224
#ifdef __BIG_ENDIAN_BITFIELD
11781225
struct Vmxnet3_RxDesc rxCmdDesc;
11791226
struct Vmxnet3_RxCompDesc rxComp;
@@ -1262,7 +1309,19 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
12621309
PCI_DMA_FROMDEVICE);
12631310
rxd->addr = cpu_to_le64(rbi->dma_addr);
12641311
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+
}
12661325
} else {
12671326
BUG_ON(ctx->skb == NULL && !skip_page_frags);
12681327

@@ -1311,12 +1370,40 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
13111370

13121371
skb = ctx->skb;
13131372
if (rcd->eop) {
1373+
u32 mtu = adapter->netdev->mtu;
13141374
skb->len += skb->data_len;
13151375

13161376
vmxnet3_rx_csum(adapter, skb,
13171377
(union Vmxnet3_GenericDesc *)rcd);
13181378
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+
}
1406+
not_lro:
13201407
if (unlikely(rcd->ts))
13211408
__vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci);
13221409

@@ -3041,14 +3128,19 @@ vmxnet3_probe_device(struct pci_dev *pdev,
30413128
goto err_alloc_pci;
30423129

30433130
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) {
30453135
VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1);
3136+
adapter->version = 1;
30463137
} else {
30473138
dev_err(&pdev->dev,
30483139
"Incompatible h/w version (0x%x) for adapter\n", ver);
30493140
err = -EBUSY;
30503141
goto err_ver;
30513142
}
3143+
dev_dbg(&pdev->dev, "Using device version %d\n", adapter->version);
30523144

30533145
ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS);
30543146
if (ver & 1) {

drivers/net/vmxnet3/vmxnet3_int.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,10 @@ struct vmxnet3_adapter {
328328

329329
u8 __iomem *hw_addr0; /* for BAR 0 */
330330
u8 __iomem *hw_addr1; /* for BAR 1 */
331+
u8 version;
332+
333+
bool rxcsum;
334+
bool lro;
331335

332336
#ifdef VMXNET3_RSS
333337
struct UPT1_RSSConf *rss_conf;

0 commit comments

Comments
 (0)