]> git.hungrycats.org Git - linux/commitdiff
forcedeth: msi interrupts
authorAyaz Abdulla <aabdulla@nvidia.com>
Thu, 12 Jun 2008 00:20:18 +0000 (00:20 +0000)
committerGreg Kroah-Hartman <gregkh@suse.de>
Mon, 16 Jun 2008 20:20:02 +0000 (13:20 -0700)
commit 4db0ee176e256444695ee2d7b004552e82fec987 upstream

Add a workaround for lost MSI interrupts.  There is a race condition in
the HW in which future interrupts could be missed.  The workaround is to
toggle the MSI irq mask.

Added cleanup based on comments from Andrew Morton.

Signed-off-by: Ayaz Abdulla <aabdulla@nvidia.com>
Cc: Manfred Spraul <manfred@colorfullife.com>
Cc: Jeff Garzik <jeff@garzik.org>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
drivers/net/forcedeth.c

index 9f088a47d8b14d5015e1e984cd7dadd5716fc467..8e877e7665815dbcfa7fb4cdb6bcf3ed6a37456b 100644 (file)
@@ -3111,6 +3111,20 @@ static void nv_link_irq(struct net_device *dev)
        dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name);
 }
 
+static void nv_msi_workaround(struct fe_priv *np)
+{
+
+       /* Need to toggle the msi irq mask within the ethernet device,
+        * otherwise, future interrupts will not be detected.
+        */
+       if (np->msi_flags & NV_MSI_ENABLED) {
+               u8 __iomem *base = np->base;
+
+               writel(0, base + NvRegMSIIrqMask);
+               writel(NVREG_MSI_VECTOR_0_ENABLED, base + NvRegMSIIrqMask);
+       }
+}
+
 static irqreturn_t nv_nic_irq(int foo, void *data)
 {
        struct net_device *dev = (struct net_device *) data;
@@ -3133,6 +3147,8 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
                if (!(events & np->irqmask))
                        break;
 
+               nv_msi_workaround(np);
+
                spin_lock(&np->lock);
                nv_tx_done(dev);
                spin_unlock(&np->lock);
@@ -3248,6 +3264,8 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
                if (!(events & np->irqmask))
                        break;
 
+               nv_msi_workaround(np);
+
                spin_lock(&np->lock);
                nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
                spin_unlock(&np->lock);
@@ -3588,6 +3606,8 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data)
        if (!(events & NVREG_IRQ_TIMER))
                return IRQ_RETVAL(0);
 
+       nv_msi_workaround(np);
+
        spin_lock(&np->lock);
        np->intr_test = 1;
        spin_unlock(&np->lock);