From: Ayaz Abdulla Date: Thu, 12 Jun 2008 00:20:18 +0000 (+0000) Subject: forcedeth: msi interrupts X-Git-Tag: v2.6.25.7~11 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8af4f53dd282f803621c9c5d928e17eed65e0d76;p=thirdparty%2Fkernel%2Fstable.git 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 Cc: Manfred Spraul Cc: Jeff Garzik Signed-off-by: Andrew Morton Signed-off-by: Jeff Garzik Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/net/forcedeth.c b/drivers/net/forcedeth.c index 9f088a47d8b14..8e877e7665815 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);