Skip to content

Commit

Permalink
cxgb3: Replace LRO with GRO
Browse files Browse the repository at this point in the history
This patch makes cxgb3 invoke the GRO hooks instead of LRO.  As
GRO has a compatible external interface to LRO this is a very
straightforward replacement.

I've kept the ioctl controls for per-queue LRO switches.  However,
we should not encourage anyone to use these.

Because of that, I've also kept the skb construction code in
cxgb3.  Hopefully we can phase out those per-queue switches
and then kill this too.

Signed-off-by: Herbert Xu <herbert@gondor.apana.org.au>
Acked-by: Divy Le Ray <divy@chelsio.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Herbert Xu authored and David S. Miller committed Jan 21, 2009
1 parent 749c10f commit 7be2df4
Show file tree
Hide file tree
Showing 5 changed files with 24 additions and 153 deletions.
1 change: 0 additions & 1 deletion drivers/net/Kconfig
Original file line number Diff line number Diff line change
Expand Up @@ -2407,7 +2407,6 @@ config CHELSIO_T3
tristate "Chelsio Communications T3 10Gb Ethernet support"
depends on CHELSIO_T3_DEPENDS
select FW_LOADER
select INET_LRO
help
This driver supports Chelsio T3-based gigabit and 10Gb Ethernet
adapters.
Expand Down
13 changes: 2 additions & 11 deletions drivers/net/cxgb3/adapter.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,6 @@
#include <linux/cache.h>
#include <linux/mutex.h>
#include <linux/bitops.h>
#include <linux/inet_lro.h>
#include "t3cdev.h"
#include <asm/io.h>

Expand Down Expand Up @@ -178,28 +177,20 @@ enum { /* per port SGE statistics */
SGE_PSTAT_TX_CSUM, /* # of TX checksum offloads */
SGE_PSTAT_VLANEX, /* # of VLAN tag extractions */
SGE_PSTAT_VLANINS, /* # of VLAN tag insertions */
SGE_PSTAT_LRO_AGGR, /* # of page chunks added to LRO sessions */
SGE_PSTAT_LRO_FLUSHED, /* # of flushed LRO sessions */
SGE_PSTAT_LRO_NO_DESC, /* # of overflown LRO sessions */

SGE_PSTAT_MAX /* must be last */
};

#define T3_MAX_LRO_SES 8
#define T3_MAX_LRO_MAX_PKTS 64
struct napi_gro_fraginfo;

struct sge_qset { /* an SGE queue set */
struct adapter *adap;
struct napi_struct napi;
struct sge_rspq rspq;
struct sge_fl fl[SGE_RXQ_PER_SET];
struct sge_txq txq[SGE_TXQ_PER_SET];
struct net_lro_mgr lro_mgr;
struct net_lro_desc lro_desc[T3_MAX_LRO_SES];
struct skb_frag_struct *lro_frag_tbl;
int lro_nfrags;
struct napi_gro_fraginfo lro_frag_tbl;
int lro_enabled;
int lro_frag_len;
void *lro_va;
struct net_device *netdev;
struct netdev_queue *tx_q; /* associated netdev TX queue */
Expand Down
42 changes: 4 additions & 38 deletions drivers/net/cxgb3/cxgb3_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -508,19 +508,9 @@ static void set_qset_lro(struct net_device *dev, int qset_idx, int val)
{
struct port_info *pi = netdev_priv(dev);
struct adapter *adapter = pi->adapter;
int i, lro_on = 1;

adapter->params.sge.qset[qset_idx].lro = !!val;
adapter->sge.qs[qset_idx].lro_enabled = !!val;

/* let ethtool report LRO on only if all queues are LRO enabled */
for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; ++i)
lro_on &= adapter->params.sge.qset[i].lro;

if (lro_on)
dev->features |= NETIF_F_LRO;
else
dev->features &= ~NETIF_F_LRO;
}

