Commit fd6905e5 authored by Jeff Garzik's avatar Jeff Garzik

[netdrvr tg3] Better interrupt masking

The bcm570x chips provide a register that disables (masks) or enables
interrupts, and as a side effect, each write to this register regardless 
of value clears various PCI and internal interrupt-pending flags.  This
register, intr-mbox-0, provides a superset of the function provided
by the mask-pci-int and clear-pci-int bits in the misc-host-ctrl register.

Furthermore, the documentation clearly implies use of this register,
as an indicator that the host [tg3 driver] is in its interrupt handler.

The new tg3 logic, taking this knowledge into account, masks-and-clears
irqs using intr-mbox-0 [only] when a hard irq is received, and
unmasks-and-clears irqs at the end of tg3_poll after all NAPI events
have been exhausted.

The old logic twiddled the misc-host-ctrl irq masking bits separately
from intr-mbox-0 bits, which was not only inconsistent but also
a few additional I/Os that were not needed.
parent f4c57464
......@@ -221,22 +221,6 @@ static void tg3_enable_ints(struct tg3 *tp)
tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
}
static inline void tg3_mask_ints(struct tg3 *tp)
{
tw32(TG3PCI_MISC_HOST_CTRL,
(tp->misc_host_ctrl | MISC_HOST_CTRL_MASK_PCI_INT));
}
static inline void tg3_unmask_ints(struct tg3 *tp)
{
tw32(TG3PCI_MISC_HOST_CTRL,
(tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT));
if (tp->hw_status->status & SD_STATUS_UPDATED) {
tw32(GRC_LOCAL_CTRL,
tp->grc_local_ctrl | GRC_LCLCTRL_SETINT);
}
}
static void tg3_switch_clocks(struct tg3 *tp)
{
if (tr32(TG3PCI_CLOCK_CTRL) & CLOCK_CTRL_44MHZ_CORE) {
......@@ -2057,7 +2041,7 @@ static int tg3_poll(struct net_device *netdev, int *budget)
if (done) {
netif_rx_complete(netdev);
tg3_unmask_ints(tp);
tg3_enable_ints(tp);
}
spin_unlock_irqrestore(&tp->lock, flags);
......@@ -2065,10 +2049,10 @@ static int tg3_poll(struct net_device *netdev, int *budget)
return (done ? 0 : 1);
}
static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg3 *tp)
static inline unsigned int tg3_has_work(struct net_device *dev, struct tg3 *tp)
{
struct tg3_hw_status *sblk = tp->hw_status;
int work_exists = 0;
unsigned int work_exists = 0;
if (!(tp->tg3_flags &
(TG3_FLAG_USE_LINKCHG_REG |
......@@ -2080,19 +2064,7 @@ static __inline__ void tg3_interrupt_main_work(struct net_device *dev, struct tg
sblk->idx[0].rx_producer != tp->rx_rcb_ptr)
work_exists = 1;
if (!work_exists)
return;
if (netif_rx_schedule_prep(dev)) {
/* NOTE: These writes are posted by the readback of
* the mailbox register done by our caller.
*/
tg3_mask_ints(tp);
__netif_rx_schedule(dev);
} else {
printk(KERN_ERR PFX "%s: Error, poll already scheduled\n",
dev->name);
}
return work_exists;
}
static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
......@@ -2107,13 +2079,16 @@ static void tg3_interrupt(int irq, void *dev_id, struct pt_regs *regs)
if (sblk->status & SD_STATUS_UPDATED) {
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000001);
tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
sblk->status &= ~SD_STATUS_UPDATED;
tg3_interrupt_main_work(dev, tp);
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000000);
tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
if (likely(tg3_has_work(dev, tp)))
netif_rx_schedule(dev);
else {
tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW,
0x00000000);
tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW);
}
}
spin_unlock_irqrestore(&tp->lock, flags);
......
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