===== drivers/net/tg3.c 1.222 vs edited ===== --- 1.222/drivers/net/tg3.c 2004-11-15 15:53:08 -08:00 +++ edited/drivers/net/tg3.c 2005-01-16 22:03:29 -08:00 @@ -434,7 +434,7 @@ { tw32(TG3PCI_MISC_HOST_CTRL, (tp->misc_host_ctrl & ~MISC_HOST_CTRL_MASK_PCI_INT)); - tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0x00000000); + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); mmiowb(); tg3_cond_int(tp); @@ -2877,7 +2877,14 @@ spin_lock_irqsave(&tp->lock, flags); + /* + * On some platforms, we may see "unhandled" interrupts + * since the status block could still be in-flight. + * But the IRQ line will still be asserted and EOI will + * cause another IRQ to be generated. + */ if (sblk->status & SD_STATUS_UPDATED) { + /* * writing any value to intr-mbox-0 clears PCI INTA# and * chip-internal interrupt pending events. @@ -2885,8 +2892,8 @@ * NIC to stop sending us irqs, engaging "in-intr-handler" * event coalescing. */ - tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - 0x00000001); + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 1); + /* * Flush PCI write. This also guarantees that our * status block has been flushed to host memory. @@ -2900,19 +2907,71 @@ /* no work, shared interrupt perhaps? re-enable * interrupts, and flush that PCI write */ - tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, - 0x00000000); + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); } - } else { /* shared interrupt */ + } else { /* shared interrupt? */ handled = 0; } spin_unlock_irqrestore(&tp->lock, flags); - return IRQ_RETVAL(handled); } + +static irqreturn_t tg3_msi_intr(int irq, void *dev_id, struct pt_regs *regs) +{ + struct net_device *dev = dev_id; + struct tg3 *tp = netdev_priv(dev); + struct tg3_hw_status *sblk = tp->hw_status; + irqreturn_t handled = 1; + +#if 0 +This did not work - test seems to be bogus. + /* We can get spurious interrupts from MSI because of HW bugs *sigh*. + * Just tell the kernel we've handled the interrupt since we will + * as long as we are polling. + */ + if (dev->state & __LINK_STATE_RX_SCHED) { +printk(" RX_SCHED"); + return 1; + } +#endif + spin_lock(&tp->lock); + + if (sblk->status & SD_STATUS_UPDATED) { + sblk->status &= ~SD_STATUS_UPDATED; + + /* + * writing any value to intr-mbox-0 clears PCI INTA# and + * chip-internal interrupt pending events. + * + * writing non-zero to intr-mbox-0 tells the NIC to stop + * sending us irqs, engaging "in-intr-handler" event + * coalescing. + */ + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 1); + + if (likely(tg3_has_work(dev, tp))) { + netif_rx_schedule(dev); /* schedule NAPI poll */ + } else { + /* no work? + * Likely a race condition with the status_tag + * handling generated a spurious interrupt. + * Nevermind...let's get back to work. + */ + tw32_mailbox(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW, 0); + tr32(MAILBOX_INTERRUPT_0 + TG3_64BIT_REG_LOW); + } + } else { + handled = 0; + } + + spin_unlock(&tp->lock); + return handled; +} + + static int tg3_init_hw(struct tg3 *); static int tg3_halt(struct tg3 *); @@ -5679,10 +5738,21 @@ if (err) return err; - err = request_irq(dev->irq, tg3_interrupt, - SA_SHIRQ, dev->name, dev); + if (pci_enable_msi(tp->pdev)) { + printk(KERN_WARNING PFX "MSI NOT enabled for %s\n", + tp->pdev->slot_name); + err = request_irq(dev->irq, tg3_interrupt, SA_SHIRQ, + dev->name, dev); + } else { + tw32(MSGINT_MODE, MSGINT_MODE_ENABLE); + printk(KERN_INFO PFX "MSI enabled on %s\n", + tp->pdev->slot_name); + err = request_irq(dev->irq, tg3_msi_intr, SA_SHIRQ, + dev->name, dev); + } if (err) { + pci_disable_msi(tp->pdev); tg3_free_consistent(tp); return err; } @@ -5713,6 +5783,7 @@ if (err) { free_irq(dev->irq, dev); + pci_disable_msi(tp->pdev); tg3_free_consistent(tp); return err; } @@ -5988,6 +6059,7 @@ spin_unlock_irq(&tp->lock); free_irq(dev->irq, dev); + pci_disable_msi(tp->pdev); memcpy(&tp->net_stats_prev, tg3_get_stats(tp->dev), sizeof(tp->net_stats_prev)); @@ -7569,9 +7641,8 @@ /* Only 5701 and later support tagged irq status mode. * Also, 5788 chips cannot use tagged irq status. * - * However, since we are using NAPI avoid tagged irq status - * because the interrupt condition is more difficult to - * fully clear in that mode. + * However, we don't use tagged irq status mode because the + * interrupt condition is more difficult to fully clear with NAPI. */ tp->coalesce_mode = 0;