diff options
author | Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com> | 2008-06-18 18:32:19 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-06-24 23:06:19 -0400 |
commit | 177db6ffd0599430a2ab63045e88fc4031f42420 (patch) | |
tree | 1c1e0b71a9589628e8b2abd82c213e1e7d1cc34b /drivers/net/ixgbe | |
parent | 8f85cd7fefa3d01c4e05aac1cb198733336cf44b (diff) |
ixgbe: add LRO support
Support for in-kernel LRO with the ability to enable/disable via ethtool
based on comments from Ben Hutchings.
Signed-off-by: Mallikarjuna R Chilakala <mallikarjuna.chilakala@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: PJ Waskiewicz <peter.p.waskiewicz.jr@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Diffstat (limited to 'drivers/net/ixgbe')
-rw-r--r-- | drivers/net/ixgbe/ixgbe.h | 9 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_ethtool.c | 11 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 111 |
3 files changed, 110 insertions, 21 deletions
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index d98113472a89..956914a5028d 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/types.h> | 32 | #include <linux/types.h> |
33 | #include <linux/pci.h> | 33 | #include <linux/pci.h> |
34 | #include <linux/netdevice.h> | 34 | #include <linux/netdevice.h> |
35 | #include <linux/inet_lro.h> | ||
35 | 36 | ||
36 | #include "ixgbe_type.h" | 37 | #include "ixgbe_type.h" |
37 | #include "ixgbe_common.h" | 38 | #include "ixgbe_common.h" |
@@ -100,6 +101,9 @@ | |||
100 | #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 | 101 | #define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000 |
101 | #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 | 102 | #define IXGBE_TX_FLAGS_VLAN_SHIFT 16 |
102 | 103 | ||
104 | #define IXGBE_MAX_LRO_DESCRIPTORS 8 | ||
105 | #define IXGBE_MAX_LRO_AGGREGATE 32 | ||
106 | |||
103 | /* wrapper around a pointer to a socket buffer, | 107 | /* wrapper around a pointer to a socket buffer, |
104 | * so a DMA handle can be stored along with the buffer */ | 108 | * so a DMA handle can be stored along with the buffer */ |
105 | struct ixgbe_tx_buffer { | 109 | struct ixgbe_tx_buffer { |
@@ -150,6 +154,8 @@ struct ixgbe_ring { | |||
150 | /* cpu for tx queue */ | 154 | /* cpu for tx queue */ |
151 | int cpu; | 155 | int cpu; |
152 | #endif | 156 | #endif |
157 | struct net_lro_mgr lro_mgr; | ||
158 | bool lro_used; | ||
153 | struct ixgbe_queue_stats stats; | 159 | struct ixgbe_queue_stats stats; |
154 | u8 v_idx; /* maps directly to the index for this ring in the hardware | 160 | u8 v_idx; /* maps directly to the index for this ring in the hardware |
155 | * vector array, can also be used for finding the bit in EICR | 161 | * vector array, can also be used for finding the bit in EICR |
@@ -287,6 +293,9 @@ struct ixgbe_adapter { | |||
287 | 293 | ||
288 | unsigned long state; | 294 | unsigned long state; |
289 | u64 tx_busy; | 295 | u64 tx_busy; |
296 | u64 lro_aggregated; | ||
297 | u64 lro_flushed; | ||
298 | u64 lro_no_desc; | ||
290 | }; | 299 | }; |
291 | 300 | ||
292 | enum ixbge_state_t { | 301 | enum ixbge_state_t { |
diff --git a/drivers/net/ixgbe/ixgbe_ethtool.c b/drivers/net/ixgbe/ixgbe_ethtool.c index 4e463778bcfd..12990b1fe7e4 100644 --- a/drivers/net/ixgbe/ixgbe_ethtool.c +++ b/drivers/net/ixgbe/ixgbe_ethtool.c | |||
@@ -90,6 +90,8 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = { | |||
90 | {"rx_header_split", IXGBE_STAT(rx_hdr_split)}, | 90 | {"rx_header_split", IXGBE_STAT(rx_hdr_split)}, |
91 | {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, | 91 | {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, |
92 | {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, | 92 | {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, |
93 | {"lro_aggregated", IXGBE_STAT(lro_aggregated)}, | ||
94 | {"lro_flushed", IXGBE_STAT(lro_flushed)}, | ||
93 | }; | 95 | }; |
94 | 96 | ||
95 | #define IXGBE_QUEUE_STATS_LEN \ | 97 | #define IXGBE_QUEUE_STATS_LEN \ |
@@ -787,6 +789,7 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, | |||
787 | int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64); | 789 | int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64); |
788 | int j, k; | 790 | int j, k; |
789 | int i; | 791 | int i; |
792 | u64 aggregated = 0, flushed = 0, no_desc = 0; | ||
790 | 793 | ||
791 | ixgbe_update_stats(adapter); | 794 | ixgbe_update_stats(adapter); |
792 | for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { | 795 | for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { |
@@ -801,11 +804,17 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev, | |||
801 | i += k; | 804 | i += k; |
802 | } | 805 | } |
803 | for (j = 0; j < adapter->num_rx_queues; j++) { | 806 | for (j = 0; j < adapter->num_rx_queues; j++) { |
807 | aggregated += adapter->rx_ring[j].lro_mgr.stats.aggregated; | ||
808 | flushed += adapter->rx_ring[j].lro_mgr.stats.flushed; | ||
809 | no_desc += adapter->rx_ring[j].lro_mgr.stats.no_desc; | ||
804 | queue_stat = (u64 *)&adapter->rx_ring[j].stats; | 810 | queue_stat = (u64 *)&adapter->rx_ring[j].stats; |
805 | for (k = 0; k < stat_count; k++) | 811 | for (k = 0; k < stat_count; k++) |
806 | data[i + k] = queue_stat[k]; | 812 | data[i + k] = queue_stat[k]; |
807 | i += k; | 813 | i += k; |
808 | } | 814 | } |
815 | adapter->lro_aggregated = aggregated; | ||
816 | adapter->lro_flushed = flushed; | ||
817 | adapter->lro_no_desc = no_desc; | ||
809 | } | 818 | } |
810 | 819 | ||
811 | static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, | 820 | static void ixgbe_get_strings(struct net_device *netdev, u32 stringset, |
@@ -973,6 +982,8 @@ static struct ethtool_ops ixgbe_ethtool_ops = { | |||
973 | .get_ethtool_stats = ixgbe_get_ethtool_stats, | 982 | .get_ethtool_stats = ixgbe_get_ethtool_stats, |
974 | .get_coalesce = ixgbe_get_coalesce, | 983 | .get_coalesce = ixgbe_get_coalesce, |
975 | .set_coalesce = ixgbe_set_coalesce, | 984 | .set_coalesce = ixgbe_set_coalesce, |
985 | .get_flags = ethtool_op_get_flags, | ||
986 | .set_flags = ethtool_op_set_flags, | ||
976 | }; | 987 | }; |
977 | 988 | ||
978 | void ixgbe_set_ethtool_ops(struct net_device *netdev) | 989 | void ixgbe_set_ethtool_ops(struct net_device *netdev) |
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 0d37c9025be4..f429c9a4754f 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
@@ -389,24 +389,39 @@ static int __ixgbe_notify_dca(struct device *dev, void *data) | |||
389 | * ixgbe_receive_skb - Send a completed packet up the stack | 389 | * ixgbe_receive_skb - Send a completed packet up the stack |
390 | * @adapter: board private structure | 390 | * @adapter: board private structure |
391 | * @skb: packet to send up | 391 | * @skb: packet to send up |
392 | * @is_vlan: packet has a VLAN tag | 392 | * @status: hardware indication of status of receive |
393 | * @tag: VLAN tag from descriptor | 393 | * @rx_ring: rx descriptor ring (for a specific queue) to setup |
394 | * @rx_desc: rx descriptor | ||
394 | **/ | 395 | **/ |
395 | static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, | 396 | static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, |
396 | struct sk_buff *skb, bool is_vlan, | 397 | struct sk_buff *skb, u8 status, |
397 | u16 tag) | 398 | struct ixgbe_ring *ring, |
399 | union ixgbe_adv_rx_desc *rx_desc) | ||
398 | { | 400 | { |
399 | if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { | 401 | bool is_vlan = (status & IXGBE_RXD_STAT_VP); |
400 | if (adapter->vlgrp && is_vlan) | 402 | u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); |
401 | vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); | ||
402 | else | ||
403 | netif_receive_skb(skb); | ||
404 | } else { | ||
405 | 403 | ||
404 | if (adapter->netdev->features & NETIF_F_LRO && | ||
405 | skb->ip_summed == CHECKSUM_UNNECESSARY) { | ||
406 | if (adapter->vlgrp && is_vlan) | 406 | if (adapter->vlgrp && is_vlan) |
407 | vlan_hwaccel_rx(skb, adapter->vlgrp, tag); | 407 | lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb, |
408 | adapter->vlgrp, tag, | ||
409 | rx_desc); | ||
408 | else | 410 | else |
409 | netif_rx(skb); | 411 | lro_receive_skb(&ring->lro_mgr, skb, rx_desc); |
412 | ring->lro_used = true; | ||
413 | } else { | ||
414 | if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { | ||
415 | if (adapter->vlgrp && is_vlan) | ||
416 | vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag); | ||
417 | else | ||
418 | netif_receive_skb(skb); | ||
419 | } else { | ||
420 | if (adapter->vlgrp && is_vlan) | ||
421 | vlan_hwaccel_rx(skb, adapter->vlgrp, tag); | ||
422 | else | ||
423 | netif_rx(skb); | ||
424 | } | ||
410 | } | 425 | } |
411 | } | 426 | } |
412 | 427 | ||
@@ -546,8 +561,8 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, | |||
546 | struct sk_buff *skb; | 561 | struct sk_buff *skb; |
547 | unsigned int i; | 562 | unsigned int i; |
548 | u32 upper_len, len, staterr; | 563 | u32 upper_len, len, staterr; |
549 | u16 hdr_info, vlan_tag; | 564 | u16 hdr_info; |
550 | bool is_vlan, cleaned = false; | 565 | bool cleaned = false; |
551 | int cleaned_count = 0; | 566 | int cleaned_count = 0; |
552 | unsigned int total_rx_bytes = 0, total_rx_packets = 0; | 567 | unsigned int total_rx_bytes = 0, total_rx_packets = 0; |
553 | 568 | ||
@@ -556,8 +571,6 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, | |||
556 | rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); | 571 | rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i); |
557 | staterr = le32_to_cpu(rx_desc->wb.upper.status_error); | 572 | staterr = le32_to_cpu(rx_desc->wb.upper.status_error); |
558 | rx_buffer_info = &rx_ring->rx_buffer_info[i]; | 573 | rx_buffer_info = &rx_ring->rx_buffer_info[i]; |
559 | is_vlan = (staterr & IXGBE_RXD_STAT_VP); | ||
560 | vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); | ||
561 | 574 | ||
562 | while (staterr & IXGBE_RXD_STAT_DD) { | 575 | while (staterr & IXGBE_RXD_STAT_DD) { |
563 | if (*work_done >= work_to_do) | 576 | if (*work_done >= work_to_do) |
@@ -635,7 +648,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, | |||
635 | total_rx_packets++; | 648 | total_rx_packets++; |
636 | 649 | ||
637 | skb->protocol = eth_type_trans(skb, netdev); | 650 | skb->protocol = eth_type_trans(skb, netdev); |
638 | ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag); | 651 | ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc); |
639 | netdev->last_rx = jiffies; | 652 | netdev->last_rx = jiffies; |
640 | 653 | ||
641 | next_desc: | 654 | next_desc: |
@@ -652,8 +665,11 @@ next_desc: | |||
652 | rx_buffer_info = next_buffer; | 665 | rx_buffer_info = next_buffer; |
653 | 666 | ||
654 | staterr = le32_to_cpu(rx_desc->wb.upper.status_error); | 667 | staterr = le32_to_cpu(rx_desc->wb.upper.status_error); |
655 | is_vlan = (staterr & IXGBE_RXD_STAT_VP); | 668 | } |
656 | vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan); | 669 | |
670 | if (rx_ring->lro_used) { | ||
671 | lro_flush_all(&rx_ring->lro_mgr); | ||
672 | rx_ring->lro_used = false; | ||
657 | } | 673 | } |
658 | 674 | ||
659 | rx_ring->next_to_clean = i; | 675 | rx_ring->next_to_clean = i; |
@@ -1382,6 +1398,33 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter) | |||
1382 | 1398 | ||
1383 | #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 | 1399 | #define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2 |
1384 | /** | 1400 | /** |
1401 | * ixgbe_get_skb_hdr - helper function for LRO header processing | ||
1402 | * @skb: pointer to sk_buff to be added to LRO packet | ||
1403 | * @iphdr: pointer to tcp header structure | ||
1404 | * @tcph: pointer to tcp header structure | ||
1405 | * @hdr_flags: pointer to header flags | ||
1406 | * @priv: private data | ||
1407 | **/ | ||
1408 | static int ixgbe_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph, | ||
1409 | u64 *hdr_flags, void *priv) | ||
1410 | { | ||
1411 | union ixgbe_adv_rx_desc *rx_desc = priv; | ||
1412 | |||
1413 | /* Verify that this is a valid IPv4 TCP packet */ | ||
1414 | if (!(rx_desc->wb.lower.lo_dword.pkt_info & | ||
1415 | (IXGBE_RXDADV_PKTTYPE_IPV4 | IXGBE_RXDADV_PKTTYPE_TCP))) | ||
1416 | return -1; | ||
1417 | |||
1418 | /* Set network headers */ | ||
1419 | skb_reset_network_header(skb); | ||
1420 | skb_set_transport_header(skb, ip_hdrlen(skb)); | ||
1421 | *iphdr = ip_hdr(skb); | ||
1422 | *tcph = tcp_hdr(skb); | ||
1423 | *hdr_flags = LRO_IPV4 | LRO_TCP; | ||
1424 | return 0; | ||
1425 | } | ||
1426 | |||
1427 | /** | ||
1385 | * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset | 1428 | * ixgbe_configure_rx - Configure 8254x Receive Unit after Reset |
1386 | * @adapter: board private structure | 1429 | * @adapter: board private structure |
1387 | * | 1430 | * |
@@ -1470,6 +1513,17 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter) | |||
1470 | adapter->rx_ring[i].tail = IXGBE_RDT(i); | 1513 | adapter->rx_ring[i].tail = IXGBE_RDT(i); |
1471 | } | 1514 | } |
1472 | 1515 | ||
1516 | /* Intitial LRO Settings */ | ||
1517 | adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE; | ||
1518 | adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS; | ||
1519 | adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr; | ||
1520 | adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID; | ||
1521 | if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) | ||
1522 | adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI; | ||
1523 | adapter->rx_ring[i].lro_mgr.dev = adapter->netdev; | ||
1524 | adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; | ||
1525 | adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; | ||
1526 | |||
1473 | if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { | 1527 | if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) { |
1474 | /* Fill out redirection table */ | 1528 | /* Fill out redirection table */ |
1475 | for (i = 0, j = 0; i < 128; i++, j++) { | 1529 | for (i = 0, j = 0; i < 128; i++, j++) { |
@@ -2489,12 +2543,18 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, | |||
2489 | struct pci_dev *pdev = adapter->pdev; | 2543 | struct pci_dev *pdev = adapter->pdev; |
2490 | int size; | 2544 | int size; |
2491 | 2545 | ||
2546 | size = sizeof(struct net_lro_desc) * IXGBE_MAX_LRO_DESCRIPTORS; | ||
2547 | rxdr->lro_mgr.lro_arr = vmalloc(size); | ||
2548 | if (!rxdr->lro_mgr.lro_arr) | ||
2549 | return -ENOMEM; | ||
2550 | memset(rxdr->lro_mgr.lro_arr, 0, size); | ||
2551 | |||
2492 | size = sizeof(struct ixgbe_rx_buffer) * rxdr->count; | 2552 | size = sizeof(struct ixgbe_rx_buffer) * rxdr->count; |
2493 | rxdr->rx_buffer_info = vmalloc(size); | 2553 | rxdr->rx_buffer_info = vmalloc(size); |
2494 | if (!rxdr->rx_buffer_info) { | 2554 | if (!rxdr->rx_buffer_info) { |
2495 | DPRINTK(PROBE, ERR, | 2555 | DPRINTK(PROBE, ERR, |
2496 | "vmalloc allocation failed for the rx desc ring\n"); | 2556 | "vmalloc allocation failed for the rx desc ring\n"); |
2497 | return -ENOMEM; | 2557 | goto alloc_failed; |
2498 | } | 2558 | } |
2499 | memset(rxdr->rx_buffer_info, 0, size); | 2559 | memset(rxdr->rx_buffer_info, 0, size); |
2500 | 2560 | ||
@@ -2508,13 +2568,18 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter, | |||
2508 | DPRINTK(PROBE, ERR, | 2568 | DPRINTK(PROBE, ERR, |
2509 | "Memory allocation failed for the rx desc ring\n"); | 2569 | "Memory allocation failed for the rx desc ring\n"); |
2510 | vfree(rxdr->rx_buffer_info); | 2570 | vfree(rxdr->rx_buffer_info); |
2511 | return -ENOMEM; | 2571 | goto alloc_failed; |
2512 | } | 2572 | } |
2513 | 2573 | ||
2514 | rxdr->next_to_clean = 0; | 2574 | rxdr->next_to_clean = 0; |
2515 | rxdr->next_to_use = 0; | 2575 | rxdr->next_to_use = 0; |
2516 | 2576 | ||
2517 | return 0; | 2577 | return 0; |
2578 | |||
2579 | alloc_failed: | ||
2580 | vfree(rxdr->lro_mgr.lro_arr); | ||
2581 | rxdr->lro_mgr.lro_arr = NULL; | ||
2582 | return -ENOMEM; | ||
2518 | } | 2583 | } |
2519 | 2584 | ||
2520 | /** | 2585 | /** |
@@ -2565,6 +2630,9 @@ static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter, | |||
2565 | { | 2630 | { |
2566 | struct pci_dev *pdev = adapter->pdev; | 2631 | struct pci_dev *pdev = adapter->pdev; |
2567 | 2632 | ||
2633 | vfree(rx_ring->lro_mgr.lro_arr); | ||
2634 | rx_ring->lro_mgr.lro_arr = NULL; | ||
2635 | |||
2568 | ixgbe_clean_rx_ring(adapter, rx_ring); | 2636 | ixgbe_clean_rx_ring(adapter, rx_ring); |
2569 | 2637 | ||
2570 | vfree(rx_ring->rx_buffer_info); | 2638 | vfree(rx_ring->rx_buffer_info); |
@@ -3517,6 +3585,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, | |||
3517 | NETIF_F_HW_VLAN_RX | | 3585 | NETIF_F_HW_VLAN_RX | |
3518 | NETIF_F_HW_VLAN_FILTER; | 3586 | NETIF_F_HW_VLAN_FILTER; |
3519 | 3587 | ||
3588 | netdev->features |= NETIF_F_LRO; | ||
3520 | netdev->features |= NETIF_F_TSO; | 3589 | netdev->features |= NETIF_F_TSO; |
3521 | netdev->features |= NETIF_F_TSO6; | 3590 | netdev->features |= NETIF_F_TSO6; |
3522 | 3591 | ||