Skip to content

Commit

Permalink
[BNX2]: Reduce spurious INTA interrupts.
Browse files Browse the repository at this point in the history
Spurious interrupts are often encountered especially on systems
using the 8259 PIC mode.  This is because the I/O write to deassert
the interrupt is posted and won't get to the chip immediately.  As
a result, the IRQ may remain asserted after the IRQ handler exits,
causing spurious interrupts.

Add read back to flush the I/O write to deassert the IRQ immediately.
We also store the last_status_idx immediately in the IRQ handler to
help detect whether the interrupt is ours or not when the IRQ is
entered again before ->poll gets called.

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 Jul 11, 2007
1 parent 9b1084b commit b8a7ce7
Showing 1 changed file with 11 additions and 2 deletions.
13 changes: 11 additions & 2 deletions drivers/net/bnx2.c
Original file line number Diff line number Diff line change
Expand Up @@ -2547,14 +2547,15 @@ bnx2_interrupt(int irq, void *dev_instance)
{
struct net_device *dev = dev_instance;
struct bnx2 *bp = netdev_priv(dev);
struct status_block *sblk = bp->status_blk;

/* When using INTx, it is possible for the interrupt to arrive
* at the CPU before the status block posted prior to the
* interrupt. Reading a register will flush the status block.
* When using MSI, the MSI message will always complete after
* the status block write.
*/
if ((bp->status_blk->status_idx == bp->last_status_idx) &&
if ((sblk->status_idx == bp->last_status_idx) &&
(REG_RD(bp, BNX2_PCICFG_MISC_STATUS) &
BNX2_PCICFG_MISC_STATUS_INTA_VALUE))
return IRQ_NONE;
Expand All @@ -2563,11 +2564,19 @@ bnx2_interrupt(int irq, void *dev_instance)
BNX2_PCICFG_INT_ACK_CMD_USE_INT_HC_PARAM |
BNX2_PCICFG_INT_ACK_CMD_MASK_INT);

/* Read back to deassert IRQ immediately to avoid too many
* spurious interrupts.
*/
REG_RD(bp, BNX2_PCICFG_INT_ACK_CMD);

/* Return here if interrupt is shared and is disabled. */
if (unlikely(atomic_read(&bp->intr_sem) != 0))
return IRQ_HANDLED;

netif_rx_schedule(dev);
if (netif_rx_schedule_prep(dev)) {
bp->last_status_idx = sblk->status_idx;
__netif_rx_schedule(dev);
}

return IRQ_HANDLED;
}
Expand Down

0 comments on commit b8a7ce7

Please sign in to comment.