Commit 4db0ee17 authored by Ayaz Abdulla's avatar Ayaz Abdulla Committed by Jeff Garzik
Browse files

forcedeth: msi interrupts



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: default avatarAyaz Abdulla <aabdulla@nvidia.com>
Cc: Manfred Spraul <manfred@colorfullife.com>
Cc: Jeff Garzik <jeff@garzik.org>
Cc: <stable@kernel.org>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarJeff Garzik <jgarzik@redhat.com>
parent 2e761e05
...@@ -3273,6 +3273,20 @@ static void nv_link_irq(struct net_device *dev) ...@@ -3273,6 +3273,20 @@ static void nv_link_irq(struct net_device *dev)
dprintk(KERN_DEBUG "%s: link change notification done.\n", dev->name); 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) static irqreturn_t nv_nic_irq(int foo, void *data)
{ {
struct net_device *dev = (struct net_device *) data; struct net_device *dev = (struct net_device *) data;
...@@ -3295,6 +3309,8 @@ static irqreturn_t nv_nic_irq(int foo, void *data) ...@@ -3295,6 +3309,8 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
if (!(events & np->irqmask)) if (!(events & np->irqmask))
break; break;
nv_msi_workaround(np);
spin_lock(&np->lock); spin_lock(&np->lock);
nv_tx_done(dev); nv_tx_done(dev);
spin_unlock(&np->lock); spin_unlock(&np->lock);
...@@ -3410,6 +3426,8 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data) ...@@ -3410,6 +3426,8 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
if (!(events & np->irqmask)) if (!(events & np->irqmask))
break; break;
nv_msi_workaround(np);
spin_lock(&np->lock); spin_lock(&np->lock);
nv_tx_done_optimized(dev, TX_WORK_PER_LOOP); nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
spin_unlock(&np->lock); spin_unlock(&np->lock);
...@@ -3750,6 +3768,8 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data) ...@@ -3750,6 +3768,8 @@ static irqreturn_t nv_nic_irq_test(int foo, void *data)
if (!(events & NVREG_IRQ_TIMER)) if (!(events & NVREG_IRQ_TIMER))
return IRQ_RETVAL(0); return IRQ_RETVAL(0);
nv_msi_workaround(np);
spin_lock(&np->lock); spin_lock(&np->lock);
np->intr_test = 1; np->intr_test = 1;
spin_unlock(&np->lock); spin_unlock(&np->lock);
......
Supports Markdown
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