diff options
-rw-r--r-- | drivers/net/netxen/netxen_nic.h | 21 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_ctx.c | 2 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_init.c | 124 |
3 files changed, 125 insertions, 22 deletions
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index bb4aa4f58676..ae81f7022d23 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h | |||
@@ -365,6 +365,7 @@ struct rcv_desc { | |||
365 | #define NETXEN_NIC_RXPKT_DESC 0x04 | 365 | #define NETXEN_NIC_RXPKT_DESC 0x04 |
366 | #define NETXEN_OLD_RXPKT_DESC 0x3f | 366 | #define NETXEN_OLD_RXPKT_DESC 0x3f |
367 | #define NETXEN_NIC_RESPONSE_DESC 0x05 | 367 | #define NETXEN_NIC_RESPONSE_DESC 0x05 |
368 | #define NETXEN_NIC_LRO_DESC 0x12 | ||
368 | 369 | ||
369 | /* for status field in status_desc */ | 370 | /* for status field in status_desc */ |
370 | #define STATUS_NEED_CKSUM (1) | 371 | #define STATUS_NEED_CKSUM (1) |
@@ -398,6 +399,24 @@ struct rcv_desc { | |||
398 | #define netxen_get_sts_opcode(sts_data) \ | 399 | #define netxen_get_sts_opcode(sts_data) \ |
399 | (((sts_data) >> 58) & 0x03F) | 400 | (((sts_data) >> 58) & 0x03F) |
400 | 401 | ||
402 | #define netxen_get_lro_sts_refhandle(sts_data) \ | ||
403 | ((sts_data) & 0x0FFFF) | ||
404 | #define netxen_get_lro_sts_length(sts_data) \ | ||
405 | (((sts_data) >> 16) & 0x0FFFF) | ||
406 | #define netxen_get_lro_sts_l2_hdr_offset(sts_data) \ | ||
407 | (((sts_data) >> 32) & 0x0FF) | ||
408 | #define netxen_get_lro_sts_l4_hdr_offset(sts_data) \ | ||
409 | (((sts_data) >> 40) & 0x0FF) | ||
410 | #define netxen_get_lro_sts_timestamp(sts_data) \ | ||
411 | (((sts_data) >> 48) & 0x1) | ||
412 | #define netxen_get_lro_sts_type(sts_data) \ | ||
413 | (((sts_data) >> 49) & 0x7) | ||
414 | #define netxen_get_lro_sts_push_flag(sts_data) \ | ||
415 | (((sts_data) >> 52) & 0x1) | ||
416 | #define netxen_get_lro_sts_seq_number(sts_data) \ | ||
417 | ((sts_data) & 0x0FFFFFFFF) | ||
418 | |||
419 | |||
401 | struct status_desc { | 420 | struct status_desc { |
402 | __le64 status_desc_data[2]; | 421 | __le64 status_desc_data[2]; |
403 | } __attribute__ ((aligned(16))); | 422 | } __attribute__ ((aligned(16))); |
@@ -712,6 +731,7 @@ struct netxen_recv_context { | |||
712 | #define NX_CAP0_LSO NX_CAP_BIT(0, 6) | 731 | #define NX_CAP0_LSO NX_CAP_BIT(0, 6) |
713 | #define NX_CAP0_JUMBO_CONTIGUOUS NX_CAP_BIT(0, 7) | 732 | #define NX_CAP0_JUMBO_CONTIGUOUS NX_CAP_BIT(0, 7) |
714 | #define NX_CAP0_LRO_CONTIGUOUS NX_CAP_BIT(0, 8) | 733 | #define NX_CAP0_LRO_CONTIGUOUS NX_CAP_BIT(0, 8) |
734 | #define NX_CAP0_HW_LRO NX_CAP_BIT(0, 10) | ||
715 | 735 | ||
716 | /* | 736 | /* |
717 | * Context state | 737 | * Context state |
@@ -969,6 +989,7 @@ typedef struct { | |||
969 | #define NX_FW_CAPABILITY_PEXQ (1 << 7) | 989 | #define NX_FW_CAPABILITY_PEXQ (1 << 7) |
970 | #define NX_FW_CAPABILITY_BDG (1 << 8) | 990 | #define NX_FW_CAPABILITY_BDG (1 << 8) |
971 | #define NX_FW_CAPABILITY_FVLANTX (1 << 9) | 991 | #define NX_FW_CAPABILITY_FVLANTX (1 << 9) |
992 | #define NX_FW_CAPABILITY_HW_LRO (1 << 10) | ||
972 | 993 | ||
973 | /* module types */ | 994 | /* module types */ |
974 | #define LINKEVENT_MODULE_NOT_PRESENT 1 | 995 | #define LINKEVENT_MODULE_NOT_PRESENT 1 |
diff --git a/drivers/net/netxen/netxen_nic_ctx.c b/drivers/net/netxen/netxen_nic_ctx.c index 9e0469643d34..412d65829d20 100644 --- a/drivers/net/netxen/netxen_nic_ctx.c +++ b/drivers/net/netxen/netxen_nic_ctx.c | |||
@@ -203,6 +203,8 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter) | |||
203 | 203 | ||
204 | cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN); | 204 | cap = (NX_CAP0_LEGACY_CONTEXT | NX_CAP0_LEGACY_MN); |
205 | cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS); | 205 | cap |= (NX_CAP0_JUMBO_CONTIGUOUS | NX_CAP0_LRO_CONTIGUOUS); |
206 | if (adapter->capabilities & NX_FW_CAPABILITY_HW_LRO) | ||
207 | cap |= NX_CAP0_HW_LRO; | ||
206 | 208 | ||
207 | prq->capabilities[0] = cpu_to_le32(cap); | 209 | prq->capabilities[0] = cpu_to_le32(cap); |
208 | prq->host_int_crb_mode = | 210 | prq->host_int_crb_mode = |
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 81253abbfa34..582828756ef4 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c | |||
@@ -1242,20 +1242,31 @@ no_skb: | |||
1242 | 1242 | ||
1243 | static struct netxen_rx_buffer * | 1243 | static struct netxen_rx_buffer * |
1244 | netxen_process_rcv(struct netxen_adapter *adapter, | 1244 | netxen_process_rcv(struct netxen_adapter *adapter, |
1245 | int ring, int index, int length, int cksum, int pkt_offset, | 1245 | struct nx_host_sds_ring *sds_ring, |
1246 | struct nx_host_sds_ring *sds_ring) | 1246 | int ring, u64 sts_data0) |
1247 | { | 1247 | { |
1248 | struct net_device *netdev = adapter->netdev; | 1248 | struct net_device *netdev = adapter->netdev; |
1249 | struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; | 1249 | struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; |
1250 | struct netxen_rx_buffer *buffer; | 1250 | struct netxen_rx_buffer *buffer; |
1251 | struct sk_buff *skb; | 1251 | struct sk_buff *skb; |
1252 | struct nx_host_rds_ring *rds_ring = &recv_ctx->rds_rings[ring]; | 1252 | struct nx_host_rds_ring *rds_ring; |
1253 | int index, length, cksum, pkt_offset; | ||
1253 | 1254 | ||
1254 | if (unlikely(index > rds_ring->num_desc)) | 1255 | if (unlikely(ring >= adapter->max_rds_rings)) |
1256 | return NULL; | ||
1257 | |||
1258 | rds_ring = &recv_ctx->rds_rings[ring]; | ||
1259 | |||
1260 | index = netxen_get_sts_refhandle(sts_data0); | ||
1261 | if (unlikely(index >= rds_ring->num_desc)) | ||
1255 | return NULL; | 1262 | return NULL; |
1256 | 1263 | ||
1257 | buffer = &rds_ring->rx_buf_arr[index]; | 1264 | buffer = &rds_ring->rx_buf_arr[index]; |
1258 | 1265 | ||
1266 | length = netxen_get_sts_totallength(sts_data0); | ||
1267 | cksum = netxen_get_sts_status(sts_data0); | ||
1268 | pkt_offset = netxen_get_sts_pkt_offset(sts_data0); | ||
1269 | |||
1259 | skb = netxen_process_rxbuf(adapter, rds_ring, index, cksum); | 1270 | skb = netxen_process_rxbuf(adapter, rds_ring, index, cksum); |
1260 | if (!skb) | 1271 | if (!skb) |
1261 | return buffer; | 1272 | return buffer; |
@@ -1279,6 +1290,78 @@ netxen_process_rcv(struct netxen_adapter *adapter, | |||
1279 | return buffer; | 1290 | return buffer; |
1280 | } | 1291 | } |
1281 | 1292 | ||
1293 | #define TCP_HDR_SIZE 20 | ||
1294 | #define TCP_TS_OPTION_SIZE 12 | ||
1295 | #define TCP_TS_HDR_SIZE (TCP_HDR_SIZE + TCP_TS_OPTION_SIZE) | ||
1296 | |||
1297 | static struct netxen_rx_buffer * | ||
1298 | netxen_process_lro(struct netxen_adapter *adapter, | ||
1299 | struct nx_host_sds_ring *sds_ring, | ||
1300 | int ring, u64 sts_data0, u64 sts_data1) | ||
1301 | { | ||
1302 | struct net_device *netdev = adapter->netdev; | ||
1303 | struct netxen_recv_context *recv_ctx = &adapter->recv_ctx; | ||
1304 | struct netxen_rx_buffer *buffer; | ||
1305 | struct sk_buff *skb; | ||
1306 | struct nx_host_rds_ring *rds_ring; | ||
1307 | struct iphdr *iph; | ||
1308 | struct tcphdr *th; | ||
1309 | bool push, timestamp; | ||
1310 | int l2_hdr_offset, l4_hdr_offset; | ||
1311 | int index; | ||
1312 | u16 lro_length, length, data_offset; | ||
1313 | u32 seq_number; | ||
1314 | |||
1315 | if (unlikely(ring > adapter->max_rds_rings)) | ||
1316 | return NULL; | ||
1317 | |||
1318 | rds_ring = &recv_ctx->rds_rings[ring]; | ||
1319 | |||
1320 | index = netxen_get_lro_sts_refhandle(sts_data0); | ||
1321 | if (unlikely(index > rds_ring->num_desc)) | ||
1322 | return NULL; | ||
1323 | |||
1324 | buffer = &rds_ring->rx_buf_arr[index]; | ||
1325 | |||
1326 | timestamp = netxen_get_lro_sts_timestamp(sts_data0); | ||
1327 | lro_length = netxen_get_lro_sts_length(sts_data0); | ||
1328 | l2_hdr_offset = netxen_get_lro_sts_l2_hdr_offset(sts_data0); | ||
1329 | l4_hdr_offset = netxen_get_lro_sts_l4_hdr_offset(sts_data0); | ||
1330 | push = netxen_get_lro_sts_push_flag(sts_data0); | ||
1331 | seq_number = netxen_get_lro_sts_seq_number(sts_data1); | ||
1332 | |||
1333 | skb = netxen_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK); | ||
1334 | if (!skb) | ||
1335 | return buffer; | ||
1336 | |||
1337 | if (timestamp) | ||
1338 | data_offset = l4_hdr_offset + TCP_TS_HDR_SIZE; | ||
1339 | else | ||
1340 | data_offset = l4_hdr_offset + TCP_HDR_SIZE; | ||
1341 | |||
1342 | skb_put(skb, lro_length + data_offset); | ||
1343 | |||
1344 | skb->truesize = (skb->len + sizeof(struct sk_buff) + | ||
1345 | ((unsigned long)skb->data - (unsigned long)skb->head)); | ||
1346 | |||
1347 | skb_pull(skb, l2_hdr_offset); | ||
1348 | skb->protocol = eth_type_trans(skb, netdev); | ||
1349 | |||
1350 | iph = (struct iphdr *)skb->data; | ||
1351 | th = (struct tcphdr *)(skb->data + (iph->ihl << 2)); | ||
1352 | |||
1353 | length = (iph->ihl << 2) + (th->doff << 2) + lro_length; | ||
1354 | iph->tot_len = htons(length); | ||
1355 | iph->check = 0; | ||
1356 | iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl); | ||
1357 | th->psh = push; | ||
1358 | th->seq = htonl(seq_number); | ||
1359 | |||
1360 | netif_receive_skb(skb); | ||
1361 | |||
1362 | return buffer; | ||
1363 | } | ||
1364 | |||
1282 | #define netxen_merge_rx_buffers(list, head) \ | 1365 | #define netxen_merge_rx_buffers(list, head) \ |
1283 | do { list_splice_tail_init(list, head); } while (0); | 1366 | do { list_splice_tail_init(list, head); } while (0); |
1284 | 1367 | ||
@@ -1295,28 +1378,33 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) | |||
1295 | u32 consumer = sds_ring->consumer; | 1378 | u32 consumer = sds_ring->consumer; |
1296 | 1379 | ||
1297 | int count = 0; | 1380 | int count = 0; |
1298 | u64 sts_data; | 1381 | u64 sts_data0, sts_data1; |
1299 | int opcode, ring, index, length, cksum, pkt_offset, desc_cnt; | 1382 | int opcode, ring = 0, desc_cnt; |
1300 | 1383 | ||
1301 | while (count < max) { | 1384 | while (count < max) { |
1302 | desc = &sds_ring->desc_head[consumer]; | 1385 | desc = &sds_ring->desc_head[consumer]; |
1303 | sts_data = le64_to_cpu(desc->status_desc_data[0]); | 1386 | sts_data0 = le64_to_cpu(desc->status_desc_data[0]); |
1304 | 1387 | ||
1305 | if (!(sts_data & STATUS_OWNER_HOST)) | 1388 | if (!(sts_data0 & STATUS_OWNER_HOST)) |
1306 | break; | 1389 | break; |
1307 | 1390 | ||
1308 | desc_cnt = netxen_get_sts_desc_cnt(sts_data); | 1391 | desc_cnt = netxen_get_sts_desc_cnt(sts_data0); |
1309 | ring = netxen_get_sts_type(sts_data); | ||
1310 | 1392 | ||
1311 | if (ring > RCV_RING_JUMBO) | 1393 | opcode = netxen_get_sts_opcode(sts_data0); |
1312 | goto skip; | ||
1313 | |||
1314 | opcode = netxen_get_sts_opcode(sts_data); | ||
1315 | 1394 | ||
1316 | switch (opcode) { | 1395 | switch (opcode) { |
1317 | case NETXEN_NIC_RXPKT_DESC: | 1396 | case NETXEN_NIC_RXPKT_DESC: |
1318 | case NETXEN_OLD_RXPKT_DESC: | 1397 | case NETXEN_OLD_RXPKT_DESC: |
1319 | case NETXEN_NIC_SYN_OFFLOAD: | 1398 | case NETXEN_NIC_SYN_OFFLOAD: |
1399 | ring = netxen_get_sts_type(sts_data0); | ||
1400 | rxbuf = netxen_process_rcv(adapter, sds_ring, | ||
1401 | ring, sts_data0); | ||
1402 | break; | ||
1403 | case NETXEN_NIC_LRO_DESC: | ||
1404 | ring = netxen_get_lro_sts_type(sts_data0); | ||
1405 | sts_data1 = le64_to_cpu(desc->status_desc_data[1]); | ||
1406 | rxbuf = netxen_process_lro(adapter, sds_ring, | ||
1407 | ring, sts_data0, sts_data1); | ||
1320 | break; | 1408 | break; |
1321 | case NETXEN_NIC_RESPONSE_DESC: | 1409 | case NETXEN_NIC_RESPONSE_DESC: |
1322 | netxen_handle_fw_message(desc_cnt, consumer, sds_ring); | 1410 | netxen_handle_fw_message(desc_cnt, consumer, sds_ring); |
@@ -1326,14 +1414,6 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) | |||
1326 | 1414 | ||
1327 | WARN_ON(desc_cnt > 1); | 1415 | WARN_ON(desc_cnt > 1); |
1328 | 1416 | ||
1329 | index = netxen_get_sts_refhandle(sts_data); | ||
1330 | length = netxen_get_sts_totallength(sts_data); | ||
1331 | cksum = netxen_get_sts_status(sts_data); | ||
1332 | pkt_offset = netxen_get_sts_pkt_offset(sts_data); | ||
1333 | |||
1334 | rxbuf = netxen_process_rcv(adapter, ring, index, | ||
1335 | length, cksum, pkt_offset, sds_ring); | ||
1336 | |||
1337 | if (rxbuf) | 1417 | if (rxbuf) |
1338 | list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); | 1418 | list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); |
1339 | 1419 | ||