[BNX2]: Fix RX packet rot.

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>

authored by Michael Chan and committed by David S. Miller c09c2627 fb0c18bd

+14 -13
+14 -12
drivers/net/bnx2.c
··· 2387 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo; 2388 } 2389 2390 static int 2391 bnx2_rx_int(struct bnx2 *bp, int budget) 2392 { 2393 - struct status_block *sblk = bp->status_blk; 2394 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod; 2395 struct l2_fhdr *rx_hdr; 2396 int rx_pkt = 0; 2397 2398 - hw_cons = bp->hw_rx_cons = sblk->status_rx_quick_consumer_index0; 2399 - if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) { 2400 - hw_cons++; 2401 - } 2402 sw_cons = bp->rx_cons; 2403 sw_prod = bp->rx_prod; 2404 ··· 2521 2522 /* Refresh hw_cons to see if there is new work */ 2523 if (sw_cons == hw_cons) { 2524 - hw_cons = bp->hw_rx_cons = 2525 - sblk->status_rx_quick_consumer_index0; 2526 - if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) 2527 - hw_cons++; 2528 rmb(); 2529 } 2530 } ··· 2625 { 2626 struct status_block *sblk = bp->status_blk; 2627 2628 - if ((sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) || 2629 (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)) 2630 return 1; 2631 ··· 2658 if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) 2659 bnx2_tx_int(bp); 2660 2661 - if (sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) 2662 work_done += bnx2_rx_int(bp, budget - work_done); 2663 2664 return work_done; ··· 4180 4181 ring_prod = prod = bp->rx_prod = 0; 4182 bp->rx_cons = 0; 4183 - bp->hw_rx_cons = 0; 4184 bp->rx_prod_bseq = 0; 4185 4186 for (i = 0; i < bp->rx_max_ring; i++) {
··· 2387 prod_bd->rx_bd_haddr_lo = cons_bd->rx_bd_haddr_lo; 2388 } 2389 2390 + static inline u16 2391 + bnx2_get_hw_rx_cons(struct bnx2 *bp) 2392 + { 2393 + u16 cons = bp->status_blk->status_rx_quick_consumer_index0; 2394 + 2395 + if (unlikely((cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT)) 2396 + cons++; 2397 + return cons; 2398 + } 2399 + 2400 static int 2401 bnx2_rx_int(struct bnx2 *bp, int budget) 2402 { 2403 u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod; 2404 struct l2_fhdr *rx_hdr; 2405 int rx_pkt = 0; 2406 2407 + hw_cons = bnx2_get_hw_rx_cons(bp); 2408 sw_cons = bp->rx_cons; 2409 sw_prod = bp->rx_prod; 2410 ··· 2515 2516 /* Refresh hw_cons to see if there is new work */ 2517 if (sw_cons == hw_cons) { 2518 + hw_cons = bnx2_get_hw_rx_cons(bp); 2519 rmb(); 2520 } 2521 } ··· 2622 { 2623 struct status_block *sblk = bp->status_blk; 2624 2625 + if ((bnx2_get_hw_rx_cons(bp) != bp->rx_cons) || 2626 (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)) 2627 return 1; 2628 ··· 2655 if (sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons) 2656 bnx2_tx_int(bp); 2657 2658 + if (bnx2_get_hw_rx_cons(bp) != bp->rx_cons) 2659 work_done += bnx2_rx_int(bp, budget - work_done); 2660 2661 return work_done; ··· 4177 4178 ring_prod = prod = bp->rx_prod = 0; 4179 bp->rx_cons = 0; 4180 bp->rx_prod_bseq = 0; 4181 4182 for (i = 0; i < bp->rx_max_ring; i++) {
-1
drivers/net/bnx2.h
··· 6513 u32 rx_prod_bseq; 6514 u16 rx_prod; 6515 u16 rx_cons; 6516 - u16 hw_rx_cons; 6517 6518 u32 rx_csum; 6519
··· 6513 u32 rx_prod_bseq; 6514 u16 rx_prod; 6515 u16 rx_cons; 6516 6517 u32 rx_csum; 6518