diff options
author | Dhananjay Phadke <dhananjay@netxen.com> | 2009-07-26 16:07:40 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-07-27 13:57:33 -0400 |
commit | 1bcfd790c49341fcbdce9526a007c4e2b9d54c7c (patch) | |
tree | 7f1d8909e32a0b2b301a28c61ad4dccd8ab866f6 /drivers/net/netxen | |
parent | 83ac51fa747c3a74372417629fcad4b110857b77 (diff) |
netxen: refactor tso code
o move all tso / checksum offload code into netxen_tso_check().
o optimize the tso header copy into simple loop.
o clean up unnecessary unions from cmd_desc_type0 struct.
Signed-off-by: Dhananjay Phadke <dhananjay@netxen.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/netxen')
-rw-r--r-- | drivers/net/netxen/netxen_nic.h | 49 | ||||
-rw-r--r-- | drivers/net/netxen/netxen_nic_main.c | 152 |
2 files changed, 83 insertions, 118 deletions
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h index 3368af0c129b..3a4cbd5dcbd9 100644 --- a/drivers/net/netxen/netxen_nic.h +++ b/drivers/net/netxen/netxen_nic.h | |||
@@ -316,56 +316,29 @@ struct netxen_ring_ctx { | |||
316 | cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)) | 316 | cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)) |
317 | 317 | ||
318 | #define netxen_set_tx_frags_len(_desc, _frags, _len) \ | 318 | #define netxen_set_tx_frags_len(_desc, _frags, _len) \ |
319 | (_desc)->num_of_buffers_total_length = \ | 319 | (_desc)->nfrags__length = \ |
320 | cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8)) | 320 | cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8)) |
321 | 321 | ||
322 | struct cmd_desc_type0 { | 322 | struct cmd_desc_type0 { |
323 | u8 tcp_hdr_offset; /* For LSO only */ | 323 | u8 tcp_hdr_offset; /* For LSO only */ |
324 | u8 ip_hdr_offset; /* For LSO only */ | 324 | u8 ip_hdr_offset; /* For LSO only */ |
325 | /* Bit pattern: 0-6 flags, 7-12 opcode, 13-15 unused */ | 325 | __le16 flags_opcode; /* 15:13 unused, 12:7 opcode, 6:0 flags */ |
326 | __le16 flags_opcode; | 326 | __le32 nfrags__length; /* 31:8 total len, 7:0 frag count */ |
327 | /* Bit pattern: 0-7 total number of segments, | 327 | |
328 | 8-31 Total size of the packet */ | 328 | __le64 addr_buffer2; |
329 | __le32 num_of_buffers_total_length; | ||
330 | union { | ||
331 | struct { | ||
332 | __le32 addr_low_part2; | ||
333 | __le32 addr_high_part2; | ||
334 | }; | ||
335 | __le64 addr_buffer2; | ||
336 | }; | ||
337 | 329 | ||
338 | __le16 reference_handle; /* changed to u16 to add mss */ | 330 | __le16 reference_handle; |
339 | __le16 mss; /* passed by NDIS_PACKET for LSO */ | 331 | __le16 mss; |
340 | /* Bit pattern 0-3 port, 0-3 ctx id */ | 332 | u8 port_ctxid; /* 7:4 ctxid 3:0 port */ |
341 | u8 port_ctxid; | ||
342 | u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */ | 333 | u8 total_hdr_length; /* LSO only : MAC+IP+TCP Hdr size */ |
343 | __le16 conn_id; /* IPSec offoad only */ | 334 | __le16 conn_id; /* IPSec offoad only */ |
344 | 335 | ||
345 | union { | 336 | __le64 addr_buffer3; |
346 | struct { | 337 | __le64 addr_buffer1; |
347 | __le32 addr_low_part3; | ||
348 | __le32 addr_high_part3; | ||
349 | }; | ||
350 | __le64 addr_buffer3; | ||
351 | }; | ||
352 | union { | ||
353 | struct { | ||
354 | __le32 addr_low_part1; | ||
355 | __le32 addr_high_part1; | ||
356 | }; | ||
357 | __le64 addr_buffer1; | ||
358 | }; | ||
359 | 338 | ||
360 | __le16 buffer_length[4]; | 339 | __le16 buffer_length[4]; |
361 | 340 | ||
362 | union { | 341 | __le64 addr_buffer4; |
363 | struct { | ||
364 | __le32 addr_low_part4; | ||
365 | __le32 addr_high_part4; | ||
366 | }; | ||
367 | __le64 addr_buffer4; | ||
368 | }; | ||
369 | 342 | ||
370 | __le64 unused; | 343 | __le64 unused; |
371 | 344 | ||
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c index fb976cbf9c71..381bd8f027c0 100644 --- a/drivers/net/netxen/netxen_nic_main.c +++ b/drivers/net/netxen/netxen_nic_main.c | |||
@@ -1310,13 +1310,18 @@ static int netxen_nic_close(struct net_device *netdev) | |||
1310 | return 0; | 1310 | return 0; |
1311 | } | 1311 | } |
1312 | 1312 | ||
1313 | static bool netxen_tso_check(struct net_device *netdev, | 1313 | static void |
1314 | struct cmd_desc_type0 *desc, struct sk_buff *skb) | 1314 | netxen_tso_check(struct net_device *netdev, |
1315 | struct nx_host_tx_ring *tx_ring, | ||
1316 | struct cmd_desc_type0 *first_desc, | ||
1317 | struct sk_buff *skb) | ||
1315 | { | 1318 | { |
1316 | bool tso = false; | ||
1317 | u8 opcode = TX_ETHER_PKT; | 1319 | u8 opcode = TX_ETHER_PKT; |
1318 | __be16 protocol = skb->protocol; | 1320 | __be16 protocol = skb->protocol; |
1319 | u16 flags = 0; | 1321 | u16 flags = 0; |
1322 | u32 producer; | ||
1323 | int copied, offset, copy_len, hdr_len = 0, tso = 0; | ||
1324 | struct cmd_desc_type0 *hwdesc; | ||
1320 | 1325 | ||
1321 | if (protocol == cpu_to_be16(ETH_P_8021Q)) { | 1326 | if (protocol == cpu_to_be16(ETH_P_8021Q)) { |
1322 | struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data; | 1327 | struct vlan_ethhdr *vh = (struct vlan_ethhdr *)skb->data; |
@@ -1327,13 +1332,14 @@ static bool netxen_tso_check(struct net_device *netdev, | |||
1327 | if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && | 1332 | if ((netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) && |
1328 | skb_shinfo(skb)->gso_size > 0) { | 1333 | skb_shinfo(skb)->gso_size > 0) { |
1329 | 1334 | ||
1330 | desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); | 1335 | hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); |
1331 | desc->total_hdr_length = | 1336 | |
1332 | skb_transport_offset(skb) + tcp_hdrlen(skb); | 1337 | first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size); |
1338 | first_desc->total_hdr_length = hdr_len; | ||
1333 | 1339 | ||
1334 | opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? | 1340 | opcode = (protocol == cpu_to_be16(ETH_P_IPV6)) ? |
1335 | TX_TCP_LSO6 : TX_TCP_LSO; | 1341 | TX_TCP_LSO6 : TX_TCP_LSO; |
1336 | tso = true; | 1342 | tso = 1; |
1337 | 1343 | ||
1338 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { | 1344 | } else if (skb->ip_summed == CHECKSUM_PARTIAL) { |
1339 | u8 l4proto; | 1345 | u8 l4proto; |
@@ -1354,10 +1360,39 @@ static bool netxen_tso_check(struct net_device *netdev, | |||
1354 | opcode = TX_UDPV6_PKT; | 1360 | opcode = TX_UDPV6_PKT; |
1355 | } | 1361 | } |
1356 | } | 1362 | } |
1357 | desc->tcp_hdr_offset = skb_transport_offset(skb); | 1363 | first_desc->tcp_hdr_offset = skb_transport_offset(skb); |
1358 | desc->ip_hdr_offset = skb_network_offset(skb); | 1364 | first_desc->ip_hdr_offset = skb_network_offset(skb); |
1359 | netxen_set_tx_flags_opcode(desc, flags, opcode); | 1365 | netxen_set_tx_flags_opcode(first_desc, flags, opcode); |
1360 | return tso; | 1366 | |
1367 | if (!tso) | ||
1368 | return; | ||
1369 | |||
1370 | /* For LSO, we need to copy the MAC/IP/TCP headers into | ||
1371 | * the descriptor ring | ||
1372 | */ | ||
1373 | producer = tx_ring->producer; | ||
1374 | copied = 0; | ||
1375 | offset = 2; | ||
1376 | |||
1377 | while (copied < hdr_len) { | ||
1378 | |||
1379 | copy_len = min((int)sizeof(struct cmd_desc_type0) - offset, | ||
1380 | (hdr_len - copied)); | ||
1381 | |||
1382 | hwdesc = &tx_ring->desc_head[producer]; | ||
1383 | tx_ring->cmd_buf_arr[producer].skb = NULL; | ||
1384 | |||
1385 | skb_copy_from_linear_data_offset(skb, copied, | ||
1386 | (char *)hwdesc + offset, copy_len); | ||
1387 | |||
1388 | copied += copy_len; | ||
1389 | offset = 0; | ||
1390 | |||
1391 | producer = get_next_index(producer, tx_ring->num_desc); | ||
1392 | } | ||
1393 | |||
1394 | tx_ring->producer = producer; | ||
1395 | barrier(); | ||
1361 | } | 1396 | } |
1362 | 1397 | ||
1363 | static void | 1398 | static void |
@@ -1381,9 +1416,8 @@ netxen_clean_tx_dma_mapping(struct pci_dev *pdev, | |||
1381 | static inline void | 1416 | static inline void |
1382 | netxen_clear_cmddesc(u64 *desc) | 1417 | netxen_clear_cmddesc(u64 *desc) |
1383 | { | 1418 | { |
1384 | int i; | 1419 | desc[0] = 0ULL; |
1385 | for (i = 0; i < 8; i++) | 1420 | desc[2] = 0ULL; |
1386 | desc[i] = 0ULL; | ||
1387 | } | 1421 | } |
1388 | 1422 | ||
1389 | static int | 1423 | static int |
@@ -1391,18 +1425,18 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
1391 | { | 1425 | { |
1392 | struct netxen_adapter *adapter = netdev_priv(netdev); | 1426 | struct netxen_adapter *adapter = netdev_priv(netdev); |
1393 | struct nx_host_tx_ring *tx_ring = adapter->tx_ring; | 1427 | struct nx_host_tx_ring *tx_ring = adapter->tx_ring; |
1394 | unsigned int first_seg_len = skb->len - skb->data_len; | 1428 | struct skb_frag_struct *frag; |
1395 | struct netxen_cmd_buffer *pbuf; | 1429 | struct netxen_cmd_buffer *pbuf; |
1396 | struct netxen_skb_frag *buffrag; | 1430 | struct netxen_skb_frag *buffrag; |
1397 | struct cmd_desc_type0 *hwdesc; | 1431 | struct cmd_desc_type0 *hwdesc, *first_desc; |
1398 | struct pci_dev *pdev = adapter->pdev; | 1432 | struct pci_dev *pdev; |
1399 | dma_addr_t temp_dma; | 1433 | dma_addr_t temp_dma; |
1400 | int i, k; | 1434 | int i, k; |
1435 | unsigned long offset; | ||
1401 | 1436 | ||
1402 | u32 producer; | 1437 | u32 producer; |
1403 | int frag_count, no_of_desc; | 1438 | int len, frag_count, no_of_desc; |
1404 | u32 num_txd = tx_ring->num_desc; | 1439 | u32 num_txd = tx_ring->num_desc; |
1405 | bool is_tso = false; | ||
1406 | 1440 | ||
1407 | frag_count = skb_shinfo(skb)->nr_frags + 1; | 1441 | frag_count = skb_shinfo(skb)->nr_frags + 1; |
1408 | 1442 | ||
@@ -1416,32 +1450,30 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
1416 | 1450 | ||
1417 | producer = tx_ring->producer; | 1451 | producer = tx_ring->producer; |
1418 | 1452 | ||
1419 | hwdesc = &tx_ring->desc_head[producer]; | 1453 | pdev = adapter->pdev; |
1420 | netxen_clear_cmddesc((u64 *)hwdesc); | 1454 | len = skb->len - skb->data_len; |
1421 | pbuf = &tx_ring->cmd_buf_arr[producer]; | ||
1422 | 1455 | ||
1423 | is_tso = netxen_tso_check(netdev, hwdesc, skb); | 1456 | temp_dma = pci_map_single(pdev, skb->data, len, PCI_DMA_TODEVICE); |
1457 | if (pci_dma_mapping_error(pdev, temp_dma)) | ||
1458 | goto drop_packet; | ||
1424 | 1459 | ||
1460 | pbuf = &tx_ring->cmd_buf_arr[producer]; | ||
1425 | pbuf->skb = skb; | 1461 | pbuf->skb = skb; |
1426 | pbuf->frag_count = frag_count; | 1462 | pbuf->frag_count = frag_count; |
1427 | buffrag = &pbuf->frag_array[0]; | ||
1428 | temp_dma = pci_map_single(pdev, skb->data, first_seg_len, | ||
1429 | PCI_DMA_TODEVICE); | ||
1430 | if (pci_dma_mapping_error(pdev, temp_dma)) | ||
1431 | goto drop_packet; | ||
1432 | 1463 | ||
1464 | buffrag = &pbuf->frag_array[0]; | ||
1433 | buffrag->dma = temp_dma; | 1465 | buffrag->dma = temp_dma; |
1434 | buffrag->length = first_seg_len; | 1466 | buffrag->length = len; |
1467 | |||
1468 | first_desc = hwdesc = &tx_ring->desc_head[producer]; | ||
1469 | netxen_clear_cmddesc((u64 *)hwdesc); | ||
1435 | netxen_set_tx_frags_len(hwdesc, frag_count, skb->len); | 1470 | netxen_set_tx_frags_len(hwdesc, frag_count, skb->len); |
1436 | netxen_set_tx_port(hwdesc, adapter->portnum); | 1471 | netxen_set_tx_port(hwdesc, adapter->portnum); |
1437 | 1472 | ||
1438 | hwdesc->buffer_length[0] = cpu_to_le16(first_seg_len); | 1473 | hwdesc->buffer_length[0] = cpu_to_le16(len); |
1439 | hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma); | 1474 | hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); |
1440 | 1475 | ||
1441 | for (i = 1, k = 1; i < frag_count; i++, k++) { | 1476 | for (i = 1, k = 1; i < frag_count; i++, k++) { |
1442 | struct skb_frag_struct *frag; | ||
1443 | int len, temp_len; | ||
1444 | unsigned long offset; | ||
1445 | 1477 | ||
1446 | /* move to next desc. if there is a need */ | 1478 | /* move to next desc. if there is a need */ |
1447 | if ((i & 0x3) == 0) { | 1479 | if ((i & 0x3) == 0) { |
@@ -1452,11 +1484,11 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
1452 | pbuf = &tx_ring->cmd_buf_arr[producer]; | 1484 | pbuf = &tx_ring->cmd_buf_arr[producer]; |
1453 | pbuf->skb = NULL; | 1485 | pbuf->skb = NULL; |
1454 | } | 1486 | } |
1487 | buffrag = &pbuf->frag_array[i]; | ||
1455 | frag = &skb_shinfo(skb)->frags[i - 1]; | 1488 | frag = &skb_shinfo(skb)->frags[i - 1]; |
1456 | len = frag->size; | 1489 | len = frag->size; |
1457 | offset = frag->page_offset; | 1490 | offset = frag->page_offset; |
1458 | 1491 | ||
1459 | temp_len = len; | ||
1460 | temp_dma = pci_map_page(pdev, frag->page, offset, | 1492 | temp_dma = pci_map_page(pdev, frag->page, offset, |
1461 | len, PCI_DMA_TODEVICE); | 1493 | len, PCI_DMA_TODEVICE); |
1462 | if (pci_dma_mapping_error(pdev, temp_dma)) { | 1494 | if (pci_dma_mapping_error(pdev, temp_dma)) { |
@@ -1464,11 +1496,10 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
1464 | goto drop_packet; | 1496 | goto drop_packet; |
1465 | } | 1497 | } |
1466 | 1498 | ||
1467 | buffrag++; | ||
1468 | buffrag->dma = temp_dma; | 1499 | buffrag->dma = temp_dma; |
1469 | buffrag->length = temp_len; | 1500 | buffrag->length = len; |
1470 | 1501 | ||
1471 | hwdesc->buffer_length[k] = cpu_to_le16(temp_len); | 1502 | hwdesc->buffer_length[k] = cpu_to_le16(len); |
1472 | switch (k) { | 1503 | switch (k) { |
1473 | case 0: | 1504 | case 0: |
1474 | hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); | 1505 | hwdesc->addr_buffer1 = cpu_to_le64(temp_dma); |
@@ -1483,53 +1514,14 @@ netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev) | |||
1483 | hwdesc->addr_buffer4 = cpu_to_le64(temp_dma); | 1514 | hwdesc->addr_buffer4 = cpu_to_le64(temp_dma); |
1484 | break; | 1515 | break; |
1485 | } | 1516 | } |
1486 | frag++; | ||
1487 | } | 1517 | } |
1488 | producer = get_next_index(producer, num_txd); | 1518 | tx_ring->producer = get_next_index(producer, num_txd); |
1489 | 1519 | ||
1490 | /* For LSO, we need to copy the MAC/IP/TCP headers into | 1520 | netxen_tso_check(netdev, tx_ring, first_desc, skb); |
1491 | * the descriptor ring | ||
1492 | */ | ||
1493 | if (is_tso) { | ||
1494 | int hdr_len, first_hdr_len, more_hdr; | ||
1495 | hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb); | ||
1496 | if (hdr_len > (sizeof(struct cmd_desc_type0) - 2)) { | ||
1497 | first_hdr_len = sizeof(struct cmd_desc_type0) - 2; | ||
1498 | more_hdr = 1; | ||
1499 | } else { | ||
1500 | first_hdr_len = hdr_len; | ||
1501 | more_hdr = 0; | ||
1502 | } | ||
1503 | /* copy the MAC/IP/TCP headers to the cmd descriptor list */ | ||
1504 | hwdesc = &tx_ring->desc_head[producer]; | ||
1505 | pbuf = &tx_ring->cmd_buf_arr[producer]; | ||
1506 | pbuf->skb = NULL; | ||
1507 | |||
1508 | /* copy the first 64 bytes */ | ||
1509 | memcpy(((void *)hwdesc) + 2, | ||
1510 | (void *)(skb->data), first_hdr_len); | ||
1511 | producer = get_next_index(producer, num_txd); | ||
1512 | |||
1513 | if (more_hdr) { | ||
1514 | hwdesc = &tx_ring->desc_head[producer]; | ||
1515 | pbuf = &tx_ring->cmd_buf_arr[producer]; | ||
1516 | pbuf->skb = NULL; | ||
1517 | /* copy the next 64 bytes - should be enough except | ||
1518 | * for pathological case | ||
1519 | */ | ||
1520 | skb_copy_from_linear_data_offset(skb, first_hdr_len, | ||
1521 | hwdesc, | ||
1522 | (hdr_len - | ||
1523 | first_hdr_len)); | ||
1524 | producer = get_next_index(producer, num_txd); | ||
1525 | } | ||
1526 | } | ||
1527 | |||
1528 | tx_ring->producer = producer; | ||
1529 | adapter->stats.txbytes += skb->len; | ||
1530 | 1521 | ||
1531 | netxen_nic_update_cmd_producer(adapter, tx_ring); | 1522 | netxen_nic_update_cmd_producer(adapter, tx_ring); |
1532 | 1523 | ||
1524 | adapter->stats.txbytes += skb->len; | ||
1533 | adapter->stats.xmitcalled++; | 1525 | adapter->stats.xmitcalled++; |
1534 | 1526 | ||
1535 | return NETDEV_TX_OK; | 1527 | return NETDEV_TX_OK; |