mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 11:46:19 +00:00
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>
This commit is contained in:
parent
8f85cd7fef
commit
177db6ffd0
4 changed files with 112 additions and 22 deletions
|
@ -2471,7 +2471,8 @@ config EHEA
|
|||
|
||||
config IXGBE
|
||||
tristate "Intel(R) 10GbE PCI Express adapters support"
|
||||
depends on PCI
|
||||
depends on PCI && INET
|
||||
select INET_LRO
|
||||
---help---
|
||||
This driver supports Intel(R) 10GbE PCI Express family of
|
||||
adapters. For more information on how to identify your adapter, go
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
#include <linux/types.h>
|
||||
#include <linux/pci.h>
|
||||
#include <linux/netdevice.h>
|
||||
#include <linux/inet_lro.h>
|
||||
|
||||
#include "ixgbe_type.h"
|
||||
#include "ixgbe_common.h"
|
||||
|
@ -100,6 +101,9 @@
|
|||
#define IXGBE_TX_FLAGS_VLAN_MASK 0xffff0000
|
||||
#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,
|
||||
* so a DMA handle can be stored along with the buffer */
|
||||
struct ixgbe_tx_buffer {
|
||||
|
@ -150,6 +154,8 @@ struct ixgbe_ring {
|
|||
/* cpu for tx queue */
|
||||
int cpu;
|
||||
#endif
|
||||
struct net_lro_mgr lro_mgr;
|
||||
bool lro_used;
|
||||
struct ixgbe_queue_stats stats;
|
||||
u8 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
|
||||
|
@ -287,6 +293,9 @@ struct ixgbe_adapter {
|
|||
|
||||
unsigned long state;
|
||||
u64 tx_busy;
|
||||
u64 lro_aggregated;
|
||||
u64 lro_flushed;
|
||||
u64 lro_no_desc;
|
||||
};
|
||||
|
||||
enum ixbge_state_t {
|
||||
|
|
|
@ -90,6 +90,8 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
|
|||
{"rx_header_split", IXGBE_STAT(rx_hdr_split)},
|
||||
{"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_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 \
|
||||
|
@ -787,6 +789,7 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
|
|||
int stat_count = sizeof(struct ixgbe_queue_stats) / sizeof(u64);
|
||||
int j, k;
|
||||
int i;
|
||||
u64 aggregated = 0, flushed = 0, no_desc = 0;
|
||||
|
||||
ixgbe_update_stats(adapter);
|
||||
for (i = 0; i < IXGBE_GLOBAL_STATS_LEN; i++) {
|
||||
|
@ -801,11 +804,17 @@ static void ixgbe_get_ethtool_stats(struct net_device *netdev,
|
|||
i += k;
|
||||
}
|
||||
for (j = 0; j < adapter->num_rx_queues; j++) {
|
||||
aggregated += adapter->rx_ring[j].lro_mgr.stats.aggregated;
|
||||
flushed += adapter->rx_ring[j].lro_mgr.stats.flushed;
|
||||
no_desc += adapter->rx_ring[j].lro_mgr.stats.no_desc;
|
||||
queue_stat = (u64 *)&adapter->rx_ring[j].stats;
|
||||
for (k = 0; k < stat_count; k++)
|
||||
data[i + k] = queue_stat[k];
|
||||
i += k;
|
||||
}
|
||||
adapter->lro_aggregated = aggregated;
|
||||
adapter->lro_flushed = flushed;
|
||||
adapter->lro_no_desc = no_desc;
|
||||
}
|
||||
|
||||
static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
|
||||
|
@ -973,6 +982,8 @@ static struct ethtool_ops ixgbe_ethtool_ops = {
|
|||
.get_ethtool_stats = ixgbe_get_ethtool_stats,
|
||||
.get_coalesce = ixgbe_get_coalesce,
|
||||
.set_coalesce = ixgbe_set_coalesce,
|
||||
.get_flags = ethtool_op_get_flags,
|
||||
.set_flags = ethtool_op_set_flags,
|
||||
};
|
||||
|
||||
void ixgbe_set_ethtool_ops(struct net_device *netdev)
|
||||
|
|
|
@ -389,24 +389,39 @@ static int __ixgbe_notify_dca(struct device *dev, void *data)
|
|||
* ixgbe_receive_skb - Send a completed packet up the stack
|
||||
* @adapter: board private structure
|
||||
* @skb: packet to send up
|
||||
* @is_vlan: packet has a VLAN tag
|
||||
* @tag: VLAN tag from descriptor
|
||||
* @status: hardware indication of status of receive
|
||||
* @rx_ring: rx descriptor ring (for a specific queue) to setup
|
||||
* @rx_desc: rx descriptor
|
||||
**/
|
||||
static void ixgbe_receive_skb(struct ixgbe_adapter *adapter,
|
||||
struct sk_buff *skb, bool is_vlan,
|
||||
u16 tag)
|
||||
struct sk_buff *skb, u8 status,
|
||||
struct ixgbe_ring *ring,
|
||||
union ixgbe_adv_rx_desc *rx_desc)
|
||||
{
|
||||
if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
|
||||
if (adapter->vlgrp && is_vlan)
|
||||
vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag);
|
||||
else
|
||||
netif_receive_skb(skb);
|
||||
} else {
|
||||
bool is_vlan = (status & IXGBE_RXD_STAT_VP);
|
||||
u16 tag = le16_to_cpu(rx_desc->wb.upper.vlan);
|
||||
|
||||
if (adapter->netdev->features & NETIF_F_LRO &&
|
||||
skb->ip_summed == CHECKSUM_UNNECESSARY) {
|
||||
if (adapter->vlgrp && is_vlan)
|
||||
vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
|
||||
lro_vlan_hwaccel_receive_skb(&ring->lro_mgr, skb,
|
||||
adapter->vlgrp, tag,
|
||||
rx_desc);
|
||||
else
|
||||
netif_rx(skb);
|
||||
lro_receive_skb(&ring->lro_mgr, skb, rx_desc);
|
||||
ring->lro_used = true;
|
||||
} else {
|
||||
if (!(adapter->flags & IXGBE_FLAG_IN_NETPOLL)) {
|
||||
if (adapter->vlgrp && is_vlan)
|
||||
vlan_hwaccel_receive_skb(skb, adapter->vlgrp, tag);
|
||||
else
|
||||
netif_receive_skb(skb);
|
||||
} else {
|
||||
if (adapter->vlgrp && is_vlan)
|
||||
vlan_hwaccel_rx(skb, adapter->vlgrp, tag);
|
||||
else
|
||||
netif_rx(skb);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -546,8 +561,8 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
|
|||
struct sk_buff *skb;
|
||||
unsigned int i;
|
||||
u32 upper_len, len, staterr;
|
||||
u16 hdr_info, vlan_tag;
|
||||
bool is_vlan, cleaned = false;
|
||||
u16 hdr_info;
|
||||
bool cleaned = false;
|
||||
int cleaned_count = 0;
|
||||
unsigned int total_rx_bytes = 0, total_rx_packets = 0;
|
||||
|
||||
|
@ -556,8 +571,6 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
|
|||
rx_desc = IXGBE_RX_DESC_ADV(*rx_ring, i);
|
||||
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
|
||||
rx_buffer_info = &rx_ring->rx_buffer_info[i];
|
||||
is_vlan = (staterr & IXGBE_RXD_STAT_VP);
|
||||
vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
|
||||
|
||||
while (staterr & IXGBE_RXD_STAT_DD) {
|
||||
if (*work_done >= work_to_do)
|
||||
|
@ -635,7 +648,7 @@ static bool ixgbe_clean_rx_irq(struct ixgbe_adapter *adapter,
|
|||
total_rx_packets++;
|
||||
|
||||
skb->protocol = eth_type_trans(skb, netdev);
|
||||
ixgbe_receive_skb(adapter, skb, is_vlan, vlan_tag);
|
||||
ixgbe_receive_skb(adapter, skb, staterr, rx_ring, rx_desc);
|
||||
netdev->last_rx = jiffies;
|
||||
|
||||
next_desc:
|
||||
|
@ -652,8 +665,11 @@ next_desc:
|
|||
rx_buffer_info = next_buffer;
|
||||
|
||||
staterr = le32_to_cpu(rx_desc->wb.upper.status_error);
|
||||
is_vlan = (staterr & IXGBE_RXD_STAT_VP);
|
||||
vlan_tag = le16_to_cpu(rx_desc->wb.upper.vlan);
|
||||
}
|
||||
|
||||
if (rx_ring->lro_used) {
|
||||
lro_flush_all(&rx_ring->lro_mgr);
|
||||
rx_ring->lro_used = false;
|
||||
}
|
||||
|
||||
rx_ring->next_to_clean = i;
|
||||
|
@ -1381,6 +1397,33 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
|
|||
(((S) & (PAGE_SIZE - 1)) ? 1 : 0))
|
||||
|
||||
#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
|
||||
/**
|
||||
* ixgbe_get_skb_hdr - helper function for LRO header processing
|
||||
* @skb: pointer to sk_buff to be added to LRO packet
|
||||
* @iphdr: pointer to tcp 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 (!(rx_desc->wb.lower.lo_dword.pkt_info &
|
||||
(IXGBE_RXDADV_PKTTYPE_IPV4 | 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* ixgbe_configure_rx - Configure 8254x Receive Unit after Reset
|
||||
* @adapter: board private structure
|
||||
|
@ -1470,6 +1513,17 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
|
|||
adapter->rx_ring[i].tail = IXGBE_RDT(i);
|
||||
}
|
||||
|
||||
/* 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;
|
||||
|
||||
if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
|
||||
/* Fill out redirection table */
|
||||
for (i = 0, j = 0; i < 128; i++, j++) {
|
||||
|
@ -2489,12 +2543,18 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
|
|||
struct pci_dev *pdev = adapter->pdev;
|
||||
int size;
|
||||
|
||||
size = sizeof(struct net_lro_desc) * IXGBE_MAX_LRO_DESCRIPTORS;
|
||||
rxdr->lro_mgr.lro_arr = vmalloc(size);
|
||||
if (!rxdr->lro_mgr.lro_arr)
|
||||
return -ENOMEM;
|
||||
memset(rxdr->lro_mgr.lro_arr, 0, size);
|
||||
|
||||
size = sizeof(struct ixgbe_rx_buffer) * rxdr->count;
|
||||
rxdr->rx_buffer_info = vmalloc(size);
|
||||
if (!rxdr->rx_buffer_info) {
|
||||
DPRINTK(PROBE, ERR,
|
||||
"vmalloc allocation failed for the rx desc ring\n");
|
||||
return -ENOMEM;
|
||||
goto alloc_failed;
|
||||
}
|
||||
memset(rxdr->rx_buffer_info, 0, size);
|
||||
|
||||
|
@ -2508,13 +2568,18 @@ int ixgbe_setup_rx_resources(struct ixgbe_adapter *adapter,
|
|||
DPRINTK(PROBE, ERR,
|
||||
"Memory allocation failed for the rx desc ring\n");
|
||||
vfree(rxdr->rx_buffer_info);
|
||||
return -ENOMEM;
|
||||
goto alloc_failed;
|
||||
}
|
||||
|
||||
rxdr->next_to_clean = 0;
|
||||
rxdr->next_to_use = 0;
|
||||
|
||||
return 0;
|
||||
|
||||
alloc_failed:
|
||||
vfree(rxdr->lro_mgr.lro_arr);
|
||||
rxdr->lro_mgr.lro_arr = NULL;
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -2565,6 +2630,9 @@ static void ixgbe_free_rx_resources(struct ixgbe_adapter *adapter,
|
|||
{
|
||||
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);
|
||||
|
||||
vfree(rx_ring->rx_buffer_info);
|
||||
|
@ -3517,6 +3585,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
|
|||
NETIF_F_HW_VLAN_RX |
|
||||
NETIF_F_HW_VLAN_FILTER;
|
||||
|
||||
netdev->features |= NETIF_F_LRO;
|
||||
netdev->features |= NETIF_F_TSO;
|
||||
netdev->features |= NETIF_F_TSO6;
|
||||
|
||||
|
|
Loading…
Reference in a new issue