Commit f4e418f7 authored by Michael Chan's avatar Michael Chan Committed by John W. Linville

[PATCH] bnx2: refine bnx2_poll

Refine bnx2_poll() logic to write back the most up-to-date status tag
when all work has been processed. This eliminates some occasional
extra interrupts when a older status tag is written even though all
work has been processed.

The idea is to read the status tag just before exiting bnx2_poll() and
then check again for any new work. If no new work is pending, the
status tag written back will not generate any extra interrupt. This
logic is similar to the changes David Miller did to tg3_poll().
Signed-off-by: default avatarMichael Chan <mchan@broadcom.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent e3648b3d
...@@ -1533,10 +1533,11 @@ bnx2_phy_int(struct bnx2 *bp) ...@@ -1533,10 +1533,11 @@ bnx2_phy_int(struct bnx2 *bp)
static void static void
bnx2_tx_int(struct bnx2 *bp) bnx2_tx_int(struct bnx2 *bp)
{ {
struct status_block *sblk = bp->status_blk;
u16 hw_cons, sw_cons, sw_ring_cons; u16 hw_cons, sw_cons, sw_ring_cons;
int tx_free_bd = 0; int tx_free_bd = 0;
hw_cons = bp->status_blk->status_tx_quick_consumer_index0; hw_cons = bp->hw_tx_cons = sblk->status_tx_quick_consumer_index0;
if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) { if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
hw_cons++; hw_cons++;
} }
...@@ -1591,7 +1592,9 @@ bnx2_tx_int(struct bnx2 *bp) ...@@ -1591,7 +1592,9 @@ bnx2_tx_int(struct bnx2 *bp)
dev_kfree_skb_irq(skb); dev_kfree_skb_irq(skb);
hw_cons = bp->status_blk->status_tx_quick_consumer_index0; hw_cons = bp->hw_tx_cons =
sblk->status_tx_quick_consumer_index0;
if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) { if ((hw_cons & MAX_TX_DESC_CNT) == MAX_TX_DESC_CNT) {
hw_cons++; hw_cons++;
} }
...@@ -1636,11 +1639,12 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb, ...@@ -1636,11 +1639,12 @@ bnx2_reuse_rx_skb(struct bnx2 *bp, struct sk_buff *skb,
static int static int
bnx2_rx_int(struct bnx2 *bp, int budget) 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; u16 hw_cons, sw_cons, sw_ring_cons, sw_prod, sw_ring_prod;
struct l2_fhdr *rx_hdr; struct l2_fhdr *rx_hdr;
int rx_pkt = 0; int rx_pkt = 0;
hw_cons = bp->status_blk->status_rx_quick_consumer_index0; hw_cons = bp->hw_rx_cons = sblk->status_rx_quick_consumer_index0;
if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) { if ((hw_cons & MAX_RX_DESC_CNT) == MAX_RX_DESC_CNT) {
hw_cons++; hw_cons++;
} }
...@@ -1760,6 +1764,15 @@ bnx2_rx_int(struct bnx2 *bp, int budget) ...@@ -1760,6 +1764,15 @@ bnx2_rx_int(struct bnx2 *bp, int budget)
if ((rx_pkt == budget)) if ((rx_pkt == budget))
break; break;
/* 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++;
rmb();
}
} }
bp->rx_cons = sw_cons; bp->rx_cons = sw_cons;
bp->rx_prod = sw_prod; bp->rx_prod = sw_prod;
...@@ -1827,15 +1840,27 @@ bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs) ...@@ -1827,15 +1840,27 @@ bnx2_interrupt(int irq, void *dev_instance, struct pt_regs *regs)
return IRQ_HANDLED; return IRQ_HANDLED;
} }
static inline int
bnx2_has_work(struct bnx2 *bp)
{
struct status_block *sblk = bp->status_blk;
if ((sblk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) ||
(sblk->status_tx_quick_consumer_index0 != bp->hw_tx_cons))
return 1;
if (((sblk->status_attn_bits & STATUS_ATTN_BITS_LINK_STATE) != 0) !=
bp->link_up)
return 1;
return 0;
}
static int static int
bnx2_poll(struct net_device *dev, int *budget) bnx2_poll(struct net_device *dev, int *budget)
{ {
struct bnx2 *bp = dev->priv; struct bnx2 *bp = dev->priv;
int rx_done = 1;
bp->last_status_idx = bp->status_blk->status_idx;
rmb();
if ((bp->status_blk->status_attn_bits & if ((bp->status_blk->status_attn_bits &
STATUS_ATTN_BITS_LINK_STATE) != STATUS_ATTN_BITS_LINK_STATE) !=
(bp->status_blk->status_attn_bits_ack & (bp->status_blk->status_attn_bits_ack &
...@@ -1846,11 +1871,10 @@ bnx2_poll(struct net_device *dev, int *budget) ...@@ -1846,11 +1871,10 @@ bnx2_poll(struct net_device *dev, int *budget)
spin_unlock(&bp->phy_lock); spin_unlock(&bp->phy_lock);
} }
if (bp->status_blk->status_tx_quick_consumer_index0 != bp->tx_cons) { if (bp->status_blk->status_tx_quick_consumer_index0 != bp->hw_tx_cons)
bnx2_tx_int(bp); bnx2_tx_int(bp);
}
if (bp->status_blk->status_rx_quick_consumer_index0 != bp->rx_cons) { if (bp->status_blk->status_rx_quick_consumer_index0 != bp->hw_rx_cons) {
int orig_budget = *budget; int orig_budget = *budget;
int work_done; int work_done;
...@@ -1860,13 +1884,12 @@ bnx2_poll(struct net_device *dev, int *budget) ...@@ -1860,13 +1884,12 @@ bnx2_poll(struct net_device *dev, int *budget)
work_done = bnx2_rx_int(bp, orig_budget); work_done = bnx2_rx_int(bp, orig_budget);
*budget -= work_done; *budget -= work_done;
dev->quota -= work_done; dev->quota -= work_done;
if (work_done >= orig_budget) {
rx_done = 0;
}
} }
if (rx_done) { bp->last_status_idx = bp->status_blk->status_idx;
rmb();
if (!bnx2_has_work(bp)) {
netif_rx_complete(dev); netif_rx_complete(dev);
REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD, REG_WR(bp, BNX2_PCICFG_INT_ACK_CMD,
BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID |
...@@ -3222,6 +3245,7 @@ bnx2_init_tx_ring(struct bnx2 *bp) ...@@ -3222,6 +3245,7 @@ bnx2_init_tx_ring(struct bnx2 *bp)
bp->tx_prod = 0; bp->tx_prod = 0;
bp->tx_cons = 0; bp->tx_cons = 0;
bp->hw_tx_cons = 0;
bp->tx_prod_bseq = 0; bp->tx_prod_bseq = 0;
val = BNX2_L2CTX_TYPE_TYPE_L2; val = BNX2_L2CTX_TYPE_TYPE_L2;
...@@ -3254,6 +3278,7 @@ bnx2_init_rx_ring(struct bnx2 *bp) ...@@ -3254,6 +3278,7 @@ bnx2_init_rx_ring(struct bnx2 *bp)
ring_prod = prod = bp->rx_prod = 0; ring_prod = prod = bp->rx_prod = 0;
bp->rx_cons = 0; bp->rx_cons = 0;
bp->hw_rx_cons = 0;
bp->rx_prod_bseq = 0; bp->rx_prod_bseq = 0;
rxbd = &bp->rx_desc_ring[0]; rxbd = &bp->rx_desc_ring[0];
......
...@@ -3914,6 +3914,9 @@ struct bnx2 { ...@@ -3914,6 +3914,9 @@ struct bnx2 {
u16 tx_cons; u16 tx_cons;
int tx_ring_size; int tx_ring_size;
u16 hw_tx_cons;
u16 hw_rx_cons;
#ifdef BCM_VLAN #ifdef BCM_VLAN
struct vlan_group *vlgrp; struct vlan_group *vlgrp;
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment