summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAyaz Abdulla <aabdulla@nvidia.com>2008-06-12 00:20:18 +0000
committerGreg Kroah-Hartman <gregkh@suse.de>2008-06-16 13:20:02 -0700
commit8af4f53dd282f803621c9c5d928e17eed65e0d76 (patch)
tree0a198f29a7d404a1dd079628814135da00cf9bb7
parenteea341fa413396a3857386051f4a1f6e3a1d81bc (diff)
forcedeth: msi interrupts
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>
-rw-r--r--drivers/net/forcedeth.c20
1 files changed, 20 insertions, 0 deletions
diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c
index 9f088a47d8b1..8e877e766581 100644
--- a/drivers/net/forcedeth.c
+++ b/drivers/net/forcedeth.c
@@ -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);