Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 133852
b: refs/heads/master
c: da3bc07
h: refs/heads/master
v: v3
  • Loading branch information
Herbert Xu authored and David S. Miller committed Jan 21, 2009
1 parent bc83175 commit 38e8353
Show file tree
Hide file tree
Showing 8 changed files with 20 additions and 215 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 78b6f4ce58d1c85190003840912cc9097cbb8146
refs/heads/master: da3bc07171dff957906cbe2ad5abb443eccf57c4
1 change: 0 additions & 1 deletion trunk/drivers/net/sfc/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ config SFC
tristate "Solarflare Solarstorm SFC4000 support"
depends on PCI && INET
select MII
select INET_LRO
select CRC32
select I2C
select I2C_ALGOBIT
Expand Down
11 changes: 1 addition & 10 deletions trunk/drivers/net/sfc/efx.c
Original file line number Diff line number Diff line change
Expand Up @@ -182,7 +182,6 @@ static int efx_process_channel(struct efx_channel *channel, int rx_quota)
channel->rx_pkt = NULL;
}

efx_flush_lro(channel);
efx_rx_strategy(channel);

efx_fast_push_rx_descriptors(&efx->rx_queue[channel->channel]);
Expand Down Expand Up @@ -1269,26 +1268,18 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
static int efx_init_napi(struct efx_nic *efx)
{
struct efx_channel *channel;
int rc;

efx_for_each_channel(channel, efx) {
channel->napi_dev = efx->net_dev;
rc = efx_lro_init(&channel->lro_mgr, efx);
if (rc)
goto err;
}
return 0;
err:
efx_fini_napi(efx);
return rc;
}

