diff options
author | Alexander Duyck <alexander.h.duyck@intel.com> | 2008-07-08 18:12:13 -0400 |
---|---|---|
committer | Jeff Garzik <jgarzik@redhat.com> | 2008-07-11 01:20:32 -0400 |
commit | d3352520273426e4c16e91d189aa8aa7ee5e96c5 (patch) | |
tree | 963c396cdc698b853acfe100080efbe41719013e | |
parent | bf36c1a0040cc6ccd63cdd1cec25d2085f2df964 (diff) |
igb: add support for in kernel LRO
This patch adds support for the use of the inet_lro module to provide
software LRO support.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
-rw-r--r-- | drivers/net/Kconfig | 9 | ||||
-rw-r--r-- | drivers/net/igb/e1000_82575.h | 2 | ||||
-rw-r--r-- | drivers/net/igb/igb.h | 16 | ||||
-rw-r--r-- | drivers/net/igb/igb_ethtool.c | 17 | ||||
-rw-r--r-- | drivers/net/igb/igb_main.c | 112 |
5 files changed, 147 insertions, 9 deletions
diff --git a/drivers/net/Kconfig b/drivers/net/Kconfig index 21414177ee1e..44d1c835128a 100644 --- a/drivers/net/Kconfig +++ b/drivers/net/Kconfig | |||
@@ -2018,6 +2018,15 @@ config IGB | |||
2018 | To compile this driver as a module, choose M here. The module | 2018 | To compile this driver as a module, choose M here. The module |
2019 | will be called igb. | 2019 | will be called igb. |
2020 | 2020 | ||
2021 | config IGB_LRO | ||
2022 | bool "Use software LRO" | ||
2023 | depends on IGB && INET | ||
2024 | select INET_LRO | ||
2025 | ---help--- | ||
2026 | Say Y here if you want to use large receive offload. | ||
2027 | |||
2028 | If in doubt, say N. | ||
2029 | |||
2021 | source "drivers/net/ixp2000/Kconfig" | 2030 | source "drivers/net/ixp2000/Kconfig" |
2022 | 2031 | ||
2023 | config MYRI_SBUS | 2032 | config MYRI_SBUS |
diff --git a/drivers/net/igb/e1000_82575.h b/drivers/net/igb/e1000_82575.h index d273236c7764..2f848e578a24 100644 --- a/drivers/net/igb/e1000_82575.h +++ b/drivers/net/igb/e1000_82575.h | |||
@@ -99,6 +99,8 @@ union e1000_adv_rx_desc { | |||
99 | /* RSS Hash results */ | 99 | /* RSS Hash results */ |
100 | 100 | ||
101 | /* RSS Packet Types as indicated in the receive descriptor */ | 101 | /* RSS Packet Types as indicated in the receive descriptor */ |
102 | #define E1000_RXDADV_PKTTYPE_IPV4 0x00000010 /* IPV4 hdr present */ | ||
103 | #define E1000_RXDADV_PKTTYPE_TCP 0x00000100 /* TCP hdr present */ | ||
102 | 104 | ||
103 | /* Transmit Descriptor - Advanced */ | 105 | /* Transmit Descriptor - Advanced */ |
104 | union e1000_adv_tx_desc { | 106 | union e1000_adv_tx_desc { |
diff --git a/drivers/net/igb/igb.h b/drivers/net/igb/igb.h index f41b9996d2ed..c25ca17d3228 100644 --- a/drivers/net/igb/igb.h +++ b/drivers/net/igb/igb.h | |||
@@ -36,6 +36,12 @@ | |||
36 | 36 | ||
37 | struct igb_adapter; | 37 | struct igb_adapter; |
38 | 38 | ||
39 | #ifdef CONFIG_IGB_LRO | ||
40 | #include <linux/inet_lro.h> | ||
41 | #define MAX_LRO_AGGR 32 | ||
42 | #define MAX_LRO_DESCRIPTORS 8 | ||
43 | #endif | ||
44 | |||
39 | /* Interrupt defines */ | 45 | /* Interrupt defines */ |
40 | #define IGB_MAX_TX_CLEAN 72 | 46 | #define IGB_MAX_TX_CLEAN 72 |
41 | 47 | ||
@@ -167,6 +173,10 @@ struct igb_ring { | |||
167 | int no_itr_adjust; | 173 | int no_itr_adjust; |
168 | struct igb_queue_stats rx_stats; | 174 | struct igb_queue_stats rx_stats; |
169 | struct napi_struct napi; | 175 | struct napi_struct napi; |
176 | #ifdef CONFIG_IGB_LRO | ||
177 | struct net_lro_mgr lro_mgr; | ||
178 | bool lro_used; | ||
179 | #endif | ||
170 | }; | 180 | }; |
171 | }; | 181 | }; |
172 | 182 | ||
@@ -278,6 +288,12 @@ struct igb_adapter { | |||
278 | #ifdef CONFIG_NETDEVICES_MULTIQUEUE | 288 | #ifdef CONFIG_NETDEVICES_MULTIQUEUE |
279 | struct igb_ring *multi_tx_table[IGB_MAX_TX_QUEUES]; | 289 | struct igb_ring *multi_tx_table[IGB_MAX_TX_QUEUES]; |
280 | #endif /* CONFIG_NETDEVICES_MULTIQUEUE */ | 290 | #endif /* CONFIG_NETDEVICES_MULTIQUEUE */ |
291 | #ifdef CONFIG_IGB_LRO | ||
292 | unsigned int lro_max_aggr; | ||
293 | unsigned int lro_aggregated; | ||
294 | unsigned int lro_flushed; | ||
295 | unsigned int lro_no_desc; | ||
296 | #endif | ||
281 | }; | 297 | }; |
282 | 298 | ||
283 | #define IGB_FLAG_HAS_MSI (1 << 0) | 299 | #define IGB_FLAG_HAS_MSI (1 << 0) |
diff --git a/drivers/net/igb/igb_ethtool.c b/drivers/net/igb/igb_ethtool.c index ef209b5cd390..7db183093768 100644 --- a/drivers/net/igb/igb_ethtool.c +++ b/drivers/net/igb/igb_ethtool.c | |||
@@ -93,6 +93,11 @@ static const struct igb_stats igb_gstrings_stats[] = { | |||
93 | { "tx_smbus", IGB_STAT(stats.mgptc) }, | 93 | { "tx_smbus", IGB_STAT(stats.mgptc) }, |
94 | { "rx_smbus", IGB_STAT(stats.mgprc) }, | 94 | { "rx_smbus", IGB_STAT(stats.mgprc) }, |
95 | { "dropped_smbus", IGB_STAT(stats.mgpdc) }, | 95 | { "dropped_smbus", IGB_STAT(stats.mgpdc) }, |
96 | #ifdef CONFIG_IGB_LRO | ||
97 | { "lro_aggregated", IGB_STAT(lro_aggregated) }, | ||
98 | { "lro_flushed", IGB_STAT(lro_flushed) }, | ||
99 | { "lro_no_desc", IGB_STAT(lro_no_desc) }, | ||
100 | #endif | ||
96 | }; | 101 | }; |
97 | 102 | ||
98 | #define IGB_QUEUE_STATS_LEN \ | 103 | #define IGB_QUEUE_STATS_LEN \ |
@@ -1917,6 +1922,18 @@ static void igb_get_ethtool_stats(struct net_device *netdev, | |||
1917 | int stat_count = sizeof(struct igb_queue_stats) / sizeof(u64); | 1922 | int stat_count = sizeof(struct igb_queue_stats) / sizeof(u64); |
1918 | int j; | 1923 | int j; |
1919 | int i; | 1924 | int i; |
1925 | #ifdef CONFIG_IGB_LRO | ||
1926 | int aggregated = 0, flushed = 0, no_desc = 0; | ||
1927 | |||
1928 | for (i = 0; i < adapter->num_rx_queues; i++) { | ||
1929 | aggregated += adapter->rx_ring[i].lro_mgr.stats.aggregated; | ||
1930 | flushed += adapter->rx_ring[i].lro_mgr.stats.flushed; | ||
1931 | no_desc += adapter->rx_ring[i].lro_mgr.stats.no_desc; | ||
1932 | } | ||
1933 | adapter->lro_aggregated = aggregated; | ||
1934 | adapter->lro_flushed = flushed; | ||
1935 | adapter->lro_no_desc = no_desc; | ||
1936 | #endif | ||
1920 | 1937 | ||
1921 | igb_update_stats(adapter); | 1938 | igb_update_stats(adapter); |
1922 | for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { | 1939 | for (i = 0; i < IGB_GLOBAL_STATS_LEN; i++) { |
diff --git a/drivers/net/igb/igb_main.c b/drivers/net/igb/igb_main.c index 660a78653287..89416ebda9ef 100644 --- a/drivers/net/igb/igb_main.c +++ b/drivers/net/igb/igb_main.c | |||
@@ -116,6 +116,9 @@ static bool igb_clean_tx_irq(struct igb_ring *); | |||
116 | static int igb_poll(struct napi_struct *, int); | 116 | static int igb_poll(struct napi_struct *, int); |
117 | static bool igb_clean_rx_irq_adv(struct igb_ring *, int *, int); | 117 | static bool igb_clean_rx_irq_adv(struct igb_ring *, int *, int); |
118 | static void igb_alloc_rx_buffers_adv(struct igb_ring *, int); | 118 | static void igb_alloc_rx_buffers_adv(struct igb_ring *, int); |
119 | #ifdef CONFIG_IGB_LRO | ||
120 | static int igb_get_skb_hdr(struct sk_buff *skb, void **, void **, u64 *, void *); | ||
121 | #endif | ||
119 | static int igb_ioctl(struct net_device *, struct ifreq *, int cmd); | 122 | static int igb_ioctl(struct net_device *, struct ifreq *, int cmd); |
120 | static void igb_tx_timeout(struct net_device *); | 123 | static void igb_tx_timeout(struct net_device *); |
121 | static void igb_reset_task(struct work_struct *); | 124 | static void igb_reset_task(struct work_struct *); |
@@ -1134,6 +1137,10 @@ static int __devinit igb_probe(struct pci_dev *pdev, | |||
1134 | netdev->features |= NETIF_F_TSO; | 1137 | netdev->features |= NETIF_F_TSO; |
1135 | netdev->features |= NETIF_F_TSO6; | 1138 | netdev->features |= NETIF_F_TSO6; |
1136 | 1139 | ||
1140 | #ifdef CONFIG_IGB_LRO | ||
1141 | netdev->features |= NETIF_F_LRO; | ||
1142 | #endif | ||
1143 | |||
1137 | netdev->vlan_features |= NETIF_F_TSO; | 1144 | netdev->vlan_features |= NETIF_F_TSO; |
1138 | netdev->vlan_features |= NETIF_F_TSO6; | 1145 | netdev->vlan_features |= NETIF_F_TSO6; |
1139 | netdev->vlan_features |= NETIF_F_HW_CSUM; | 1146 | netdev->vlan_features |= NETIF_F_HW_CSUM; |
@@ -1705,6 +1712,14 @@ int igb_setup_rx_resources(struct igb_adapter *adapter, | |||
1705 | struct pci_dev *pdev = adapter->pdev; | 1712 | struct pci_dev *pdev = adapter->pdev; |
1706 | int size, desc_len; | 1713 | int size, desc_len; |
1707 | 1714 | ||
1715 | #ifdef CONFIG_IGB_LRO | ||
1716 | size = sizeof(struct net_lro_desc) * MAX_LRO_DESCRIPTORS; | ||
1717 | rx_ring->lro_mgr.lro_arr = vmalloc(size); | ||
1718 | if (!rx_ring->lro_mgr.lro_arr) | ||
1719 | goto err; | ||
1720 | memset(rx_ring->lro_mgr.lro_arr, 0, size); | ||
1721 | #endif | ||
1722 | |||
1708 | size = sizeof(struct igb_buffer) * rx_ring->count; | 1723 | size = sizeof(struct igb_buffer) * rx_ring->count; |
1709 | rx_ring->buffer_info = vmalloc(size); | 1724 | rx_ring->buffer_info = vmalloc(size); |
1710 | if (!rx_ring->buffer_info) | 1725 | if (!rx_ring->buffer_info) |
@@ -1731,6 +1746,10 @@ int igb_setup_rx_resources(struct igb_adapter *adapter, | |||
1731 | return 0; | 1746 | return 0; |
1732 | 1747 | ||
1733 | err: | 1748 | err: |
1749 | #ifdef CONFIG_IGB_LRO | ||
1750 | vfree(rx_ring->lro_mgr.lro_arr); | ||
1751 | rx_ring->lro_mgr.lro_arr = NULL; | ||
1752 | #endif | ||
1734 | vfree(rx_ring->buffer_info); | 1753 | vfree(rx_ring->buffer_info); |
1735 | dev_err(&adapter->pdev->dev, "Unable to allocate memory for " | 1754 | dev_err(&adapter->pdev->dev, "Unable to allocate memory for " |
1736 | "the receive descriptor ring\n"); | 1755 | "the receive descriptor ring\n"); |
@@ -1894,6 +1913,16 @@ static void igb_configure_rx(struct igb_adapter *adapter) | |||
1894 | rxdctl |= IGB_RX_HTHRESH << 8; | 1913 | rxdctl |= IGB_RX_HTHRESH << 8; |
1895 | rxdctl |= IGB_RX_WTHRESH << 16; | 1914 | rxdctl |= IGB_RX_WTHRESH << 16; |
1896 | wr32(E1000_RXDCTL(i), rxdctl); | 1915 | wr32(E1000_RXDCTL(i), rxdctl); |
1916 | #ifdef CONFIG_IGB_LRO | ||
1917 | /* Intitial LRO Settings */ | ||
1918 | ring->lro_mgr.max_aggr = MAX_LRO_AGGR; | ||
1919 | ring->lro_mgr.max_desc = MAX_LRO_DESCRIPTORS; | ||
1920 | ring->lro_mgr.get_skb_header = igb_get_skb_hdr; | ||
1921 | ring->lro_mgr.features = LRO_F_NAPI | LRO_F_EXTRACT_VLAN_ID; | ||
1922 | ring->lro_mgr.dev = adapter->netdev; | ||
1923 | ring->lro_mgr.ip_summed = CHECKSUM_UNNECESSARY; | ||
1924 | ring->lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY; | ||
1925 | #endif | ||
1897 | } | 1926 | } |
1898 | 1927 | ||
1899 | if (adapter->num_rx_queues > 1) { | 1928 | if (adapter->num_rx_queues > 1) { |
@@ -2085,6 +2114,11 @@ static void igb_free_rx_resources(struct igb_ring *rx_ring) | |||
2085 | vfree(rx_ring->buffer_info); | 2114 | vfree(rx_ring->buffer_info); |
2086 | rx_ring->buffer_info = NULL; | 2115 | rx_ring->buffer_info = NULL; |
2087 | 2116 | ||
2117 | #ifdef CONFIG_IGB_LRO | ||
2118 | vfree(rx_ring->lro_mgr.lro_arr); | ||
2119 | rx_ring->lro_mgr.lro_arr = NULL; | ||
2120 | #endif | ||
2121 | |||
2088 | pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); | 2122 | pci_free_consistent(pdev, rx_ring->size, rx_ring->desc, rx_ring->dma); |
2089 | 2123 | ||
2090 | rx_ring->desc = NULL; | 2124 | rx_ring->desc = NULL; |
@@ -3735,22 +3769,75 @@ done_cleaning: | |||
3735 | return retval; | 3769 | return retval; |
3736 | } | 3770 | } |
3737 | 3771 | ||
3772 | #ifdef CONFIG_IGB_LRO | ||
3773 | /** | ||
3774 | * igb_get_skb_hdr - helper function for LRO header processing | ||
3775 | * @skb: pointer to sk_buff to be added to LRO packet | ||
3776 | * @iphdr: pointer to ip header structure | ||
3777 | * @tcph: pointer to tcp header structure | ||
3778 | * @hdr_flags: pointer to header flags | ||
3779 | * @priv: pointer to the receive descriptor for the current sk_buff | ||
3780 | **/ | ||
3781 | static int igb_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph, | ||
3782 | u64 *hdr_flags, void *priv) | ||
3783 | { | ||
3784 | union e1000_adv_rx_desc *rx_desc = priv; | ||
3785 | u16 pkt_type = rx_desc->wb.lower.lo_dword.pkt_info & | ||
3786 | (E1000_RXDADV_PKTTYPE_IPV4 | E1000_RXDADV_PKTTYPE_TCP); | ||
3787 | |||
3788 | /* Verify that this is a valid IPv4 TCP packet */ | ||
3789 | if (pkt_type != (E1000_RXDADV_PKTTYPE_IPV4 | | ||
3790 | E1000_RXDADV_PKTTYPE_TCP)) | ||
3791 | return -1; | ||
3792 | |||
3793 | /* Set network headers */ | ||
3794 | skb_reset_network_header(skb); | ||
3795 | skb_set_transport_header(skb, ip_hdrlen(skb)); | ||
3796 | *iphdr = ip_hdr(skb); | ||
3797 | *tcph = tcp_hdr(skb); | ||
3798 | *hdr_flags = LRO_IPV4 | LRO_TCP; | ||
3799 | |||
3800 | return 0; | ||
3801 | |||
3802 | } | ||
3803 | #endif /* CONFIG_IGB_LRO */ | ||
3738 | 3804 | ||
3739 | /** | 3805 | /** |
3740 | * igb_receive_skb - helper function to handle rx indications | 3806 | * igb_receive_skb - helper function to handle rx indications |
3741 | * @adapter: board private structure | 3807 | * @ring: pointer to receive ring receving this packet |
3742 | * @status: descriptor status field as written by hardware | 3808 | * @status: descriptor status field as written by hardware |
3743 | * @vlan: descriptor vlan field as written by hardware (no le/be conversion) | 3809 | * @vlan: descriptor vlan field as written by hardware (no le/be conversion) |
3744 | * @skb: pointer to sk_buff to be indicated to stack | 3810 | * @skb: pointer to sk_buff to be indicated to stack |
3745 | **/ | 3811 | **/ |
3746 | static void igb_receive_skb(struct igb_adapter *adapter, u8 status, __le16 vlan, | 3812 | static void igb_receive_skb(struct igb_ring *ring, u8 status, |
3747 | struct sk_buff *skb) | 3813 | union e1000_adv_rx_desc * rx_desc, |
3814 | struct sk_buff *skb) | ||
3748 | { | 3815 | { |
3749 | if (adapter->vlgrp && (status & E1000_RXD_STAT_VP)) | 3816 | struct igb_adapter * adapter = ring->adapter; |
3750 | vlan_hwaccel_receive_skb(skb, adapter->vlgrp, | 3817 | bool vlan_extracted = (adapter->vlgrp && (status & E1000_RXD_STAT_VP)); |
3751 | le16_to_cpu(vlan)); | 3818 | |
3752 | else | 3819 | #ifdef CONFIG_IGB_LRO |
3753 | netif_receive_skb(skb); | 3820 | if (adapter->netdev->features & NETIF_F_LRO && |
3821 | skb->ip_summed == CHECKSUM_UNNECESSARY) { | ||
3822 | if (vlan_extracted) | ||
3823 | lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb, | ||
3824 | adapter->vlgrp, | ||
3825 | le16_to_cpu(rx_desc->wb.upper.vlan), | ||
3826 | rx_desc); | ||
3827 | else | ||
3828 | lro_receive_skb(&ring->lro_mgr,skb, rx_desc); | ||
3829 | ring->lro_used = 1; | ||
3830 | } else { | ||
3831 | #endif | ||
3832 | if (vlan_extracted) | ||
3833 | vlan_hwaccel_receive_skb(skb, adapter->vlgrp, | ||
3834 | le16_to_cpu(rx_desc->wb.upper.vlan)); | ||
3835 | else | ||
3836 | |||
3837 | netif_receive_skb(skb); | ||
3838 | #ifdef CONFIG_IGB_LRO | ||
3839 | } | ||
3840 | #endif | ||
3754 | } | 3841 | } |
3755 | 3842 | ||
3756 | 3843 | ||
@@ -3883,7 +3970,7 @@ send_up: | |||
3883 | 3970 | ||
3884 | skb->protocol = eth_type_trans(skb, netdev); | 3971 | skb->protocol = eth_type_trans(skb, netdev); |
3885 | 3972 | ||
3886 | igb_receive_skb(adapter, staterr, rx_desc->wb.upper.vlan, skb); | 3973 | igb_receive_skb(rx_ring, staterr, rx_desc, skb); |
3887 | 3974 | ||
3888 | netdev->last_rx = jiffies; | 3975 | netdev->last_rx = jiffies; |
3889 | 3976 | ||
@@ -3906,6 +3993,13 @@ next_desc: | |||
3906 | rx_ring->next_to_clean = i; | 3993 | rx_ring->next_to_clean = i; |
3907 | cleaned_count = IGB_DESC_UNUSED(rx_ring); | 3994 | cleaned_count = IGB_DESC_UNUSED(rx_ring); |
3908 | 3995 | ||
3996 | #ifdef CONFIG_IGB_LRO | ||
3997 | if (rx_ring->lro_used) { | ||
3998 | lro_flush_all(&rx_ring->lro_mgr); | ||
3999 | rx_ring->lro_used = 0; | ||
4000 | } | ||
4001 | #endif | ||
4002 | |||
3909 | if (cleaned_count) | 4003 | if (cleaned_count) |
3910 | igb_alloc_rx_buffers_adv(rx_ring, cleaned_count); | 4004 | igb_alloc_rx_buffers_adv(rx_ring, cleaned_count); |
3911 | 4005 | ||