Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Shreyas Bhatewara and committed by
David S. Miller
45dac1d6 c41fcce9

+134 -2
+37 -1
drivers/net/vmxnet3/vmxnet3_defs.h
··· 1 1 /* 2 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 6 * This program is free software; you can redistribute it and/or modify it 7 7 * under the terms of the GNU General Public License as published by the ··· 277 277 #endif /* __BIG_ENDIAN_BITFIELD */ 278 278 }; 279 279 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 + 280 314 /* fields in RxCompDesc we access via Vmxnet3_GenericDesc.dword[3] */ 281 315 #define VMXNET3_RCD_TUC_SHIFT 16 282 316 #define VMXNET3_RCD_IPC_SHIFT 19 ··· 344 310 struct Vmxnet3_RxDesc rxd; 345 311 struct Vmxnet3_TxCompDesc tcd; 346 312 struct Vmxnet3_RxCompDesc rcd; 313 + struct Vmxnet3_RxCompDescExt rcdExt; 347 314 }; 348 315 349 316 #define VMXNET3_INIT_GEN 1 ··· 396 361 /* completion descriptor types */ 397 362 #define VMXNET3_CDTYPE_TXCOMP 0 /* Tx Completion Descriptor */ 398 363 #define VMXNET3_CDTYPE_RXCOMP 3 /* Rx Completion Descriptor */ 364 + #define VMXNET3_CDTYPE_RXCOMP_LRO 4 /* Rx Completion Descriptor for LRO */ 399 365 400 366 enum { 401 367 VMXNET3_GOS_BITS_UNK = 0, /* unknown */
+93 -1
drivers/net/vmxnet3/vmxnet3_drv.c
··· 1163 1163 } 1164 1164 1165 1165 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 + 1166 1212 static int 1167 1213 vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq, 1168 1214 struct vmxnet3_adapter *adapter, int quota) ··· 1220 1174 bool skip_page_frags = false; 1221 1175 struct Vmxnet3_RxCompDesc *rcd; 1222 1176 struct vmxnet3_rx_ctx *ctx = &rq->rx_ctx; 1177 + u16 segCnt = 0, mss = 0; 1223 1178 #ifdef __BIG_ENDIAN_BITFIELD 1224 1179 struct Vmxnet3_RxDesc rxCmdDesc; 1225 1180 struct Vmxnet3_RxCompDesc rxComp; ··· 1309 1262 PCI_DMA_FROMDEVICE); 1310 1263 rxd->addr = cpu_to_le64(rbi->dma_addr); 1311 1264 rxd->len = rbi->len; 1265 + if (adapter->version == 2 && 1266 + rcd->type == VMXNET3_CDTYPE_RXCOMP_LRO) { 1267 + struct Vmxnet3_RxCompDescExt *rcdlro; 1268 + rcdlro = (struct Vmxnet3_RxCompDescExt *)rcd; 1312 1269 1270 + segCnt = rcdlro->segCnt; 1271 + BUG_ON(segCnt <= 1); 1272 + mss = rcdlro->mss; 1273 + if (unlikely(segCnt <= 1)) 1274 + segCnt = 0; 1275 + } else { 1276 + segCnt = 0; 1277 + } 1313 1278 } else { 1314 1279 BUG_ON(ctx->skb == NULL && !skip_page_frags); 1315 1280 ··· 1370 1311 1371 1312 skb = ctx->skb; 1372 1313 if (rcd->eop) { 1314 + u32 mtu = adapter->netdev->mtu; 1373 1315 skb->len += skb->data_len; 1374 1316 1375 1317 vmxnet3_rx_csum(adapter, skb, 1376 1318 (union Vmxnet3_GenericDesc *)rcd); 1377 1319 skb->protocol = eth_type_trans(skb, adapter->netdev); 1320 + if (!rcd->tcp || !adapter->lro) 1321 + goto not_lro; 1378 1322 1323 + if (segCnt != 0 && mss != 0) { 1324 + skb_shinfo(skb)->gso_type = rcd->v4 ? 1325 + SKB_GSO_TCPV4 : SKB_GSO_TCPV6; 1326 + skb_shinfo(skb)->gso_size = mss; 1327 + skb_shinfo(skb)->gso_segs = segCnt; 1328 + } else if (segCnt != 0 || skb->len > mtu) { 1329 + u32 hlen; 1330 + 1331 + hlen = vmxnet3_get_hdr_len(adapter, skb, 1332 + (union Vmxnet3_GenericDesc *)rcd); 1333 + if (hlen == 0) 1334 + goto not_lro; 1335 + 1336 + skb_shinfo(skb)->gso_type = 1337 + rcd->v4 ? SKB_GSO_TCPV4 : SKB_GSO_TCPV6; 1338 + if (segCnt != 0) { 1339 + skb_shinfo(skb)->gso_segs = segCnt; 1340 + skb_shinfo(skb)->gso_size = 1341 + DIV_ROUND_UP(skb->len - 1342 + hlen, segCnt); 1343 + } else { 1344 + skb_shinfo(skb)->gso_size = mtu - hlen; 1345 + } 1346 + } 1347 + not_lro: 1379 1348 if (unlikely(rcd->ts)) 1380 1349 __vlan_hwaccel_put_tag(skb, htons(ETH_P_8021Q), rcd->tci); 1381 1350 ··· 3128 3041 goto err_alloc_pci; 3129 3042 3130 3043 ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_VRRS); 3131 - if (ver & 1) { 3044 + if (ver & 2) { 3045 + VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 2); 3046 + adapter->version = 2; 3047 + } else if (ver & 1) { 3132 3048 VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_VRRS, 1); 3049 + adapter->version = 1; 3133 3050 } else { 3134 3051 dev_err(&pdev->dev, 3135 3052 "Incompatible h/w version (0x%x) for adapter\n", ver); 3136 3053 err = -EBUSY; 3137 3054 goto err_ver; 3138 3055 } 3056 + dev_dbg(&pdev->dev, "Using device version %d\n", adapter->version); 3139 3057 3140 3058 ver = VMXNET3_READ_BAR1_REG(adapter, VMXNET3_REG_UVRS); 3141 3059 if (ver & 1) {
+4
drivers/net/vmxnet3/vmxnet3_int.h
··· 328 328 329 329 u8 __iomem *hw_addr0; /* for BAR 0 */ 330 330 u8 __iomem *hw_addr1; /* for BAR 1 */ 331 + u8 version; 332 + 333 + bool rxcsum; 334 + bool lro; 331 335 332 336 #ifdef VMXNET3_RSS 333 337 struct UPT1_RSSConf *rss_conf;