/**
Expand Down Expand Up @@ -1433,9 +1423,9 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_VLANINS);
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_TX_CSUM);
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_RX_CSUM_GOOD);
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_AGGR);
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_FLUSHED);
*data++ = collect_sge_port_stats(adapter, pi, SGE_PSTAT_LRO_NO_DESC);
*data++ = 0;
*data++ = 0;
*data++ = 0;
*data++ = s->rx_cong_drops;

*data++ = s->num_toggled;
Expand Down Expand Up @@ -1826,28 +1816,6 @@ static void get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
memset(&wol->sopass, 0, sizeof(wol->sopass));
}

static int cxgb3_set_flags(struct net_device *dev, u32 data)
{
struct port_info *pi = netdev_priv(dev);
int i;

if (data & ETH_FLAG_LRO) {
if (!(pi->rx_offload & T3_RX_CSUM))
return -EINVAL;

pi->rx_offload |= T3_LRO;
for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++)
set_qset_lro(dev, i, 1);

} else {
pi->rx_offload &= ~T3_LRO;
for (i = pi->first_qset; i < pi->first_qset + pi->nqsets; i++)
set_qset_lro(dev, i, 0);
}

return 0;
}

static const struct ethtool_ops cxgb_ethtool_ops = {
.get_settings = get_settings,
.set_settings = set_settings,
Expand Down Expand Up @@ -1877,8 +1845,6 @@ static const struct ethtool_ops cxgb_ethtool_ops = {
.get_regs = get_regs,
.get_wol = get_wol,
.set_tso = ethtool_op_set_tso,
.get_flags = ethtool_op_get_flags,
.set_flags = cxgb3_set_flags,
};

static int in_range(int val, int lo, int hi)
Expand Down Expand Up @@ -2967,7 +2933,7 @@ static int __devinit init_one(struct pci_dev *pdev,
netdev->mem_end = mmio_start + mmio_len - 1;
netdev->features |= NETIF_F_SG | NETIF_F_IP_CSUM | NETIF_F_TSO;
netdev->features |= NETIF_F_LLTX;
netdev->features |= NETIF_F_LRO;
netdev->features |= NETIF_F_GRO;
if (pci_using_dac)
netdev->features |= NETIF_F_HIGHDMA;

Expand Down
119 changes: 16 additions & 103 deletions drivers/net/cxgb3/sge.c
Original file line number Diff line number Diff line change
Expand Up @@ -585,8 +585,7 @@ static void t3_reset_qset(struct sge_qset *q)
memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET);
q->txq_stopped = 0;
q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */
kfree(q->lro_frag_tbl);
q->lro_nfrags = q->lro_frag_len = 0;
q->lro_frag_tbl.nr_frags = q->lro_frag_tbl.len = 0;
}


