Skip to content

Commit

Permalink
[BNX2]: Fix RX packet rot.
Browse files Browse the repository at this point in the history
Packets can be left in the RX ring if the NAPI budget is reached.
This is caused by storing the latest rx index at the beginning of
bnx2_rx_int().  We may not process all the work up to this index
if the budget is reached and so some packets in the RX ring may rot
when we later check for more work using this stored rx index.

The fix is to not store this latest hw index and only store the
processed rx index.  We use a new function bnx2_get_hw_rx_cons()
to fetch the latest hw rx index.

Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Michael Chan authored and David S. Miller committed Dec 11, 2007
1 parent fb0c18b commit c09c262
Show file tree
Hide file tree
Showing 2 changed files with 14 additions and 13 deletions.
26 changes: 14 additions & 12 deletions drivers/net/bnx2.c
Original file line number Diff line number Diff line change
Expand Up @@ -2387,18 +2387,24 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo;
}

static inline u16
bnx2_get_hw_rx_cons(struct bnx2 *bp)
{
u16 cons = bp->status_blk->status_rx_quick_consumer_index0;

if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT))
cons++;
return cons;
}

static int
bnx2_rx_int(struct bnx2 *bp, int budget)
{
struct status_block *sblk = bp->status_blk;
u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
struct l2_fhdr *rx_hdr;
int rx_pkt = 0;

hw_cons = bp->hw_rx_cons = sblk->status_rx_quick_consumer_index0;
if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) {
hw_cons++;
}
hw_cons = bnx2_get_hw_rx_cons(bp);
sw_cons = bp->rx_cons;
sw_prod = bp->rx_prod;

Expand Down Expand Up @@ -2515,10 +2521,7 @@ bnx2_rx_int(struct bnx2 *bp, int budget)

/* Refresh hw_cons to see if there is new work */
if (sw_cons == hw_cons) {
hw_cons = bp->hw_rx_cons =
sblk->status_rx_quick_consumer_index0;
if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)
hw_cons++;
hw_cons = bnx2_get_hw_rx_cons(bp);
rmb();
}
}
Expand Down Expand Up @@ -2622,7 +2625,7 @@ bnx2_has_work(struct bnx2 *bp)
{
struct status_block *sblk = bp->status_blk;

if ((sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) ||
if ((bnx2_get_hw_rx_cons(bp) != bp->rx_cons) ||
(sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons))
return 1;

Expand Down Expand Up @@ -2655,7 +2658,7 @@ static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget)
if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
bnx2_tx_int(bp);

if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons)
if (bnx2_get_hw_rx_cons(bp) != bp->rx_cons)
work_done += bnx2_rx_int(bp, budget - work_done);

return work_done;
Expand Down Expand Up @@ -4177,7 +4180,6 @@ bnx2_init_rx_ring(struct bnx2 *bp)

ring_prod = prod = bp->rx_prod = 0;
bp->rx_cons = 0;
bp->hw_rx_cons = 0;
bp->rx_prod_bseq = 0;

for (i = 0; i < bp->rx_max_ring; i++) {
Expand Down
1 change: 0 additions & 1 deletion drivers/net/bnx2.h
Original file line number Diff line number Diff line change
Expand Up @@ -6513,7 +6513,6 @@ struct bnx2 {
u32 rx_prod_bseq;
u16 rx_prod;
u16 rx_cons;
u16 hw_rx_cons;

u32 rx_csum;

Expand Down

0 comments on commit c09c262

Please sign in to comment.