On Thu, 11 Oct 2007 17:17:43 -0700 (PDT) David Miller <[EMAIL PROTECTED]> wrote:
> From: Stephen Hemminger <[EMAIL PROTECTED]> > Date: Thu, 11 Oct 2007 16:55:48 -0700 > > > On Thu, 11 Oct 2007 16:48:27 -0700 (PDT) > > David Miller <[EMAIL PROTECTED]> wrote: > > > > > Alternatively we could loop in tg3_poll() until either budget > > > is exhausted or tg3_has_work() returns false. Actually, this sounds > > > like a cleaner scheme the more I think about it. > > > > > > BNX2 likely has a similar issue. > > > > sky2 as well. > > Thanks for the heads up Stephen. > > Here is a patch that implements the looping idea in tg3, bnx2, and > sky2. > > diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c > index bbfbdaf..b015d52 100644 > --- a/drivers/net/bnx2.c > +++ b/drivers/net/bnx2.c > @@ -2633,15 +2633,11 @@ bnx2_has_work(struct bnx2 *bp) > return 0; > } > > -static int > -bnx2_poll(struct napi_struct *napi, int budget) > +static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget) > { > - struct bnx2 *bp = container_of(napi, struct bnx2, napi); > - struct net_device *dev = bp->dev; > struct status_block *sblk = bp->status_blk; > u32 status_attn_bits = sblk->status_attn_bits; > u32 status_attn_bits_ack = sblk->status_attn_bits_ack; > - int work_done = 0; > > if ((status_attn_bits & STATUS_ATTN_EVENTS) != > (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { > @@ -2660,27 +2656,43 @@ bnx2_poll(struct napi_struct *napi, int budget) > bnx2_tx_int(bp); > > if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) > - work_done = bnx2_rx_int(bp, budget); > + work_done += bnx2_rx_int(bp, budget - work_done); > > - bp->last_status_idx = bp->status_blk->status_idx; > - rmb(); > + return work_done; > +} > + > +static int bnx2_poll(struct napi_struct *napi, int budget) > +{ > + struct bnx2 *bp = container_of(napi, struct bnx2, napi); > + int work_done = 0; > + > + while (1) { > + work_done += bnx2_poll_work(bp, work_done, budget); > > - if (!bnx2_has_work(bp)) { > - netif_rx_complete(dev, napi); > - if (likely(bp->flags & USING_MSI_FLAG)) { > + if (unlikely(work_done >= budget)) > + break; > + > + if (likely(!bnx2_has_work(bp))) { > + bp->last_status_idx = bp->status_blk->status_idx; > + rmb(); > + > + netif_rx_complete(bp->dev, napi); > + if (likely(bp->flags & USING_MSI_FLAG)) { > + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, > + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | > + bp->last_status_idx); > + return 0; > + } > REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, > BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | > + BNX2_PCICFG_INT_ACK_CMD_MASK_INT | > bp->last_status_idx); > - return 0; > - } > - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, > - BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | > - BNX2_PCICFG_INT_ACK_CMD_MASK_INT | > - bp->last_status_idx); > > - REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, > - BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | > - bp->last_status_idx); > + REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, > + BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | > + bp->last_status_idx); > + break; > + } > } > > return work_done; > diff --git a/drivers/net/sky2.c b/drivers/net/sky2.c > index fe0e756..25da238 100644 > --- a/drivers/net/sky2.c > +++ b/drivers/net/sky2.c > @@ -2605,33 +2605,41 @@ static void sky2_err_intr(struct sky2_hw *hw, u32 > status) > static int sky2_poll(struct napi_struct *napi, int work_limit) > { > struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi); > - u32 status = sky2_read32(hw, B0_Y2_SP_EISR); > - int work_done; > + int work_done = 0; > > - if (unlikely(status & Y2_IS_ERROR)) > - sky2_err_intr(hw, status); > + while (1) { > + u32 status = sky2_read32(hw, B0_Y2_SP_EISR); > > - if (status & Y2_IS_IRQ_PHY1) > - sky2_phy_intr(hw, 0); > + if (unlikely(status & Y2_IS_ERROR)) > + sky2_err_intr(hw, status); > > - if (status & Y2_IS_IRQ_PHY2) > - sky2_phy_intr(hw, 1); > + if (status & Y2_IS_IRQ_PHY1) > + sky2_phy_intr(hw, 0); > > - work_done = sky2_status_intr(hw, work_limit); > + if (status & Y2_IS_IRQ_PHY2) > + sky2_phy_intr(hw, 1); > > - /* More work? */ > - if (hw->st_idx == sky2_read16(hw, STAT_PUT_IDX)) { > - /* Bug/Errata workaround? > - * Need to kick the TX irq moderation timer. > - */ > - if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { > - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); > - sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); > - } > + work_done += sky2_status_intr(hw, work_limit - work_done); > > - napi_complete(napi); > - sky2_read32(hw, B0_Y2_SP_LISR); > + if (unlikely(work_done >= work_limit)) > + break; > + > + /* More work? */ > + if (likely(hw->st_idx == sky2_read16(hw, STAT_PUT_IDX))) { > + /* Bug/Errata workaround? > + * Need to kick the TX irq moderation timer. > + */ > + if (sky2_read8(hw, STAT_TX_TIMER_CTRL) == TIM_START) { > + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); > + sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); > + } > + > + napi_complete(napi); > + sky2_read32(hw, B0_Y2_SP_LISR); > + break; > + } > } > + > return work_done; > } You don't need to re-read the status register and process the PHY irq's inside loop. Try this: --- a/drivers/net/sky2.c 2007-10-11 13:16:15.000000000 -0700 +++ b/drivers/net/sky2.c 2007-10-11 17:30:29.000000000 -0700 @@ -2606,7 +2606,7 @@ static int sky2_poll(struct napi_struct { struct sky2_hw *hw = container_of(napi, struct sky2_hw, napi); u32 status = sky2_read32(hw, B0_Y2_SP_EISR); - int work_done; + int work_done = 0; if (unlikely(status & Y2_IS_ERROR)) sky2_err_intr(hw, status); @@ -2617,10 +2617,16 @@ static int sky2_poll(struct napi_struct if (status & Y2_IS_IRQ_PHY2) sky2_phy_intr(hw, 1); - work_done = sky2_status_intr(hw, work_limit); + for(;;) { + work_done += sky2_status_intr(hw, work_limit); + + if (work_done >= work_limit) + break; + + /* More work? */ + if (hw->st_idx != sky2_read16(hw, STAT_PUT_IDX)) + continue; - /* More work? */ - if (hw->st_idx == sky2_read16(hw, STAT_PUT_IDX)) { /* Bug/Errata workaround? * Need to kick the TX irq moderation timer. */ @@ -2628,10 +2634,13 @@ static int sky2_poll(struct napi_struct sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_STOP); sky2_write8(hw, STAT_TX_TIMER_CTRL, TIM_START); } - + napi_complete(napi); sky2_read32(hw, B0_Y2_SP_LISR); + break; + } + return work_done; } - To unsubscribe from this list: send the line "unsubscribe netdev" in the body of a message to [EMAIL PROTECTED] More majordomo info at http://vger.kernel.org/majordomo-info.html