ixgbe: Replace LRO with GRO

This patch makes ixgbe invoke the GRO hooks instead of LRO.  As
GRO has a compatible external interface to LRO this is a very
straightforward replacement.

As GRO uses the napi structure to track the held packets, I've
modified the code paths involved to pass that along.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Herbert Xu 2009-01-18 21:49:45 -08:00 committed by David S. Miller
parent f3f3abb62c
commit 78b6f4ce58
4 changed files with 13 additions and 89 deletions

View File

@ -2444,7 +2444,6 @@ config ENIC
config IXGBE config IXGBE
tristate "Intel(R) 10GbE PCI Express adapters support" tristate "Intel(R) 10GbE PCI Express adapters support"
depends on PCI && INET depends on PCI && INET
select INET_LRO
---help--- ---help---
This driver supports Intel(R) 10GbE PCI Express family of This driver supports Intel(R) 10GbE PCI Express family of
adapters. For more information on how to identify your adapter, go adapters. For more information on how to identify your adapter, go

View File

@ -31,7 +31,6 @@
#include <linux/types.h> #include <linux/types.h>
#include <linux/pci.h> #include <linux/pci.h>
#include <linux/netdevice.h> #include <linux/netdevice.h>
#include <linux/inet_lro.h>
#include <linux/aer.h> #include <linux/aer.h>
#include "ixgbe_type.h" #include "ixgbe_type.h"
@ -88,9 +87,6 @@
#define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000 #define IXGBE_TX_FLAGS_VLAN_PRIO_MASK 0x0000e000
#define IXGBE_TX_FLAGS_VLAN_SHIFT 16 #define IXGBE_TX_FLAGS_VLAN_SHIFT 16
#define IXGBE_MAX_LRO_DESCRIPTORS 8
#define IXGBE_MAX_LRO_AGGREGATE 32
/* wrapper around a pointer to a socket buffer, /* wrapper around a pointer to a socket buffer,
* so a DMA handle can be stored along with the buffer */ * so a DMA handle can be stored along with the buffer */
struct ixgbe_tx_buffer { struct ixgbe_tx_buffer {
@ -142,8 +138,6 @@ struct ixgbe_ring {
/* cpu for tx queue */ /* cpu for tx queue */
int cpu; int cpu;
#endif #endif
struct net_lro_mgr lro_mgr;
bool lro_used;
struct ixgbe_queue_stats stats; struct ixgbe_queue_stats stats;
u16 v_idx; /* maps directly to the index for this ring in the hardware u16 v_idx; /* maps directly to the index for this ring in the hardware
* vector array, can also be used for finding the bit in EICR * vector array, can also be used for finding the bit in EICR
@ -301,9 +295,6 @@ struct ixgbe_adapter {
unsigned long state; unsigned long state;
u64 tx_busy; u64 tx_busy;
u64 lro_aggregated;
u64 lro_flushed;
u64 lro_no_desc;
unsigned int tx_ring_count; unsigned int tx_ring_count;
unsigned int rx_ring_count; unsigned int rx_ring_count;

View File

@ -89,8 +89,6 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
{"rx_header_split", IXGBE_STAT(rx_hdr_split)}, {"rx_header_split", IXGBE_STAT(rx_hdr_split)},
{"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)}, {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)},
{"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)}, {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)},
{"lro_aggregated", IXGBE_STAT(lro_aggregated)},
{"lro_flushed", IXGBE_STAT(lro_flushed)},
}; };
#define IXGBE_QUEUE_STATS_LEN \ #define IXGBE_QUEUE_STATS_LEN \
@ -808,15 +806,6 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64); int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
int j, k; int j, k;
int i; int i;
u64 aggregated = 0, flushed = 0, no_desc = 0;
for (i = 0; i < adapter->num_rx_queues; i++) {
aggregated += adapter->rx_ring[i].lro_mgr.stats.aggregated;
flushed += adapter->rx_ring[i].lro_mgr.stats.flushed;
no_desc += adapter->rx_ring[i].lro_mgr.stats.no_desc;
}
adapter->lro_aggregated = aggregated;
adapter->lro_flushed = flushed;
adapter->lro_no_desc = no_desc;
ixgbe_update_stats(adapter); ixgbe_update_stats(adapter);
for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) { for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {

View File

@ -403,23 +403,20 @@ static int __ixgbe_notify_dca(struct device *dev, void *data)
* @rx_ring: rx descriptor ring (for a specific queue) to setup * @rx_ring: rx descriptor ring (for a specific queue) to setup
* @rx_desc: rx descriptor * @rx_desc: rx descriptor
**/ **/
static void ixgbe_receive_skb(struct ixgbe_adapter *adapter, static void ixgbe_receive_skb(struct ixgbe_q_vector *q_vector,
struct sk_buff *skb, u8 status, struct sk_buff *skb, u8 status,
struct ixgbe_ring *ring,
union ixgbe_adv_rx_desc *rx_desc) union ixgbe_adv_rx_desc *rx_desc)
{ {
struct ixgbe_adapter *adapter = q_vector->adapter;
struct napi_struct *napi = &q_vector->napi;
bool is_vlan = (status & IXGBE_RXD_STAT_VP); bool is_vlan = (status & IXGBE_RXD_STAT_VP);
u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan); u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
if (adapter->netdev->features & NETIF_F_LRO && if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
skb->ip_summed == CHECKSUM_UNNECESSARY) {
if (adapter->vlgrp && is_vlan && (tag != 0)) if (adapter->vlgrp && is_vlan && (tag != 0))
lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb, vlan_gro_receive(napi, adapter->vlgrp, tag, skb);
adapter->vlgrp, tag,
rx_desc);
else else
lro_receive_skb(&ring->lro_mgr, skb, rx_desc); napi_gro_receive(napi, skb);
ring->lro_used = true;
} else { } else {
if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) { if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
if (adapter->vlgrp && is_vlan && (tag != 0)) if (adapter->vlgrp && is_vlan && (tag != 0))
@ -574,10 +571,11 @@ static inline u16 ixgbe_get_pkt_info(union ixgbe_adv_rx_desc *rx_desc)
return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info; return rx_desc->wb.lower.lo_dword.hs_rss.pkt_info;
} }
static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter, static bool ixgbe_clean_rx_irq(struct ixgbe_q_vector *q_vector,
struct ixgbe_ring *rx_ring, struct ixgbe_ring *rx_ring,
int *work_done, int work_to_do) int *work_done, int work_to_do)
{ {
struct ixgbe_adapter *adapter = q_vector->adapter;
struct pci_dev *pdev = adapter->pdev; struct pci_dev *pdev = adapter->pdev;
union ixgbe_adv_rx_desc *rx_desc, *next_rxd; union ixgbe_adv_rx_desc *rx_desc, *next_rxd;
struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer; struct ixgbe_rx_buffer *rx_buffer_info, *next_buffer;
@ -678,7 +676,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
total_rx_packets++; total_rx_packets++;
skb->protocol = eth_type_trans(skb, adapter->netdev); skb->protocol = eth_type_trans(skb, adapter->netdev);
ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc); ixgbe_receive_skb(q_vector, skb, staterr, rx_desc);
next_desc: next_desc:
rx_desc->wb.upper.status_error = 0; rx_desc->wb.upper.status_error = 0;
@ -696,11 +694,6 @@ next_desc:
staterr = le32_to_cpu(rx_desc->wb.upper.status_error); staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
} }
if (rx_ring->lro_used) {
lro_flush_all(&rx_ring->lro_mgr);
rx_ring->lro_used = false;
}
rx_ring->next_to_clean = i; rx_ring->next_to_clean = i;
cleaned_count = IXGBE_DESC_UNUSED(rx_ring); cleaned_count = IXGBE_DESC_UNUSED(rx_ring);
@ -1052,7 +1045,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
ixgbe_update_rx_dca(adapter, rx_ring); ixgbe_update_rx_dca(adapter, rx_ring);
#endif #endif
ixgbe_clean_rx_irq(adapter, rx_ring, &work_done, budget); ixgbe_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
/* If all Rx work done, exit the polling mode */ /* If all Rx work done, exit the polling mode */
if (work_done < budget) { if (work_done < budget) {
@ -1095,7 +1088,7 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget)
if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) if (adapter->flags & IXGBE_FLAG_DCA_ENABLED)
ixgbe_update_rx_dca(adapter, rx_ring); ixgbe_update_rx_dca(adapter, rx_ring);
#endif #endif
ixgbe_clean_rx_irq(adapter, rx_ring, &work_done, budget); ixgbe_clean_rx_irq(q_vector, rx_ring, &work_done, budget);
enable_mask |= rx_ring->v_idx; enable_mask |= rx_ring->v_idx;
r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues, r_idx = find_next_bit(q_vector->rxr_idx, adapter->num_rx_queues,
r_idx + 1); r_idx + 1);
@ -1568,33 +1561,6 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index)
IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl); IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl);
} }
/**
* ixgbe_get_skb_hdr - helper function for LRO header processing
* @skb: pointer to sk_buff to be added to LRO packet
* @iphdr: pointer to ip header structure
* @tcph: pointer to tcp header structure
* @hdr_flags: pointer to header flags
* @priv: private data
**/
static int ixgbe_get_skb_hdr(struct sk_buff *skb, void **iphdr, void **tcph,
u64 *hdr_flags, void *priv)
{
union ixgbe_adv_rx_desc *rx_desc = priv;
/* Verify that this is a valid IPv4 TCP packet */
if (!((ixgbe_get_pkt_info(rx_desc) & IXGBE_RXDADV_PKTTYPE_IPV4) &&
(ixgbe_get_pkt_info(rx_desc) & IXGBE_RXDADV_PKTTYPE_TCP)))
return -1;
/* Set network headers */
skb_reset_network_header(skb);
skb_set_transport_header(skb, ip_hdrlen(skb));
*iphdr = ip_hdr(skb);
*tcph = tcp_hdr(skb);
*hdr_flags = LRO_IPV4 | LRO_TCP;
return 0;
}
#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \ #define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
(((S) & (PAGE_SIZE - 1)) ? 1 : 0)) (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
@ -1666,16 +1632,6 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
adapter->rx_ring[i].head = IXGBE_RDH(j); adapter->rx_ring[i].head = IXGBE_RDH(j);
adapter->rx_ring[i].tail = IXGBE_RDT(j); adapter->rx_ring[i].tail = IXGBE_RDT(j);
adapter->rx_ring[i].rx_buf_len = rx_buf_len; adapter->rx_ring[i].rx_buf_len = rx_buf_len;
/* Intitial LRO Settings */
adapter->rx_ring[i].lro_mgr.max_aggr = IXGBE_MAX_LRO_AGGREGATE;
adapter->rx_ring[i].lro_mgr.max_desc = IXGBE_MAX_LRO_DESCRIPTORS;
adapter->rx_ring[i].lro_mgr.get_skb_header = ixgbe_get_skb_hdr;
adapter->rx_ring[i].lro_mgr.features = LRO_F_EXTRACT_VLAN_ID;
if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL))
adapter->rx_ring[i].lro_mgr.features |= LRO_F_NAPI;
adapter->rx_ring[i].lro_mgr.dev = adapter->netdev;
adapter->rx_ring[i].lro_mgr.ip_summed = CHECKSUM_UNNECESSARY;
adapter->rx_ring[i].lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
ixgbe_configure_srrctl(adapter, j); ixgbe_configure_srrctl(adapter, j);
} }
@ -2310,7 +2266,7 @@ static int ixgbe_poll(struct napi_struct *napi, int budget)
#endif #endif
tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring); tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
ixgbe_clean_rx_irq(adapter, adapter->rx_ring, &work_done, budget); ixgbe_clean_rx_irq(q_vector, adapter->rx_ring, &work_done, budget);
if (tx_cleaned) if (tx_cleaned)
work_done = budget; work_done = budget;
@ -2926,12 +2882,6 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
struct pci_dev *pdev = adapter->pdev; struct pci_dev *pdev = adapter->pdev;
int size; int size;
size = sizeof(struct net_lro_desc) * IXGBE_MAX_LRO_DESCRIPTORS;
rx_ring->lro_mgr.lro_arr = vmalloc(size);
if (!rx_ring->lro_mgr.lro_arr)
return -ENOMEM;
memset(rx_ring->lro_mgr.lro_arr, 0, size);
size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count; size = sizeof(struct ixgbe_rx_buffer) * rx_ring->count;
rx_ring->rx_buffer_info = vmalloc(size); rx_ring->rx_buffer_info = vmalloc(size);
if (!rx_ring->rx_buffer_info) { if (!rx_ring->rx_buffer_info) {
@ -2960,8 +2910,6 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
return 0; return 0;
alloc_failed: alloc_failed:
vfree(rx_ring->lro_mgr.lro_arr);
rx_ring->lro_mgr.lro_arr = NULL;
return -ENOMEM; return -ENOMEM;
} }
@ -3039,9 +2987,6 @@ void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
{ {
struct pci_dev *pdev = adapter->pdev; struct pci_dev *pdev = adapter->pdev;
vfree(rx_ring->lro_mgr.lro_arr);
rx_ring->lro_mgr.lro_arr = NULL;
ixgbe_clean_rx_ring(adapter, rx_ring); ixgbe_clean_rx_ring(adapter, rx_ring);
vfree(rx_ring->rx_buffer_info); vfree(rx_ring->rx_buffer_info);
@ -4141,7 +4086,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
netdev->features |= NETIF_F_IPV6_CSUM; netdev->features |= NETIF_F_IPV6_CSUM;
netdev->features |= NETIF_F_TSO; netdev->features |= NETIF_F_TSO;
netdev->features |= NETIF_F_TSO6; netdev->features |= NETIF_F_TSO6;
netdev->features |= NETIF_F_LRO; netdev->features |= NETIF_F_GRO;
netdev->vlan_features |= NETIF_F_TSO; netdev->vlan_features |= NETIF_F_TSO;
netdev->vlan_features |= NETIF_F_TSO6; netdev->vlan_features |= NETIF_F_TSO6;