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: Ayaz Abdulla <aabdulla@nvidia.com> Cc: Manfred Spraul <manfred@colorfullife.com> Cc: Jeff Garzik <jeff@garzik.org> Cc: <stable@kernel.org> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Jeff Garzik <jgarzik@redhat.com>
This commit is contained in:
parent
2e761e0532
commit
4db0ee176e
|
@ -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)
|
||||||
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)
|
||||||
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)
|
||||||
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);
|
||||||
|
|
Loading…
Reference in New Issue