static void efx_fini_napi(struct efx_nic *efx)
{
struct efx_channel *channel;

efx_for_each_channel(channel, efx) {
efx_lro_fini(&channel->lro_mgr);
channel->napi_dev = NULL;
}
}
Expand Down Expand Up @@ -2097,7 +2088,7 @@ static int __devinit efx_pci_probe(struct pci_dev *pci_dev,
net_dev->features |= (NETIF_F_IP_CSUM | NETIF_F_SG |
NETIF_F_HIGHDMA | NETIF_F_TSO);
if (lro)
net_dev->features |= NETIF_F_LRO;
net_dev->features |= NETIF_F_GRO;
/* Mask for features that also apply to VLAN devices */
net_dev->vlan_features |= (NETIF_F_ALL_CSUM | NETIF_F_SG |
NETIF_F_HIGHDMA | NETIF_F_TSO);
Expand Down
9 changes: 0 additions & 9 deletions trunk/drivers/net/sfc/net_driver.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,15 +25,11 @@
#include <linux/device.h>
#include <linux/highmem.h>
#include <linux/workqueue.h>
#include <linux/inet_lro.h>
#include <linux/i2c.h>

#include "enum.h"
#include "bitfield.h"

#define EFX_MAX_LRO_DESCRIPTORS 8
#define EFX_MAX_LRO_AGGR MAX_SKB_FRAGS

/**************************************************************************
*
* Build definitions
Expand Down Expand Up @@ -340,13 +336,10 @@ enum efx_rx_alloc_method {
* @eventq_read_ptr: Event queue read pointer
* @last_eventq_read_ptr: Last event queue read pointer value.
* @eventq_magic: Event queue magic value for driver-generated test events
* @lro_mgr: LRO state
* @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
* and diagnostic counters
* @rx_alloc_push_pages: RX allocation method currently in use for pushing
* descriptors
* @rx_alloc_pop_pages: RX allocation method currently in use for popping
* descriptors
* @n_rx_tobe_disc: Count of RX_TOBE_DISC errors
* @n_rx_ip_frag_err: Count of RX IP fragment errors
* @n_rx_ip_hdr_chksum_err: Count of RX IP header checksum errors
Expand All @@ -371,10 +364,8 @@ struct efx_channel {
unsigned int last_eventq_read_ptr;
unsigned int eventq_magic;

struct net_lro_mgr lro_mgr;
int rx_alloc_level;
int rx_alloc_push_pages;
int rx_alloc_pop_pages;

unsigned n_rx_tobe_disc;
unsigned n_rx_ip_frag_err;
Expand Down
207 changes: 16 additions & 191 deletions trunk/drivers/net/sfc/rx.c
Original file line number Diff line number Diff line change
Expand Up @@ -99,109 +99,6 @@ static inline unsigned int efx_rx_buf_size(struct efx_nic *efx)
}


/**************************************************************************
*
* Linux generic LRO handling
*
**************************************************************************
*/

static int efx_lro_get_skb_hdr(struct sk_buff *skb, void **ip_hdr,
void **tcpudp_hdr, u64 *hdr_flags, void *priv)
{
struct efx_channel *channel = priv;
struct iphdr *iph;
struct tcphdr *th;

iph = (struct iphdr *)skb->data;
if (skb->protocol != htons(ETH_P_IP) || iph->protocol != IPPROTO_TCP)
goto fail;

th = (struct tcphdr *)(skb->data + iph->ihl * 4);

*tcpudp_hdr = th;
*ip_hdr = iph;
*hdr_flags = LRO_IPV4 | LRO_TCP;

channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
return 0;
fail:
channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
return -1;
}

static int efx_get_frag_hdr(struct skb_frag_struct *frag, void **mac_hdr,
void **ip_hdr, void **tcpudp_hdr, u64 *hdr_flags,
void *priv)
{
struct efx_channel *channel = priv;
struct ethhdr *eh;
struct iphdr *iph;

/* We support EtherII and VLAN encapsulated IPv4 */
eh = page_address(frag->page) + frag->page_offset;
*mac_hdr = eh;

if (eh->h_proto == htons(ETH_P_IP)) {
iph = (struct iphdr *)(eh + 1);
} else {
struct vlan_ethhdr *veh = (struct vlan_ethhdr *)eh;
if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
goto fail;

iph = (struct iphdr *)(veh + 1);
}
*ip_hdr = iph;

/* We can only do LRO over TCP */
if (iph->protocol != IPPROTO_TCP)
goto fail;

*hdr_flags = LRO_IPV4 | LRO_TCP;
*tcpudp_hdr = (struct tcphdr *)((u8 *) iph + iph->ihl * 4);

channel->rx_alloc_level += RX_ALLOC_FACTOR_LRO;
return 0;
fail:
channel->rx_alloc_level += RX_ALLOC_FACTOR_SKB;
return -1;
}

int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx)
{
size_t s = sizeof(struct net_lro_desc) * EFX_MAX_LRO_DESCRIPTORS;
struct net_lro_desc *lro_arr;

/* Allocate the LRO descriptors structure */
lro_arr = kzalloc(s, GFP_KERNEL);
if (lro_arr == NULL)
return -ENOMEM;

lro_mgr->lro_arr = lro_arr;
lro_mgr->max_desc = EFX_MAX_LRO_DESCRIPTORS;
lro_mgr->max_aggr = EFX_MAX_LRO_AGGR;
lro_mgr->frag_align_pad = EFX_PAGE_SKB_ALIGN;

lro_mgr->get_skb_header = efx_lro_get_skb_hdr;
lro_mgr->get_frag_header = efx_get_frag_hdr;
lro_mgr->dev = efx->net_dev;

lro_mgr->features = LRO_F_NAPI;

/* We can pass packets up with the checksum intact */
lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;

lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;

return 0;
}

void efx_lro_fini(struct net_lro_mgr *lro_mgr)
{
kfree(lro_mgr->lro_arr);
lro_mgr->lro_arr = NULL;
}