Expand Down Expand Up @@ -1945,10 +1944,8 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
qs->port_stats[SGE_PSTAT_VLANEX]++;
if (likely(grp))
if (lro)
lro_vlan_hwaccel_receive_skb(&qs->lro_mgr, skb,
grp,
ntohs(p->vlan),
p);
vlan_gro_receive(&qs->napi, grp,
ntohs(p->vlan), skb);
else {
if (unlikely(pi->iscsi_ipv4addr &&
is_arp(skb))) {
Expand All @@ -1965,7 +1962,7 @@ static void rx_eth(struct adapter *adap, struct sge_rspq *rq,
dev_kfree_skb_any(skb);
} else if (rq->polling) {
if (lro)
lro_receive_skb(&qs->lro_mgr, skb, p);
napi_gro_receive(&qs->napi, skb);
else {
if (unlikely(pi->iscsi_ipv4addr && is_arp(skb)))
cxgb3_arp_process(adap, skb);
Expand All @@ -1980,59 +1977,6 @@ static inline int is_eth_tcp(u32 rss)
return G_HASHTYPE(ntohl(rss)) == RSS_HASH_4_TUPLE;
}

/**
* lro_frame_ok - check if an ingress packet is eligible for LRO
* @p: the CPL header of the packet
*
* Returns true if a received packet is eligible for LRO.
* The following conditions must be true:
* - packet is TCP/IP Ethernet II (checked elsewhere)
* - not an IP fragment
* - no IP options
* - TCP/IP checksums are correct
* - the packet is for this host
*/
static inline int lro_frame_ok(const struct cpl_rx_pkt *p)
{
const struct ethhdr *eh = (struct ethhdr *)(p + 1);
const struct iphdr *ih = (struct iphdr *)(eh + 1);

return (*((u8 *)p + 1) & 0x90) == 0x10 && p->csum == htons(0xffff) &&
eh->h_proto == htons(ETH_P_IP) && ih->ihl == (sizeof(*ih) >> 2);
}

static int t3_get_lro_header(void **eh, void **iph, void **tcph,
u64 *hdr_flags, void *priv)
{
const struct cpl_rx_pkt *cpl = priv;

if (!lro_frame_ok(cpl))
return -1;

*eh = (struct ethhdr *)(cpl + 1);
*iph = (struct iphdr *)((struct ethhdr *)*eh + 1);
*tcph = (struct tcphdr *)((struct iphdr *)*iph + 1);

*hdr_flags = LRO_IPV4 | LRO_TCP;
return 0;
}

static int t3_get_skb_header(struct sk_buff *skb,
void **iph, void **tcph, u64 *hdr_flags,
void *priv)
{
void *eh;

return t3_get_lro_header(&eh, iph, tcph, hdr_flags, priv);
}

static int t3_get_frag_header(struct skb_frag_struct *frag, void **eh,
void **iph, void **tcph, u64 *hdr_flags,
void *priv)
{
return t3_get_lro_header(eh, iph, tcph, hdr_flags, priv);
}

/**
* lro_add_page - add a page chunk to an LRO session
* @adap: the adapter
Expand All @@ -2049,8 +1993,9 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
{
struct rx_sw_desc *sd = &fl->sdesc[fl->cidx];
struct cpl_rx_pkt *cpl;
struct skb_frag_struct *rx_frag = qs->lro_frag_tbl;
int nr_frags = qs->lro_nfrags, frag_len = qs->lro_frag_len;
struct skb_frag_struct *rx_frag = qs->lro_frag_tbl.frags;
int nr_frags = qs->lro_frag_tbl.nr_frags;
int frag_len = qs->lro_frag_tbl.len;
int offset = 0;

if (!nr_frags) {
Expand All @@ -2069,13 +2014,13 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
rx_frag->page_offset = sd->pg_chunk.offset + offset;
rx_frag->size = len;
frag_len += len;
qs->lro_nfrags++;
qs->lro_frag_len = frag_len;
qs->lro_frag_tbl.nr_frags++;
qs->lro_frag_tbl.len = frag_len;

if (!complete)
return;

qs->lro_nfrags = qs->lro_frag_len = 0;
qs->lro_frag_tbl.ip_summed = CHECKSUM_UNNECESSARY;
cpl = qs->lro_va;

if (unlikely(cpl->vlan_valid)) {
Expand All @@ -2084,36 +2029,15 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
struct vlan_group *grp = pi->vlan_grp;

if (likely(grp != NULL)) {
lro_vlan_hwaccel_receive_frags(&qs->lro_mgr,
qs->lro_frag_tbl,
frag_len, frag_len,
grp, ntohs(cpl->vlan),
cpl, 0);
return;
vlan_gro_frags(&qs->napi, grp, ntohs(cpl->vlan),
&qs->lro_frag_tbl);
goto out;
}
}
lro_receive_frags(&qs->lro_mgr, qs->lro_frag_tbl,
frag_len, frag_len, cpl, 0);
}
napi_gro_frags(&qs->napi, &qs->lro_frag_tbl);

/**
* init_lro_mgr - initialize a LRO manager object
* @lro_mgr: the LRO manager object
*/
static void init_lro_mgr(struct sge_qset *qs, struct net_lro_mgr *lro_mgr)
{
lro_mgr->dev = qs->netdev;
lro_mgr->features = LRO_F_NAPI;
lro_mgr->frag_align_pad = NET_IP_ALIGN;
lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
lro_mgr->max_desc = T3_MAX_LRO_SES;
lro_mgr->lro_arr = qs->lro_desc;
lro_mgr->get_frag_header = t3_get_frag_header;
lro_mgr->get_skb_header = t3_get_skb_header;
lro_mgr->max_aggr = T3_MAX_LRO_MAX_PKTS;
if (lro_mgr->max_aggr > MAX_SKB_FRAGS)
lro_mgr->max_aggr = MAX_SKB_FRAGS;
out:
qs->lro_frag_tbl.nr_frags = qs->lro_frag_tbl.len = 0;
}

/**
Expand Down Expand Up @@ -2357,10 +2281,6 @@ static int process_responses(struct adapter *adap, struct sge_qset *qs,
}

deliver_partial_bundle(&adap->tdev, q, offload_skbs, ngathered);
lro_flush_all(&qs->lro_mgr);
qs->port_stats[SGE_PSTAT_LRO_AGGR] = qs->lro_mgr.stats.aggregated;
qs->port_stats[SGE_PSTAT_LRO_FLUSHED] = qs->lro_mgr.stats.flushed;
qs->port_stats[SGE_PSTAT_LRO_NO_DESC] = qs->lro_mgr.stats.no_desc;

if (sleeping)
check_ring_db(adap, qs, sleeping);
Expand Down Expand Up @@ -2907,7 +2827,6 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
{
int i, avail, ret = -ENOMEM;
struct sge_qset *q = &adapter->sge.qs[id];
struct net_lro_mgr *lro_mgr = &q->lro_mgr;

init_qset_cntxt(q, id);
setup_timer(&q->tx_reclaim_timer, sge_timer_cb, (unsigned long)q);
Expand Down Expand Up @@ -2987,10 +2906,6 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
q->fl[0].order = FL0_PG_ORDER;
q->fl[1].order = FL1_PG_ORDER;

q->lro_frag_tbl = kcalloc(MAX_FRAME_SIZE / FL1_PG_CHUNK_SIZE + 1,
sizeof(struct skb_frag_struct),
GFP_KERNEL);
q->lro_nfrags = q->lro_frag_len = 0;
spin_lock_irq(&adapter->sge.reg_lock);

/* FL threshold comparison uses < */
Expand Down Expand Up @@ -3042,8 +2957,6 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
q->tx_q = netdevq;
t3_update_qset_coalesce(q, p);

init_lro_mgr(q, lro_mgr);

avail = refill_fl(adapter, &q->fl[0], q->fl[0].size,
GFP_KERNEL | __GFP_COMP);
if (!avail) {
Expand Down
2 changes: 2 additions & 0 deletions drivers/scsi/cxgb3i/cxgb3i_ddp.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
#ifndef __CXGB3I_ULP2_DDP_H__
#define __CXGB3I_ULP2_DDP_H__

#include <linux/vmalloc.h>

/**
* struct cxgb3i_tag_format - cxgb3i ulp tag format for an iscsi entity
*
Expand Down

0 comments on commit 7be2df4

Please sign in to comment.