diff options
author | David S. Miller <davem@sunset.davemloft.net> | 2007-10-11 21:08:29 -0400 |
---|---|---|
committer | David S. Miller <davem@sunset.davemloft.net> | 2007-10-11 21:08:29 -0400 |
commit | 6f535763165331bb91277d7519b507fed22034e5 (patch) | |
tree | 1968a01affa1cce3a3199c455d1fe1ebdca3ff47 /drivers/net/bnx2.c | |
parent | b08d6cb22c777c8c91c16d8e3b8aafc93c98cbd9 (diff) |
[NET]: Fix NAPI completion handling in some drivers.
In order for the list handling in net_rx_action() to be
correct, drivers must follow certain rules as stated by
this comment in net_rx_action():
/* Drivers must not modify the NAPI state if they
* consume the entire weight. In such cases this code
* still "owns" the NAPI instance and therefore can
* move the instance around on the list at-will.
*/
A few drivers do not do this because they mix the budget checks
with reading hardware state, resulting in crashes like the one
reported by takano@axe-inc.co.jp.
BNX2 and TG3 are taken care of here, SKY2 fix is from Stephen
Hemminger.
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/bnx2.c')
-rw-r--r-- | drivers/net/bnx2.c | 52 |
1 files changed, 32 insertions, 20 deletions
diff --git a/drivers/net/bnx2.c b/drivers/net/bnx2.c index bbfbdafb4ae5..d68accea380b 100644 --- a/drivers/net/bnx2.c +++ b/drivers/net/bnx2.c | |||
@@ -2633,15 +2633,11 @@ bnx2_has_work(struct bnx2 *bp) | |||
2633 | return 0; | 2633 | return 0; |
2634 | } | 2634 | } |
2635 | 2635 | ||
2636 | static int | 2636 | static int bnx2_poll_work(struct bnx2 *bp, int work_done, int budget) |
2637 | bnx2_poll(struct napi_struct *napi, int budget) | ||
2638 | { | 2637 | { |
2639 | struct bnx2 *bp = container_of(napi, struct bnx2, napi); | ||
2640 | struct net_device *dev = bp->dev; | ||
2641 | struct status_block *sblk = bp->status_blk; | 2638 | struct status_block *sblk = bp->status_blk; |
2642 | u32 status_attn_bits = sblk->status_attn_bits; | 2639 | u32 status_attn_bits = sblk->status_attn_bits; |
2643 | u32 status_attn_bits_ack = sblk->status_attn_bits_ack; | 2640 | u32 status_attn_bits_ack = sblk->status_attn_bits_ack; |
2644 | int work_done = 0; | ||
2645 | 2641 | ||
2646 | if ((status_attn_bits & STATUS_ATTN_EVENTS) != | 2642 | if ((status_attn_bits & STATUS_ATTN_EVENTS) != |
2647 | (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { | 2643 | (status_attn_bits_ack & STATUS_ATTN_EVENTS)) { |
@@ -2660,27 +2656,43 @@ bnx2_poll(struct napi_struct *napi, int budget) | |||
2660 | bnx2_tx_int(bp); | 2656 | bnx2_tx_int(bp); |
2661 | 2657 | ||
2662 | if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) | 2658 | if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) |
2663 | work_done = bnx2_rx_int(bp, budget); | 2659 | work_done += bnx2_rx_int(bp, budget - work_done); |
2664 | 2660 | ||
2665 | bp->last_status_idx = bp->status_blk->status_idx; | 2661 | return work_done; |
2666 | rmb(); | 2662 | } |
2663 | |||
2664 | static int bnx2_poll(struct napi_struct *napi, int budget) | ||
2665 | { | ||
2666 | struct bnx2 *bp = container_of(napi, struct bnx2, napi); | ||
2667 | int work_done = 0; | ||
2668 | |||
2669 | while (1) { | ||
2670 | work_done = bnx2_poll_work(bp, work_done, budget); | ||
2667 | 2671 | ||
2668 | if (!bnx2_has_work(bp)) { | 2672 | if (unlikely(work_done >= budget)) |
2669 | netif_rx_complete(dev, napi); | 2673 | break; |
2670 | if (likely(bp->flags & USING_MSI_FLAG)) { | 2674 | |
2675 | if (likely(!bnx2_has_work(bp))) { | ||
2676 | bp->last_status_idx = bp->status_blk->status_idx; | ||
2677 | rmb(); | ||
2678 | |||
2679 | netif_rx_complete(bp->dev, napi); | ||
2680 | if (likely(bp->flags & USING_MSI_FLAG)) { | ||
2681 | REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, | ||
2682 | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | | ||
2683 | bp->last_status_idx); | ||
2684 | return 0; | ||
2685 | } | ||
2671 | REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, | 2686 | REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, |
2672 | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | | 2687 | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | |
2688 | BNX2_PCICFG_INT_ACK_CMD_MASK_INT | | ||
2673 | bp->last_status_idx); | 2689 | bp->last_status_idx); |
2674 | return 0; | ||
2675 | } | ||
2676 | REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, | ||
2677 | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | | ||
2678 | BNX2_PCICFG_INT_ACK_CMD_MASK_INT | | ||
2679 | bp->last_status_idx); | ||
2680 | 2690 | ||
2681 | REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, | 2691 | REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, |
2682 | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | | 2692 | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | |
2683 | bp->last_status_idx); | 2693 | bp->last_status_idx); |
2694 | break; | ||
2695 | } | ||
2684 | } | 2696 | } |
2685 | 2697 | ||
2686 | return work_done; | 2698 | return work_done; |