/**
* efx_init_rx_buffer_skb - create new RX buffer using skb-based allocation
*
Expand Down Expand Up @@ -549,77 +446,31 @@ static void efx_rx_packet__check_len(struct efx_rx_queue *rx_queue,
static void efx_rx_packet_lro(struct efx_channel *channel,
struct efx_rx_buffer *rx_buf)
{
struct net_lro_mgr *lro_mgr = &channel->lro_mgr;
void *priv = channel;
struct napi_struct *napi = &channel->napi_str;

/* Pass the skb/page into the LRO engine */
if (rx_buf->page) {
struct skb_frag_struct frags;
struct napi_gro_fraginfo info;

frags.page = rx_buf->page;
frags.page_offset = efx_rx_buf_offset(rx_buf);
frags.size = rx_buf->len;
info.frags[0].page = rx_buf->page;
info.frags[0].page_offset = efx_rx_buf_offset(rx_buf);
info.frags[0].size = rx_buf->len;
info.nr_frags = 1;
info.ip_summed = CHECKSUM_UNNECESSARY;
info.len = rx_buf->len;

lro_receive_frags(lro_mgr, &frags, rx_buf->len,
rx_buf->len, priv, 0);
napi_gro_frags(napi, &info);

EFX_BUG_ON_PARANOID(rx_buf->skb);
rx_buf->page = NULL;
} else {
EFX_BUG_ON_PARANOID(!rx_buf->skb);

lro_receive_skb(lro_mgr, rx_buf->skb, priv);
napi_gro_receive(napi, rx_buf->skb);
rx_buf->skb = NULL;
}
}

/* Allocate and construct an SKB around a struct page.*/
static struct sk_buff *efx_rx_mk_skb(struct efx_rx_buffer *rx_buf,
struct efx_nic *efx,
int hdr_len)
{
struct sk_buff *skb;

/* Allocate an SKB to store the headers */
skb = netdev_alloc_skb(efx->net_dev, hdr_len + EFX_PAGE_SKB_ALIGN);
if (unlikely(skb == NULL)) {
EFX_ERR_RL(efx, "RX out of memory for skb\n");
return NULL;
}

EFX_BUG_ON_PARANOID(skb_shinfo(skb)->nr_frags);
EFX_BUG_ON_PARANOID(rx_buf->len < hdr_len);

skb->ip_summed = CHECKSUM_UNNECESSARY;
skb_reserve(skb, EFX_PAGE_SKB_ALIGN);

skb->len = rx_buf->len;
skb->truesize = rx_buf->len + sizeof(struct sk_buff);
memcpy(skb->data, rx_buf->data, hdr_len);
skb->tail += hdr_len;

/* Append the remaining page onto the frag list */
if (unlikely(rx_buf->len > hdr_len)) {
struct skb_frag_struct *frag = skb_shinfo(skb)->frags;
frag->page = rx_buf->page;
frag->page_offset = efx_rx_buf_offset(rx_buf) + hdr_len;
frag->size = skb->len - hdr_len;
skb_shinfo(skb)->nr_frags = 1;
skb->data_len = frag->size;
} else {
__free_pages(rx_buf->page, efx->rx_buffer_order);
skb->data_len = 0;
}

/* Ownership has transferred from the rx_buf to skb */
rx_buf->page = NULL;

/* Move past the ethernet header */
skb->protocol = eth_type_trans(skb, efx->net_dev);

return skb;
}

