* [PATCH 0/3] chelsio driver changes
@ 2006-12-15 19:07 Stephen Hemminger
2006-12-15 19:07 ` [PATCH 1/3] chelsio: fix error path Stephen Hemminger
` (3 more replies)
0 siblings, 4 replies; 19+ messages in thread
From: Stephen Hemminger @ 2006-12-15 19:07 UTC (permalink / raw)
To: Jeff Garzik; +Cc: netdev
One error path bug fix, and a couple of changes to improve
receive performance. The performance is now up to 5+ Gbits/sec
which is about the limit of the memory/bus on the test systems.
^ permalink raw reply [flat|nested] 19+ messages in thread* [PATCH 1/3] chelsio: fix error path 2006-12-15 19:07 [PATCH 0/3] chelsio driver changes Stephen Hemminger @ 2006-12-15 19:07 ` Stephen Hemminger 2006-12-15 19:07 ` [PATCH 2/3] chelsio: NAPI speed improvement Stephen Hemminger ` (2 subsequent siblings) 3 siblings, 0 replies; 19+ messages in thread From: Stephen Hemminger @ 2006-12-15 19:07 UTC (permalink / raw) To: Jeff Garzik; +Cc: netdev [-- Attachment #1: chelsio-coverity.patch --] [-- Type: text/plain, Size: 625 bytes --] Fix handling of allocation failure. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> --- linux-2.6.20-rc1.orig/drivers/net/chelsio/my3126.c +++ linux-2.6.20-rc1/drivers/net/chelsio/my3126.c @@ -170,13 +170,14 @@ static struct cphy *my3126_phy_create(ad { struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); - if (cphy) - cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); + if (!cphy) + return NULL; + cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); cphy->bmsr = 0; - return (cphy); + return cphy; } /* Chip Reset */ -- ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 2/3] chelsio: NAPI speed improvement 2006-12-15 19:07 [PATCH 0/3] chelsio driver changes Stephen Hemminger 2006-12-15 19:07 ` [PATCH 1/3] chelsio: fix error path Stephen Hemminger @ 2006-12-15 19:07 ` Stephen Hemminger 2006-12-15 19:07 ` [PATCH 3/3] chelsio: more receive cleanup Stephen Hemminger 2006-12-26 21:16 ` [PATCH 0/3] chelsio driver changes Jeff Garzik 3 siblings, 0 replies; 19+ messages in thread From: Stephen Hemminger @ 2006-12-15 19:07 UTC (permalink / raw) To: Jeff Garzik; +Cc: netdev [-- Attachment #1: chelsio-napi2.patch --] [-- Type: text/plain, Size: 4598 bytes --] Speedup and cleanup the receive processing by eliminating the mmio read and a lock round trip. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> --- drivers/net/chelsio/sge.c | 82 ++++++++++++++++++++-------------------------- 1 file changed, 37 insertions(+), 45 deletions(-) --- linux-2.6.20-rc1.orig/drivers/net/chelsio/sge.c +++ linux-2.6.20-rc1/drivers/net/chelsio/sge.c @@ -1576,6 +1576,14 @@ static int process_responses(struct adap return budget; } +static inline int responses_pending(const struct adapter *adapter) +{ + const struct respQ *Q = &adapter->sge->respQ; + const struct respQ_e *e = &Q->entries[Q->cidx]; + + return (e->GenerationBit == Q->genbit); +} + #ifdef CONFIG_CHELSIO_T1_NAPI /* * A simpler version of process_responses() that handles only pure (i.e., @@ -1585,13 +1593,16 @@ static int process_responses(struct adap * which the caller must ensure is a valid pure response. Returns 1 if it * encounters a valid data-carrying response, 0 otherwise. */ -static int process_pure_responses(struct adapter *adapter, struct respQ_e *e) +static int process_pure_responses(struct adapter *adapter) { struct sge *sge = adapter->sge; struct respQ *q = &sge->respQ; + struct respQ_e *e = &q->entries[q->cidx]; unsigned int flags = 0; unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; + if (e->DataValid) + return 1; do { flags |= e->Qsleeping; @@ -1627,22 +1638,17 @@ static int process_pure_responses(struct int t1_poll(struct net_device *dev, int *budget) { struct adapter *adapter = dev->priv; - int effective_budget = min(*budget, dev->quota); - int work_done = process_responses(adapter, effective_budget); + int work_done; + work_done = process_responses(adapter, min(*budget, dev->quota)); *budget -= work_done; dev->quota -= work_done; - if (work_done >= effective_budget) + if (unlikely(responses_pending(adapter))) return 1; - spin_lock_irq(&adapter->async_lock); - __netif_rx_complete(dev); + netif_rx_complete(dev); writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); - writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA, - adapter->regs + A_PL_ENABLE); - spin_unlock_irq(&adapter->async_lock); - return 0; } @@ -1652,44 +1658,34 @@ int t1_poll(struct net_device *dev, int irqreturn_t t1_interrupt(int irq, void *data) { struct adapter *adapter = data; - struct net_device *dev = adapter->sge->netdev; struct sge *sge = adapter->sge; - u32 cause; - int handled = 0; + int handled; - cause = readl(adapter->regs + A_PL_CAUSE); - if (cause == 0 || cause == ~0) - return IRQ_NONE; + if (likely(responses_pending(adapter))) { + struct net_device *dev = sge->netdev; - spin_lock(&adapter->async_lock); - if (cause & F_PL_INTR_SGE_DATA) { - struct respQ *q = &adapter->sge->respQ; - struct respQ_e *e = &q->entries[q->cidx]; - - handled = 1; - writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - - if (e->GenerationBit == q->genbit && - __netif_rx_schedule_prep(dev)) { - if (e->DataValid || process_pure_responses(adapter, e)) { - /* mask off data IRQ */ - writel(adapter->slow_intr_mask, - adapter->regs + A_PL_ENABLE); - __netif_rx_schedule(sge->netdev); - goto unlock; - } - /* no data, no NAPI needed */ - netif_poll_enable(dev); + writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); + if (__netif_rx_schedule_prep(dev)) { + if (process_pure_responses(adapter)) { + __netif_rx_schedule(dev); + } else { + /* no data, no NAPI needed */ + writel(sge->respQ.cidx, + adapter->regs + A_SG_SLEEPING); + netif_poll_enable(dev); /* undo schedule_prep */ + } } - writel(q->cidx, adapter->regs + A_SG_SLEEPING); - } else - handled = t1_slow_intr_handler(adapter); + return IRQ_HANDLED; + } + + spin_lock(&adapter->async_lock); + handled = t1_slow_intr_handler(adapter); + spin_unlock(&adapter->async_lock); if (!handled) sge->stats.unhandled_irqs++; -unlock: - spin_unlock(&adapter->async_lock); + return IRQ_RETVAL(handled != 0); } @@ -1712,17 +1708,13 @@ unlock: irqreturn_t t1_interrupt(int irq, void *cookie) { int work_done; - struct respQ_e *e; struct adapter *adapter = cookie; - struct respQ *Q = &adapter->sge->respQ; spin_lock(&adapter->async_lock); - e = &Q->entries[Q->cidx]; - prefetch(e); writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - if (likely(e->GenerationBit == Q->genbit)) + if (likely(responses_pending(adapter)) work_done = process_responses(adapter, -1); else work_done = t1_slow_intr_handler(adapter); -- ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 3/3] chelsio: more receive cleanup 2006-12-15 19:07 [PATCH 0/3] chelsio driver changes Stephen Hemminger 2006-12-15 19:07 ` [PATCH 1/3] chelsio: fix error path Stephen Hemminger 2006-12-15 19:07 ` [PATCH 2/3] chelsio: NAPI speed improvement Stephen Hemminger @ 2006-12-15 19:07 ` Stephen Hemminger 2006-12-15 20:10 ` Francois Romieu 2006-12-26 21:16 ` [PATCH 0/3] chelsio driver changes Jeff Garzik 3 siblings, 1 reply; 19+ messages in thread From: Stephen Hemminger @ 2006-12-15 19:07 UTC (permalink / raw) To: Jeff Garzik; +Cc: netdev [-- Attachment #1: chelsio-prefetch --] [-- Type: text/plain, Size: 6939 bytes --] Cleanup receive processing some more: * do the reserve padding of skb during setup * don't pass constants to get_packet * do smart prefetch of skb * make copybreak a module parameter Signed-off-by: Stephen Hemminger <shemminger@osdl.org> --- drivers/net/chelsio/sge.c | 81 +++++++++++++++++++++++----------------------- 1 file changed, 42 insertions(+), 39 deletions(-) --- linux-2.6.20-rc1.orig/drivers/net/chelsio/sge.c +++ linux-2.6.20-rc1/drivers/net/chelsio/sge.c @@ -71,12 +71,9 @@ #define SGE_FREEL_REFILL_THRESH 16 #define SGE_RESPQ_E_N 1024 #define SGE_INTRTIMER_NRES 1000 -#define SGE_RX_COPY_THRES 256 #define SGE_RX_SM_BUF_SIZE 1536 #define SGE_TX_DESC_MAX_PLEN 16384 -# define SGE_RX_DROP_THRES 2 - #define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4) /* @@ -862,6 +859,8 @@ static void refill_free_list(struct sge skb_reserve(skb, q->dma_offset); mapping = pci_map_single(pdev, skb->data, dma_len, PCI_DMA_FROMDEVICE); + skb_reserve(skb, sge->rx_pkt_pad); + ce->skb = skb; pci_unmap_addr_set(ce, dma_addr, mapping); pci_unmap_len_set(ce, dma_len, dma_len); @@ -1041,6 +1040,10 @@ static void recycle_fl_buf(struct freelQ } } +static int copybreak __read_mostly = 256; +module_param(copybreak, int, 0); +MODULE_PARM_DESC(copybreak, "Receive copy threshold"); + /** * get_packet - return the next ingress packet buffer * @pdev: the PCI device that received the packet @@ -1059,37 +1062,33 @@ static void recycle_fl_buf(struct freelQ * threshold and the packet is too big to copy, or (b) the packet should * be copied but there is no memory for the copy. */ -static inline struct sk_buff *get_packet(struct pci_dev *pdev, - struct freelQ *fl, unsigned int len, - int dma_pad, int skb_pad, - unsigned int copy_thres, - unsigned int drop_thres) +static inline struct sk_buff *get_packet(struct pci_dev *pdev, struct freelQ *fl, + unsigned int len) { struct sk_buff *skb; - struct freelQ_ce *ce = &fl->centries[fl->cidx]; + const struct freelQ_ce *ce = &fl->centries[fl->cidx]; + + if (len < copybreak) { + skb = alloc_skb(len + 2, GFP_ATOMIC); + if (!skb) + goto use_orig_buf; - if (len < copy_thres) { - skb = alloc_skb(len + skb_pad, GFP_ATOMIC); - if (likely(skb != NULL)) { - skb_reserve(skb, skb_pad); - skb_put(skb, len); - pci_dma_sync_single_for_cpu(pdev, + skb_reserve(skb, 2); /* align IP header */ + skb_put(skb, len); + pci_dma_sync_single_for_cpu(pdev, pci_unmap_addr(ce, dma_addr), pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); - memcpy(skb->data, ce->skb->data + dma_pad, len); - pci_dma_sync_single_for_device(pdev, + memcpy(skb->data, ce->skb->data, len); + pci_dma_sync_single_for_device(pdev, pci_unmap_addr(ce, dma_addr), pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); - } else if (!drop_thres) - goto use_orig_buf; - recycle_fl_buf(fl, fl->cidx); return skb; } - if (fl->credits < drop_thres) { + if (fl->credits < 2) { recycle_fl_buf(fl, fl->cidx); return NULL; } @@ -1098,7 +1097,8 @@ use_orig_buf: pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr), pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); skb = ce->skb; - skb_reserve(skb, dma_pad); + prefetch(skb->data); + skb_put(skb, len); return skb; } @@ -1375,27 +1375,25 @@ static void restart_sched(unsigned long * * Process an ingress ethernet pakcet and deliver it to the stack. */ -static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) +static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) { struct sk_buff *skb; - struct cpl_rx_pkt *p; + const struct cpl_rx_pkt *p; struct adapter *adapter = sge->adapter; struct sge_port_stats *st; - skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad, - sge->rx_pkt_pad, 2, SGE_RX_COPY_THRES, - SGE_RX_DROP_THRES); + skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad); if (unlikely(!skb)) { sge->stats.rx_drops++; - return 0; + return; } - p = (struct cpl_rx_pkt *)skb->data; - skb_pull(skb, sizeof(*p)); + p = (const struct cpl_rx_pkt *) skb->data; if (p->iff >= adapter->params.nports) { kfree_skb(skb); - return 0; + return; } + __skb_pull(skb, sizeof(*p)); skb->dev = adapter->port[p->iff].dev; skb->dev->last_rx = jiffies; @@ -1427,7 +1425,6 @@ static int sge_rx(struct sge *sge, struc netif_rx(skb); #endif } - return 0; } /* @@ -1510,12 +1507,11 @@ static int process_responses(struct adap struct sge *sge = adapter->sge; struct respQ *q = &sge->respQ; struct respQ_e *e = &q->entries[q->cidx]; - int budget_left = budget; + int done = 0; unsigned int flags = 0; unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; - - while (likely(budget_left && e->GenerationBit == q->genbit)) { + while (done < budget && e->GenerationBit == q->genbit) { flags |= e->Qsleeping; cmdq_processed[0] += e->Cmdq0CreditReturn; @@ -1525,14 +1521,16 @@ static int process_responses(struct adap * ping-pong of TX state information on MP where the sender * might run on a different CPU than this function... */ - if (unlikely(flags & F_CMDQ0_ENABLE || cmdq_processed[0] > 64)) { + if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) { flags = update_tx_info(adapter, flags, cmdq_processed[0]); cmdq_processed[0] = 0; } + if (unlikely(cmdq_processed[1] > 16)) { sge->cmdQ[1].processed += cmdq_processed[1]; cmdq_processed[1] = 0; } + if (likely(e->DataValid)) { struct freelQ *fl = &sge->freelQ[e->FreelistQid]; @@ -1542,12 +1540,16 @@ static int process_responses(struct adap else sge_rx(sge, fl, e->BufferLength); + ++done; + /* * Note: this depends on each packet consuming a * single free-list buffer; cf. the BUG above. */ if (++fl->cidx == fl->size) fl->cidx = 0; + prefetch(fl->centries[fl->cidx].skb); + if (unlikely(--fl->credits < fl->size - SGE_FREEL_REFILL_THRESH)) refill_free_list(sge, fl); @@ -1566,14 +1568,12 @@ static int process_responses(struct adap writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT); q->credits = 0; } - --budget_left; } flags = update_tx_info(adapter, flags, cmdq_processed[0]); sge->cmdQ[1].processed += cmdq_processed[1]; - budget -= budget_left; - return budget; + return done; } static inline int responses_pending(const struct adapter *adapter) @@ -1598,11 +1598,14 @@ static int process_pure_responses(struct struct sge *sge = adapter->sge; struct respQ *q = &sge->respQ; struct respQ_e *e = &q->entries[q->cidx]; + const struct freelQ *fl = &sge->freelQ[e->FreelistQid]; unsigned int flags = 0; unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; + prefetch(fl->centries[fl->cidx].skb); if (e->DataValid) return 1; + do { flags |= e->Qsleeping; -- ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] chelsio: more receive cleanup 2006-12-15 19:07 ` [PATCH 3/3] chelsio: more receive cleanup Stephen Hemminger @ 2006-12-15 20:10 ` Francois Romieu 2006-12-15 22:55 ` Stephen Hemminger 0 siblings, 1 reply; 19+ messages in thread From: Francois Romieu @ 2006-12-15 20:10 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Jeff Garzik, netdev Stephen Hemminger <shemminger@osdl.org> : [...] > --- linux-2.6.20-rc1.orig/drivers/net/chelsio/sge.c > +++ linux-2.6.20-rc1/drivers/net/chelsio/sge.c [...] > @@ -1059,37 +1062,33 @@ static void recycle_fl_buf(struct freelQ > * threshold and the packet is too big to copy, or (b) the packet should > * be copied but there is no memory for the copy. > */ > -static inline struct sk_buff *get_packet(struct pci_dev *pdev, > - struct freelQ *fl, unsigned int len, > - int dma_pad, int skb_pad, > - unsigned int copy_thres, > - unsigned int drop_thres) > +static inline struct sk_buff *get_packet(struct pci_dev *pdev, struct freelQ *fl, > + unsigned int len) > { > struct sk_buff *skb; > - struct freelQ_ce *ce = &fl->centries[fl->cidx]; > + const struct freelQ_ce *ce = &fl->centries[fl->cidx]; > + > + if (len < copybreak) { If you are into cleanups, maybe add likely/unlikely (and remove the inline) ? > + skb = alloc_skb(len + 2, GFP_ATOMIC); > + if (!skb) > + goto use_orig_buf; > > - if (len < copy_thres) { > - skb = alloc_skb(len + skb_pad, GFP_ATOMIC); > - if (likely(skb != NULL)) { > - skb_reserve(skb, skb_pad); > - skb_put(skb, len); > - pci_dma_sync_single_for_cpu(pdev, > + skb_reserve(skb, 2); /* align IP header */ s/2/NET_IP_ALIGN/ Btw, since the driver supports netpoll, its blind enabling of interrupts in t1_poll() seems old-fashoined (see thread starting at http://lkml.org/lkml/2006/12/12/86) -- Ueimor ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] chelsio: more receive cleanup 2006-12-15 20:10 ` Francois Romieu @ 2006-12-15 22:55 ` Stephen Hemminger 2006-12-16 0:26 ` Francois Romieu 0 siblings, 1 reply; 19+ messages in thread From: Stephen Hemminger @ 2006-12-15 22:55 UTC (permalink / raw) To: Francois Romieu; +Cc: Jeff Garzik, netdev On Fri, 15 Dec 2006 21:10:19 +0100 Francois Romieu <romieu@fr.zoreil.com> wrote: > Stephen Hemminger <shemminger@osdl.org> : > [...] > > --- linux-2.6.20-rc1.orig/drivers/net/chelsio/sge.c > > +++ linux-2.6.20-rc1/drivers/net/chelsio/sge.c > [...] > > @@ -1059,37 +1062,33 @@ static void recycle_fl_buf(struct freelQ > > * threshold and the packet is too big to copy, or (b) the packet should > > * be copied but there is no memory for the copy. > > */ > > -static inline struct sk_buff *get_packet(struct pci_dev *pdev, > > - struct freelQ *fl, unsigned int len, > > - int dma_pad, int skb_pad, > > - unsigned int copy_thres, > > - unsigned int drop_thres) > > +static inline struct sk_buff *get_packet(struct pci_dev *pdev, struct freelQ *fl, > > + unsigned int len) > > { > > struct sk_buff *skb; > > - struct freelQ_ce *ce = &fl->centries[fl->cidx]; > > + const struct freelQ_ce *ce = &fl->centries[fl->cidx]; > > + > > + if (len < copybreak) { > > If you are into cleanups, maybe add likely/unlikely (and remove the inline) ? Why, you can't predict copybreak on off > > > + skb = alloc_skb(len + 2, GFP_ATOMIC); > > + if (!skb) > > + goto use_orig_buf; > > > > - if (len < copy_thres) { > > - skb = alloc_skb(len + skb_pad, GFP_ATOMIC); > > - if (likely(skb != NULL)) { > > - skb_reserve(skb, skb_pad); > > - skb_put(skb, len); > > - pci_dma_sync_single_for_cpu(pdev, > > + skb_reserve(skb, 2); /* align IP header */ > > s/2/NET_IP_ALIGN/ This is wrong, NET_IP_ALIGN is for DMA buffers only. It is defined as 0 for those platforms where DMA alignment is important. In this case we are copying, so we want to force 2. > Btw, since the driver supports netpoll, its blind enabling of interrupts > in t1_poll() seems old-fashoined (see thread starting at > http://lkml.org/lkml/2006/12/12/86) > -- Stephen Hemminger <shemminger@osdl.org> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] chelsio: more receive cleanup 2006-12-15 22:55 ` Stephen Hemminger @ 2006-12-16 0:26 ` Francois Romieu 2006-12-16 1:28 ` Stephen Hemminger 0 siblings, 1 reply; 19+ messages in thread From: Francois Romieu @ 2006-12-16 0:26 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Jeff Garzik, netdev Stephen Hemminger <shemminger@osdl.org> : > Francois Romieu <romieu@fr.zoreil.com> wrote: [...] > Why, you can't predict copybreak on off Plain gut feeling. I'd rather spend extra cycles on small packets (whose allocation is already optimized) and keep the normal packets less expensive on a 10Gb/s network card. [...] > This is wrong, NET_IP_ALIGN is for DMA buffers only. It is defined > as 0 for those platforms where DMA alignment is important. In this > case we are copying, so we want to force 2. Ok, ok. -- Ueimor ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] chelsio: more receive cleanup 2006-12-16 0:26 ` Francois Romieu @ 2006-12-16 1:28 ` Stephen Hemminger 0 siblings, 0 replies; 19+ messages in thread From: Stephen Hemminger @ 2006-12-16 1:28 UTC (permalink / raw) To: Francois Romieu; +Cc: Jeff Garzik, netdev On Sat, 16 Dec 2006 01:26:04 +0100 Francois Romieu <romieu@fr.zoreil.com> wrote: > Stephen Hemminger <shemminger@osdl.org> : > > Francois Romieu <romieu@fr.zoreil.com> wrote: > [...] > > Why, you can't predict copybreak on off > > Plain gut feeling. I'd rather spend extra cycles on small packets (whose > allocation is already optimized) and keep the normal packets less expensive > on a 10Gb/s network card. > Likely/unlikely is an optimization that doesn't make a big difference and I would rather the compiler choose unless it is something obvious like an error path or external interrupt (like PHY). There was some discussion on LKML, which I mostly forgot, that hinted that on some architectures using likely/unlikely incorrectly could have a major hit. -- Stephen Hemminger <shemminger@osdl.org> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 0/3] chelsio driver changes 2006-12-15 19:07 [PATCH 0/3] chelsio driver changes Stephen Hemminger ` (2 preceding siblings ...) 2006-12-15 19:07 ` [PATCH 3/3] chelsio: more receive cleanup Stephen Hemminger @ 2006-12-26 21:16 ` Jeff Garzik 2007-01-08 19:24 ` [PATCH 1/3] chelsio: error path fix Stephen Hemminger 3 siblings, 1 reply; 19+ messages in thread From: Jeff Garzik @ 2006-12-26 21:16 UTC (permalink / raw) To: Stephen Hemminger; +Cc: netdev Stephen Hemminger wrote: > One error path bug fix, and a couple of changes to improve > receive performance. The performance is now up to 5+ Gbits/sec > which is about the limit of the memory/bus on the test systems. I request a rediff+resend against netdev-2.6.git#upstream, giving sufficient time [hours :(] for it to mirror out. Jeff ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 1/3] chelsio: error path fix 2006-12-26 21:16 ` [PATCH 0/3] chelsio driver changes Jeff Garzik @ 2007-01-08 19:24 ` Stephen Hemminger [not found] ` <20070108112524.730e89f0@dxpl.pdx.osdl.net> 2007-01-08 19:26 ` [PATCH 2/3] chelsio: NAPI speed improvement Stephen Hemminger 0 siblings, 2 replies; 19+ messages in thread From: Stephen Hemminger @ 2007-01-08 19:24 UTC (permalink / raw) To: Jeff Garzik; +Cc: netdev Fix handling of allocation failure. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> --- netdev-2.6.orig/drivers/net/chelsio/my3126.c +++ netdev-2.6/drivers/net/chelsio/my3126.c @@ -170,9 +170,10 @@ static struct cphy *my3126_phy_create(ad { struct cphy *cphy = kzalloc(sizeof (*cphy), GFP_KERNEL); - if (cphy) - cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); + if (!cphy) + return NULL; + cphy_init(cphy, adapter, phy_addr, &my3126_ops, mdio_ops); INIT_DELAYED_WORK(&cphy->phy_update, my3216_poll); cphy->bmsr = 0; ^ permalink raw reply [flat|nested] 19+ messages in thread
[parent not found: <20070108112524.730e89f0@dxpl.pdx.osdl.net>]
* [PATCH 3/3] chelsio: more rx speedup [not found] ` <20070108112524.730e89f0@dxpl.pdx.osdl.net> @ 2007-01-08 19:26 ` Stephen Hemminger 2007-01-09 8:42 ` Ingo Oeser 2007-01-19 3:05 ` Jeff Garzik 0 siblings, 2 replies; 19+ messages in thread From: Stephen Hemminger @ 2007-01-08 19:26 UTC (permalink / raw) To: Jeff Garzik; +Cc: netdev Cleanup receive processing some more: * do the reserve padding of skb during setup * don't pass constants to get_packet * do smart prefetch of skb * make copybreak a module parameter Signed-off-by: Stephen Hemminger <shemminger@osdl.org> --- drivers/net/chelsio/sge.c | 87 +++++++++++++++++++++++----------------------- 1 file changed, 45 insertions(+), 42 deletions(-) --- netdev-2.6.orig/drivers/net/chelsio/sge.c +++ netdev-2.6/drivers/net/chelsio/sge.c @@ -71,12 +71,9 @@ #define SGE_FREEL_REFILL_THRESH 16 #define SGE_RESPQ_E_N 1024 #define SGE_INTRTIMER_NRES 1000 -#define SGE_RX_COPY_THRES 256 #define SGE_RX_SM_BUF_SIZE 1536 #define SGE_TX_DESC_MAX_PLEN 16384 -# define SGE_RX_DROP_THRES 2 - #define SGE_RESPQ_REPLENISH_THRES (SGE_RESPQ_E_N / 4) /* @@ -846,6 +843,8 @@ static void refill_free_list(struct sge skb_reserve(skb, q->dma_offset); mapping = pci_map_single(pdev, skb->data, dma_len, PCI_DMA_FROMDEVICE); + skb_reserve(skb, sge->rx_pkt_pad); + ce->skb = skb; pci_unmap_addr_set(ce, dma_addr, mapping); pci_unmap_len_set(ce, dma_len, dma_len); @@ -1024,6 +1023,10 @@ static void recycle_fl_buf(struct freelQ } } +static int copybreak __read_mostly = 256; +module_param(copybreak, int, 0); +MODULE_PARM_DESC(copybreak, "Receive copy threshold"); + /** * get_packet - return the next ingress packet buffer * @pdev: the PCI device that received the packet @@ -1043,45 +1046,42 @@ static void recycle_fl_buf(struct freelQ * be copied but there is no memory for the copy. */ static inline struct sk_buff *get_packet(struct pci_dev *pdev, - struct freelQ *fl, unsigned int len, - int dma_pad, int skb_pad, - unsigned int copy_thres, - unsigned int drop_thres) + struct freelQ *fl, unsigned int len) { struct sk_buff *skb; - struct freelQ_ce *ce = &fl->centries[fl->cidx]; + const struct freelQ_ce *ce = &fl->centries[fl->cidx]; - if (len < copy_thres) { - skb = alloc_skb(len + skb_pad, GFP_ATOMIC); - if (likely(skb != NULL)) { - skb_reserve(skb, skb_pad); - skb_put(skb, len); - pci_dma_sync_single_for_cpu(pdev, - pci_unmap_addr(ce, dma_addr), - pci_unmap_len(ce, dma_len), - PCI_DMA_FROMDEVICE); - memcpy(skb->data, ce->skb->data + dma_pad, len); - pci_dma_sync_single_for_device(pdev, + if (len < copybreak) { + skb = alloc_skb(len + 2, GFP_ATOMIC); + if (!skb) + goto use_orig_buf; + + skb_reserve(skb, 2); /* align IP header */ + skb_put(skb, len); + pci_dma_sync_single_for_cpu(pdev, pci_unmap_addr(ce, dma_addr), pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); - } else if (!drop_thres) - goto use_orig_buf; - + memcpy(skb->data, ce->skb->data, len); + pci_dma_sync_single_for_device(pdev, + pci_unmap_addr(ce, dma_addr), + pci_unmap_len(ce, dma_len), + PCI_DMA_FROMDEVICE); recycle_fl_buf(fl, fl->cidx); return skb; } - if (fl->credits < drop_thres) { +use_orig_buf: + if (fl->credits < 2) { recycle_fl_buf(fl, fl->cidx); return NULL; } -use_orig_buf: pci_unmap_single(pdev, pci_unmap_addr(ce, dma_addr), pci_unmap_len(ce, dma_len), PCI_DMA_FROMDEVICE); skb = ce->skb; - skb_reserve(skb, dma_pad); + prefetch(skb->data); + skb_put(skb, len); return skb; } @@ -1359,27 +1359,25 @@ static void restart_sched(unsigned long * * Process an ingress ethernet pakcet and deliver it to the stack. */ -static int sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) +static void sge_rx(struct sge *sge, struct freelQ *fl, unsigned int len) { struct sk_buff *skb; - struct cpl_rx_pkt *p; + const struct cpl_rx_pkt *p; struct adapter *adapter = sge->adapter; struct sge_port_stats *st; - skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad, - sge->rx_pkt_pad, 2, SGE_RX_COPY_THRES, - SGE_RX_DROP_THRES); + skb = get_packet(adapter->pdev, fl, len - sge->rx_pkt_pad); if (unlikely(!skb)) { sge->stats.rx_drops++; - return 0; + return; } - p = (struct cpl_rx_pkt *)skb->data; - skb_pull(skb, sizeof(*p)); + p = (const struct cpl_rx_pkt *) skb->data; if (p->iff >= adapter->params.nports) { kfree_skb(skb); - return 0; + return; } + __skb_pull(skb, sizeof(*p)); skb->dev = adapter->port[p->iff].dev; skb->dev->last_rx = jiffies; @@ -1411,7 +1409,6 @@ static int sge_rx(struct sge *sge, struc netif_rx(skb); #endif } - return 0; } /* @@ -1493,12 +1490,11 @@ static int process_responses(struct adap struct sge *sge = adapter->sge; struct respQ *q = &sge->respQ; struct respQ_e *e = &q->entries[q->cidx]; - int budget_left = budget; + int done = 0; unsigned int flags = 0; unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; - - while (likely(budget_left && e->GenerationBit == q->genbit)) { + while (done < budget && e->GenerationBit == q->genbit) { flags |= e->Qsleeping; cmdq_processed[0] += e->Cmdq0CreditReturn; @@ -1508,14 +1504,16 @@ static int process_responses(struct adap * ping-pong of TX state information on MP where the sender * might run on a different CPU than this function... */ - if (unlikely(flags & F_CMDQ0_ENABLE || cmdq_processed[0] > 64)) { + if (unlikely((flags & F_CMDQ0_ENABLE) || cmdq_processed[0] > 64)) { flags = update_tx_info(adapter, flags, cmdq_processed[0]); cmdq_processed[0] = 0; } + if (unlikely(cmdq_processed[1] > 16)) { sge->cmdQ[1].processed += cmdq_processed[1]; cmdq_processed[1] = 0; } + if (likely(e->DataValid)) { struct freelQ *fl = &sge->freelQ[e->FreelistQid]; @@ -1525,12 +1523,16 @@ static int process_responses(struct adap else sge_rx(sge, fl, e->BufferLength); + ++done; + /* * Note: this depends on each packet consuming a * single free-list buffer; cf. the BUG above. */ if (++fl->cidx == fl->size) fl->cidx = 0; + prefetch(fl->centries[fl->cidx].skb); + if (unlikely(--fl->credits < fl->size - SGE_FREEL_REFILL_THRESH)) refill_free_list(sge, fl); @@ -1549,14 +1551,12 @@ static int process_responses(struct adap writel(q->credits, adapter->regs + A_SG_RSPQUEUECREDIT); q->credits = 0; } - --budget_left; } flags = update_tx_info(adapter, flags, cmdq_processed[0]); sge->cmdQ[1].processed += cmdq_processed[1]; - budget -= budget_left; - return budget; + return done; } static inline int responses_pending(const struct adapter *adapter) @@ -1581,11 +1581,14 @@ static int process_pure_responses(struct struct sge *sge = adapter->sge; struct respQ *q = &sge->respQ; struct respQ_e *e = &q->entries[q->cidx]; + const struct freelQ *fl = &sge->freelQ[e->FreelistQid]; unsigned int flags = 0; unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; + prefetch(fl->centries[fl->cidx].skb); if (e->DataValid) return 1; + do { flags |= e->Qsleeping; ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] chelsio: more rx speedup 2007-01-08 19:26 ` [PATCH 3/3] chelsio: more rx speedup Stephen Hemminger @ 2007-01-09 8:42 ` Ingo Oeser 2007-01-09 18:26 ` Stephen Hemminger 2007-01-19 3:05 ` Jeff Garzik 1 sibling, 1 reply; 19+ messages in thread From: Ingo Oeser @ 2007-01-09 8:42 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Jeff Garzik, netdev Hi Stephen, Stephen Hemminger schrieb: > --- netdev-2.6.orig/drivers/net/chelsio/sge.c > +++ netdev-2.6/drivers/net/chelsio/sge.c [...] > @@ -1043,45 +1046,42 @@ static void recycle_fl_buf(struct freelQ > * be copied but there is no memory for the copy. > */ > static inline struct sk_buff *get_packet(struct pci_dev *pdev, > - struct freelQ *fl, unsigned int len, > - int dma_pad, int skb_pad, > - unsigned int copy_thres, > - unsigned int drop_thres) > + struct freelQ *fl, unsigned int len) > { > struct sk_buff *skb; > - struct freelQ_ce *ce = &fl->centries[fl->cidx]; > + const struct freelQ_ce *ce = &fl->centries[fl->cidx]; > > - if (len < copy_thres) { > - skb = alloc_skb(len + skb_pad, GFP_ATOMIC); > - if (likely(skb != NULL)) { > - skb_reserve(skb, skb_pad); > - skb_put(skb, len); > - pci_dma_sync_single_for_cpu(pdev, > - pci_unmap_addr(ce, dma_addr), > - pci_unmap_len(ce, dma_len), > - PCI_DMA_FROMDEVICE); > - memcpy(skb->data, ce->skb->data + dma_pad, len); > - pci_dma_sync_single_for_device(pdev, > + if (len < copybreak) { > + skb = alloc_skb(len + 2, GFP_ATOMIC); > + if (!skb) > + goto use_orig_buf; > + > + skb_reserve(skb, 2); /* align IP header */ Please use NET_IP_ALIGN here: + skb = alloc_skb(len + NET_IP_ALIGN, GFP_ATOMIC); + if (!skb) + goto use_orig_buf; + + skb_reserve(skb, NET_IP_ALIGN); > + skb_put(skb, len); > + pci_dma_sync_single_for_cpu(pdev, > pci_unmap_addr(ce, dma_addr), > pci_unmap_len(ce, dma_len), > PCI_DMA_FROMDEVICE); > - } else if (!drop_thres) > - goto use_orig_buf; > - > + memcpy(skb->data, ce->skb->data, len); > + pci_dma_sync_single_for_device(pdev, > + pci_unmap_addr(ce, dma_addr), > + pci_unmap_len(ce, dma_len), > + PCI_DMA_FROMDEVICE); > recycle_fl_buf(fl, fl->cidx); > return skb; > } > > - if (fl->credits < drop_thres) { > +use_orig_buf: > + if (fl->credits < 2) { Why 2? What does this magic number mean? Regards Ingo Oeser ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] chelsio: more rx speedup 2007-01-09 8:42 ` Ingo Oeser @ 2007-01-09 18:26 ` Stephen Hemminger 2007-01-10 2:08 ` Divy Le Ray 2007-01-10 8:30 ` Ingo Oeser 0 siblings, 2 replies; 19+ messages in thread From: Stephen Hemminger @ 2007-01-09 18:26 UTC (permalink / raw) To: Ingo Oeser; +Cc: Jeff Garzik, netdev On Tue, 9 Jan 2007 09:42:03 +0100 Ingo Oeser <netdev@axxeo.de> wrote: > Hi Stephen, > > Stephen Hemminger schrieb: > > --- netdev-2.6.orig/drivers/net/chelsio/sge.c > > +++ netdev-2.6/drivers/net/chelsio/sge.c > [...] > > @@ -1043,45 +1046,42 @@ static void recycle_fl_buf(struct freelQ > > * be copied but there is no memory for the copy. > > */ > > static inline struct sk_buff *get_packet(struct pci_dev *pdev, > > - struct freelQ *fl, unsigned int len, > > - int dma_pad, int skb_pad, > > - unsigned int copy_thres, > > - unsigned int drop_thres) > > + struct freelQ *fl, unsigned int len) > > { > > struct sk_buff *skb; > > - struct freelQ_ce *ce = &fl->centries[fl->cidx]; > > + const struct freelQ_ce *ce = &fl->centries[fl->cidx]; > > > > - if (len < copy_thres) { > > - skb = alloc_skb(len + skb_pad, GFP_ATOMIC); > > - if (likely(skb != NULL)) { > > - skb_reserve(skb, skb_pad); > > - skb_put(skb, len); > > - pci_dma_sync_single_for_cpu(pdev, > > - pci_unmap_addr(ce, dma_addr), > > - pci_unmap_len(ce, dma_len), > > - PCI_DMA_FROMDEVICE); > > - memcpy(skb->data, ce->skb->data + dma_pad, len); > > - pci_dma_sync_single_for_device(pdev, > > + if (len < copybreak) { > > + skb = alloc_skb(len + 2, GFP_ATOMIC); > > + if (!skb) > > + goto use_orig_buf; > > + > > + skb_reserve(skb, 2); /* align IP header */ > > Please use NET_IP_ALIGN here: Wrong, NET_IP_ALIGN is intended to deal with platforms where alignment of DMA is more important of alignment of structures. Therefore if data is copied, it should always be 2. > > + skb = alloc_skb(len + NET_IP_ALIGN, GFP_ATOMIC); > + if (!skb) > + goto use_orig_buf; > + > + skb_reserve(skb, NET_IP_ALIGN); > > > + skb_put(skb, len); > > + pci_dma_sync_single_for_cpu(pdev, > > pci_unmap_addr(ce, dma_addr), > > pci_unmap_len(ce, dma_len), > > PCI_DMA_FROMDEVICE); > > - } else if (!drop_thres) > > - goto use_orig_buf; > > - > > + memcpy(skb->data, ce->skb->data, len); > > + pci_dma_sync_single_for_device(pdev, > > + pci_unmap_addr(ce, dma_addr), > > + pci_unmap_len(ce, dma_len), > > + PCI_DMA_FROMDEVICE); > > recycle_fl_buf(fl, fl->cidx); > > return skb; > > } > > > > - if (fl->credits < drop_thres) { > > +use_orig_buf: > > + if (fl->credits < 2) { > > Why 2? What does this magic number mean? No idea, it was there in the original. (as a parameter). -- Stephen Hemminger <shemminger@osdl.org> ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] chelsio: more rx speedup 2007-01-09 18:26 ` Stephen Hemminger @ 2007-01-10 2:08 ` Divy Le Ray 2007-01-10 8:34 ` Ingo Oeser 2007-01-10 8:30 ` Ingo Oeser 1 sibling, 1 reply; 19+ messages in thread From: Divy Le Ray @ 2007-01-10 2:08 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Ingo Oeser, Jeff Garzik, netdev Stephen Hemminger wrote: > On Tue, 9 Jan 2007 09:42:03 +0100 > Ingo Oeser <netdev@axxeo.de> wrote: > > >> Hi Stephen, >> >> Stephen Hemminger schrieb: >> >>> --- netdev-2.6.orig/drivers/net/chelsio/sge.c >>> +++ netdev-2.6/drivers/net/chelsio/sge.c >>> >> [...] >> >>> @@ -1043,45 +1046,42 @@ static void recycle_fl_buf(struct freelQ >>> * be copied but there is no memory for the copy. >>> */ >>> static inline struct sk_buff *get_packet(struct pci_dev *pdev, >>> - struct freelQ *fl, unsigned int len, >>> - int dma_pad, int skb_pad, >>> - unsigned int copy_thres, >>> - unsigned int drop_thres) >>> + struct freelQ *fl, unsigned int len) >>> { >>> struct sk_buff *skb; >>> - struct freelQ_ce *ce = &fl->centries[fl->cidx]; >>> + const struct freelQ_ce *ce = &fl->centries[fl->cidx]; >>> >>> - if (len < copy_thres) { >>> - skb = alloc_skb(len + skb_pad, GFP_ATOMIC); >>> - if (likely(skb != NULL)) { >>> - skb_reserve(skb, skb_pad); >>> - skb_put(skb, len); >>> - pci_dma_sync_single_for_cpu(pdev, >>> - pci_unmap_addr(ce, dma_addr), >>> - pci_unmap_len(ce, dma_len), >>> - PCI_DMA_FROMDEVICE); >>> - memcpy(skb->data, ce->skb->data + dma_pad, len); >>> - pci_dma_sync_single_for_device(pdev, >>> + if (len < copybreak) { >>> + skb = alloc_skb(len + 2, GFP_ATOMIC); >>> + if (!skb) >>> + goto use_orig_buf; >>> + >>> + skb_reserve(skb, 2); /* align IP header */ >>> >> Please use NET_IP_ALIGN here: >> > > Wrong, NET_IP_ALIGN is intended to deal with platforms where alignment of DMA is more > important of alignment of structures. Therefore if data is copied, it should > always be 2. > > >> + skb = alloc_skb(len + NET_IP_ALIGN, GFP_ATOMIC); >> + if (!skb) >> + goto use_orig_buf; >> + >> + skb_reserve(skb, NET_IP_ALIGN); >> >> >>> + skb_put(skb, len); >>> + pci_dma_sync_single_for_cpu(pdev, >>> pci_unmap_addr(ce, dma_addr), >>> pci_unmap_len(ce, dma_len), >>> PCI_DMA_FROMDEVICE); >>> - } else if (!drop_thres) >>> - goto use_orig_buf; >>> - >>> + memcpy(skb->data, ce->skb->data, len); >>> + pci_dma_sync_single_for_device(pdev, >>> + pci_unmap_addr(ce, dma_addr), >>> + pci_unmap_len(ce, dma_len), >>> + PCI_DMA_FROMDEVICE); >>> recycle_fl_buf(fl, fl->cidx); >>> return skb; >>> } >>> >>> - if (fl->credits < drop_thres) { >>> +use_orig_buf: >>> + if (fl->credits < 2) { >>> >> Why 2? What does this magic number mean? >> > > No idea, it was there in the original. (as a parameter). > > The T2 HW behaves nicely when it is guaranteed to have 2 available entries in the rx free list. Cheers, Divy ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] chelsio: more rx speedup 2007-01-10 2:08 ` Divy Le Ray @ 2007-01-10 8:34 ` Ingo Oeser 0 siblings, 0 replies; 19+ messages in thread From: Ingo Oeser @ 2007-01-10 8:34 UTC (permalink / raw) To: Divy Le Ray; +Cc: Stephen Hemminger, Jeff Garzik, netdev Divy Le Ray schrieb: > Stephen Hemminger wrote: > > On Tue, 9 Jan 2007 09:42:03 +0100 > > Ingo Oeser <netdev@axxeo.de> wrote: > >> Stephen Hemminger schrieb: > >>> - if (fl->credits < drop_thres) { > >>> +use_orig_buf: > >>> + if (fl->credits < 2) { > >>> > >> Why 2? What does this magic number mean? > > No idea, it was there in the original. (as a parameter). > The T2 HW behaves nicely when it is guaranteed to have 2 available > entries in the rx free list. Can we have a #define for this? That would help people understand this issue more. And don't be shy about errata, all hardware and software out there has them like the humans that made them :-) Regards Ingo Oeser ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] chelsio: more rx speedup 2007-01-09 18:26 ` Stephen Hemminger 2007-01-10 2:08 ` Divy Le Ray @ 2007-01-10 8:30 ` Ingo Oeser 1 sibling, 0 replies; 19+ messages in thread From: Ingo Oeser @ 2007-01-10 8:30 UTC (permalink / raw) To: Stephen Hemminger; +Cc: Jeff Garzik, netdev Stephen Hemminger schrieb: > On Tue, 9 Jan 2007 09:42:03 +0100 > Ingo Oeser <netdev@axxeo.de> wrote: > > Stephen Hemminger schrieb: > > > --- netdev-2.6.orig/drivers/net/chelsio/sge.c > > > +++ netdev-2.6/drivers/net/chelsio/sge.c > > Please use NET_IP_ALIGN here: > > Wrong, NET_IP_ALIGN is intended to deal with platforms where alignment of DMA is more > important of alignment of structures. Therefore if data is copied, it should > always be 2. Ah! Thanks for clearing this up. These magic numbers always make my head spin so I tried to come up with sth. useful :-) If this pattern is present in many drivers, we might have a define or helper for this. Regards Ingo Oeser ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 3/3] chelsio: more rx speedup 2007-01-08 19:26 ` [PATCH 3/3] chelsio: more rx speedup Stephen Hemminger 2007-01-09 8:42 ` Ingo Oeser @ 2007-01-19 3:05 ` Jeff Garzik 1 sibling, 0 replies; 19+ messages in thread From: Jeff Garzik @ 2007-01-19 3:05 UTC (permalink / raw) To: Stephen Hemminger; +Cc: netdev Stephen Hemminger wrote: > Cleanup receive processing some more: > * do the reserve padding of skb during setup > * don't pass constants to get_packet > * do smart prefetch of skb > * make copybreak a module parameter > > Signed-off-by: Stephen Hemminger <shemminger@osdl.org> applied ^ permalink raw reply [flat|nested] 19+ messages in thread
* [PATCH 2/3] chelsio: NAPI speed improvement 2007-01-08 19:24 ` [PATCH 1/3] chelsio: error path fix Stephen Hemminger [not found] ` <20070108112524.730e89f0@dxpl.pdx.osdl.net> @ 2007-01-08 19:26 ` Stephen Hemminger 2007-01-19 3:05 ` Jeff Garzik 1 sibling, 1 reply; 19+ messages in thread From: Stephen Hemminger @ 2007-01-08 19:26 UTC (permalink / raw) To: Jeff Garzik; +Cc: netdev Speedup and cleanup the receive processing by eliminating the mmio read and a lock round trip. Signed-off-by: Stephen Hemminger <shemminger@osdl.org> --- drivers/net/chelsio/sge.c | 77 ++++++++++++++++++++-------------------------- 1 file changed, 35 insertions(+), 42 deletions(-) --- netdev-2.6.orig/drivers/net/chelsio/sge.c +++ netdev-2.6/drivers/net/chelsio/sge.c @@ -1559,6 +1559,14 @@ static int process_responses(struct adap return budget; } +static inline int responses_pending(const struct adapter *adapter) +{ + const struct respQ *Q = &adapter->sge->respQ; + const struct respQ_e *e = &Q->entries[Q->cidx]; + + return (e->GenerationBit == Q->genbit); +} + #ifdef CONFIG_CHELSIO_T1_NAPI /* * A simpler version of process_responses() that handles only pure (i.e., @@ -1568,13 +1576,16 @@ static int process_responses(struct adap * which the caller must ensure is a valid pure response. Returns 1 if it * encounters a valid data-carrying response, 0 otherwise. */ -static int process_pure_responses(struct adapter *adapter, struct respQ_e *e) +static int process_pure_responses(struct adapter *adapter) { struct sge *sge = adapter->sge; struct respQ *q = &sge->respQ; + struct respQ_e *e = &q->entries[q->cidx]; unsigned int flags = 0; unsigned int cmdq_processed[SGE_CMDQ_N] = {0, 0}; + if (e->DataValid) + return 1; do { flags |= e->Qsleeping; @@ -1610,23 +1621,20 @@ static int process_pure_responses(struct int t1_poll(struct net_device *dev, int *budget) { struct adapter *adapter = dev->priv; - int effective_budget = min(*budget, dev->quota); - int work_done = process_responses(adapter, effective_budget); + int work_done; + work_done = process_responses(adapter, min(*budget, dev->quota)); *budget -= work_done; dev->quota -= work_done; - if (work_done >= effective_budget) + if (unlikely(responses_pending(adapter))) return 1; - spin_lock_irq(&adapter->async_lock); - __netif_rx_complete(dev); + netif_rx_complete(dev); writel(adapter->sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); - writel(adapter->slow_intr_mask | F_PL_INTR_SGE_DATA, - adapter->regs + A_PL_ENABLE); - spin_unlock_irq(&adapter->async_lock); return 0; + } /* @@ -1635,44 +1643,33 @@ int t1_poll(struct net_device *dev, int irqreturn_t t1_interrupt(int irq, void *data) { struct adapter *adapter = data; - struct net_device *dev = adapter->sge->netdev; struct sge *sge = adapter->sge; - u32 cause; - int handled = 0; + int handled; - cause = readl(adapter->regs + A_PL_CAUSE); - if (cause == 0 || cause == ~0) - return IRQ_NONE; - - spin_lock(&adapter->async_lock); - if (cause & F_PL_INTR_SGE_DATA) { - struct respQ *q = &adapter->sge->respQ; - struct respQ_e *e = &q->entries[q->cidx]; + if (likely(responses_pending(adapter))) { + struct net_device *dev = sge->netdev; - handled = 1; writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - if (e->GenerationBit == q->genbit && - __netif_rx_schedule_prep(dev)) { - if (e->DataValid || process_pure_responses(adapter, e)) { - /* mask off data IRQ */ - writel(adapter->slow_intr_mask, - adapter->regs + A_PL_ENABLE); - __netif_rx_schedule(sge->netdev); - goto unlock; + if (__netif_rx_schedule_prep(dev)) { + if (process_pure_responses(adapter)) + __netif_rx_schedule(dev); + else { + /* no data, no NAPI needed */ + writel(sge->respQ.cidx, adapter->regs + A_SG_SLEEPING); + netif_poll_enable(dev); /* undo schedule_prep */ } - /* no data, no NAPI needed */ - netif_poll_enable(dev); - } - writel(q->cidx, adapter->regs + A_SG_SLEEPING); - } else - handled = t1_slow_intr_handler(adapter); + return IRQ_HANDLED; + } + + spin_lock(&adapter->async_lock); + handled = t1_slow_intr_handler(adapter); + spin_unlock(&adapter->async_lock); if (!handled) sge->stats.unhandled_irqs++; -unlock: - spin_unlock(&adapter->async_lock); + return IRQ_RETVAL(handled != 0); } @@ -1695,17 +1692,13 @@ unlock: irqreturn_t t1_interrupt(int irq, void *cookie) { int work_done; - struct respQ_e *e; struct adapter *adapter = cookie; - struct respQ *Q = &adapter->sge->respQ; spin_lock(&adapter->async_lock); - e = &Q->entries[Q->cidx]; - prefetch(e); writel(F_PL_INTR_SGE_DATA, adapter->regs + A_PL_CAUSE); - if (likely(e->GenerationBit == Q->genbit)) + if (likely(responses_pending(adapter)) work_done = process_responses(adapter, -1); else work_done = t1_slow_intr_handler(adapter); ^ permalink raw reply [flat|nested] 19+ messages in thread
* Re: [PATCH 2/3] chelsio: NAPI speed improvement 2007-01-08 19:26 ` [PATCH 2/3] chelsio: NAPI speed improvement Stephen Hemminger @ 2007-01-19 3:05 ` Jeff Garzik 0 siblings, 0 replies; 19+ messages in thread From: Jeff Garzik @ 2007-01-19 3:05 UTC (permalink / raw) To: Stephen Hemminger; +Cc: netdev Stephen Hemminger wrote: > Speedup and cleanup the receive processing by eliminating the > mmio read and a lock round trip. > > Signed-off-by: Stephen Hemminger <shemminger@osdl.org> applied ^ permalink raw reply [flat|nested] 19+ messages in thread
end of thread, other threads:[~2007-01-19 3:05 UTC | newest]
Thread overview: 19+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2006-12-15 19:07 [PATCH 0/3] chelsio driver changes Stephen Hemminger
2006-12-15 19:07 ` [PATCH 1/3] chelsio: fix error path Stephen Hemminger
2006-12-15 19:07 ` [PATCH 2/3] chelsio: NAPI speed improvement Stephen Hemminger
2006-12-15 19:07 ` [PATCH 3/3] chelsio: more receive cleanup Stephen Hemminger
2006-12-15 20:10 ` Francois Romieu
2006-12-15 22:55 ` Stephen Hemminger
2006-12-16 0:26 ` Francois Romieu
2006-12-16 1:28 ` Stephen Hemminger
2006-12-26 21:16 ` [PATCH 0/3] chelsio driver changes Jeff Garzik
2007-01-08 19:24 ` [PATCH 1/3] chelsio: error path fix Stephen Hemminger
[not found] ` <20070108112524.730e89f0@dxpl.pdx.osdl.net>
2007-01-08 19:26 ` [PATCH 3/3] chelsio: more rx speedup Stephen Hemminger
2007-01-09 8:42 ` Ingo Oeser
2007-01-09 18:26 ` Stephen Hemminger
2007-01-10 2:08 ` Divy Le Ray
2007-01-10 8:34 ` Ingo Oeser
2007-01-10 8:30 ` Ingo Oeser
2007-01-19 3:05 ` Jeff Garzik
2007-01-08 19:26 ` [PATCH 2/3] chelsio: NAPI speed improvement Stephen Hemminger
2007-01-19 3:05 ` Jeff Garzik
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for NNTP newsgroup(s).