@@ -1163,6 +1163,52 @@ vmxnet3_rx_error(struct vmxnet3_rx_queue *rq, struct Vmxnet3_RxCompDesc *rcd,
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 )
@@ -1174,6 +1220,7 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
1174
1220
bool skip_page_frags = false;
1175
1221
struct Vmxnet3_RxCompDesc * rcd ;
1176
1222
struct vmxnet3_rx_ctx * ctx = & rq -> rx_ctx ;
1223
+ u16 segCnt = 0 , mss = 0 ;
1177
1224
#ifdef __BIG_ENDIAN_BITFIELD
1178
1225
struct Vmxnet3_RxDesc rxCmdDesc ;
1179
1226
struct Vmxnet3_RxCompDesc rxComp ;
@@ -1262,7 +1309,19 @@ vmxnet3_rq_rx_complete(struct vmxnet3_rx_queue *rq,
1262
1309
PCI_DMA_FROMDEVICE );
1263
1310
rxd -> addr = cpu_to_le64 (rbi -> dma_addr );
1264
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
1325
} else {
1267
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
1371
skb = ctx -> skb ;
1313
1372
if (rcd -> eop ) {
1373
+ u32 mtu = adapter -> netdev -> mtu ;
1314
1374
skb -> len += skb -> data_len ;
1315
1375
1316
1376
vmxnet3_rx_csum (adapter , skb ,
1317
1377
(union Vmxnet3_GenericDesc * )rcd );
1318
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
+ }
1406
+ not_lro :
1320
1407
if (unlikely (rcd -> ts ))
1321
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
3128
goto err_alloc_pci ;
3042
3129
3043
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
3135
VMXNET3_WRITE_BAR1_REG (adapter , VMXNET3_REG_VRRS , 1 );
3136
+ adapter -> version = 1 ;
3046
3137
} else {
3047
3138
dev_err (& pdev -> dev ,
3048
3139
"Incompatible h/w version (0x%x) for adapter\n" , ver );
3049
3140
err = - EBUSY ;
3050
3141
goto err_ver ;
3051
3142
}
3143
+ dev_dbg (& pdev -> dev , "Using device version %d\n" , adapter -> version );
3052
3144
3053
3145
ver = VMXNET3_READ_BAR1_REG (adapter , VMXNET3_REG_UVRS );
3054
3146
if (ver & 1 ) {
0 commit comments