void efx_rx_packet(struct efx_rx_queue *rx_queue, unsigned int index,
unsigned int len, bool checksummed, bool discard)
{
Expand Down Expand Up @@ -687,7 +538,6 @@ void __efx_rx_packet(struct efx_channel *channel,
{
struct efx_nic *efx = channel->efx;
struct sk_buff *skb;
bool lro = !!(efx->net_dev->features & NETIF_F_LRO);

/* If we're in loopback test, then pass the packet directly to the
* loopback layer, and free the rx_buf here
Expand All @@ -709,41 +559,21 @@ void __efx_rx_packet(struct efx_channel *channel,
efx->net_dev);
}

/* Both our generic-LRO and SFC-SSR support skb and page based
* allocation, but neither support switching from one to the
* other on the fly. If we spot that the allocation mode has
* changed, then flush the LRO state.
*/
if (unlikely(channel->rx_alloc_pop_pages != (rx_buf->page != NULL))) {
efx_flush_lro(channel);
channel->rx_alloc_pop_pages = (rx_buf->page != NULL);
}
if (likely(checksummed && lro)) {
if (likely(checksummed || rx_buf->page)) {
efx_rx_packet_lro(channel, rx_buf);
goto done;
}

/* Form an skb if required */
if (rx_buf->page) {
int hdr_len = min(rx_buf->len, EFX_SKB_HEADERS);
skb = efx_rx_mk_skb(rx_buf, efx, hdr_len);
if (unlikely(skb == NULL)) {
efx_free_rx_buffer(efx, rx_buf);
goto done;
}
} else {
/* We now own the SKB */
skb = rx_buf->skb;
rx_buf->skb = NULL;
}
/* We now own the SKB */
skb = rx_buf->skb;
rx_buf->skb = NULL;

EFX_BUG_ON_PARANOID(rx_buf->page);
EFX_BUG_ON_PARANOID(rx_buf->skb);
EFX_BUG_ON_PARANOID(!skb);

/* Set the SKB flags */
if (unlikely(!checksummed || !efx->rx_checksum_enabled))
skb->ip_summed = CHECKSUM_NONE;
skb->ip_summed = CHECKSUM_NONE;

/* Pass the packet up */
netif_receive_skb(skb);
Expand All @@ -760,7 +590,7 @@ void efx_rx_strategy(struct efx_channel *channel)
enum efx_rx_alloc_method method = rx_alloc_method;

/* Only makes sense to use page based allocation if LRO is enabled */
if (!(channel->efx->net_dev->features & NETIF_F_LRO)) {
if (!(channel->efx->net_dev->features & NETIF_F_GRO)) {
method = RX_ALLOC_METHOD_SKB;
} else if (method == RX_ALLOC_METHOD_AUTO) {
/* Constrain the rx_alloc_level */
Expand Down Expand Up @@ -865,11 +695,6 @@ void efx_remove_rx_queue(struct efx_rx_queue *rx_queue)
rx_queue->buffer = NULL;
}

void efx_flush_lro(struct efx_channel *channel)
{
lro_flush_all(&channel->lro_mgr);
}


module_param(rx_alloc_method, int, 0644);
MODULE_PARM_DESC(rx_alloc_method, "Allocation method used for RX buffers");
Expand Down
3 changes: 0 additions & 3 deletions trunk/drivers/net/sfc/rx.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,6 @@ void efx_remove_rx_queue(struct efx_rx_queue *rx_queue);
void efx_init_rx_queue(struct efx_rx_queue *rx_queue);
void efx_fini_rx_queue(struct efx_rx_queue *rx_queue);

int efx_lro_init(struct net_lro_mgr *lro_mgr, struct efx_nic *efx);
void efx_lro_fini(struct net_lro_mgr *lro_mgr);
void efx_flush_lro(struct efx_channel *channel);
void efx_rx_strategy(struct efx_channel *channel);
void efx_fast_push_rx_descriptors(struct efx_rx_queue *rx_queue);
void efx_rx_work(struct work_struct *data);
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/net/sfc/sfe4001.c
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@
*/

#include <linux/delay.h>
#include <linux/rtnetlink.h>
#include "net_driver.h"
#include "efx.h"
#include "phy.h"
Expand Down
1 change: 1 addition & 0 deletions trunk/drivers/net/sfc/tenxpress.c
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
*/

#include <linux/delay.h>
#include <linux/rtnetlink.h>
#include <linux/seq_file.h>
#include "efx.h"
#include "mdio_10g.h"
Expand Down

0 comments on commit 38e8353

Please sign in to comment.