Package: linux-image-2.6.18-4 Severity: important Tags: patch Kernel 2.6.18 contains a version of the natsemi driver which supports NAPI but has buggy handling of shared interrupts. The patch below (which is a slightly cut down version of one which has been accepted upstream, omitting reversion of another change which worked around this problem) fixes this. The active part of the patch is the very first chnage.
Severity important since this can cause the driver to hang on machines where a natsemi device shares an interrupt. Subject: natsemi: Fix NAPI for interrupt sharing The interrupt status register for the natsemi chips is clear on read and was read unconditionally from both the interrupt and from the NAPI poll routine, meaning that if the interrupt service routine was called (for example, due to a shared interrupt) while a NAPI poll was scheduled interrupts could be missed. This patch fixes that by ensuring that the interrupt status register is only read by the interrupt handler when interrupts are enabled from the chip. Thanks to Sergei Shtylyov <[EMAIL PROTECTED]> for spotting the issue, Mark Huth <[EMAIL PROTECTED]> for a simpler method and Simon Blake <[EMAIL PROTECTED]> for testing resources. Index: linux-2.6/drivers/net/natsemi.c =================================================================== --- linux-2.6.orig/drivers/net/natsemi.c 2007-03-11 02:32:43.000000000 +0000 +++ linux-2.6/drivers/net/natsemi.c 2007-03-13 19:38:31.000000000 +0000 @@ -2119,28 +2119,35 @@ struct netdev_private *np = netdev_priv(dev); void __iomem * ioaddr = ns_ioaddr(dev); - if (np->hands_off) + /* Reading IntrStatus automatically acknowledges so don't do + * that while interrupts are disabled, (for example, while a + * poll is scheduled). */ + if (np->hands_off || !readl(ioaddr + IntrEnable)) return IRQ_NONE; - /* Reading automatically acknowledges. */ np->intr_status = readl(ioaddr + IntrStatus); + if (!np->intr_status) + return IRQ_NONE; + if (netif_msg_intr(np)) printk(KERN_DEBUG "%s: Interrupt, status %#08x, mask %#08x.\n", dev->name, np->intr_status, readl(ioaddr + IntrMask)); - if (!np->intr_status) - return IRQ_NONE; - prefetch(&np->rx_skbuff[np->cur_rx % RX_RING_SIZE]); if (netif_rx_schedule_prep(dev)) { /* Disable interrupts and register for poll */ natsemi_irq_disable(dev); __netif_rx_schedule(dev); - } + } else + printk(KERN_WARNING + "%s: Ignoring interrupt, status %#08x, mask %#08x.\n", + dev->name, np->intr_status, + readl(ioaddr + IntrMask)); + return IRQ_HANDLED; } @@ -2156,6 +2163,12 @@ int work_done = 0; do { + if (netif_msg_intr(np)) + printk(KERN_DEBUG + "%s: Poll, status %#08x, mask %#08x.\n", + dev->name, np->intr_status, + readl(ioaddr + IntrMask)); + if (np->intr_status & (IntrTxDone | IntrTxIntr | IntrTxIdle | IntrTxErr)) { spin_lock(&np->lock); -- System Information: Debian Release: 4.0 APT prefers unstable APT policy: (500, 'unstable') Architecture: powerpc (ppc) Shell: /bin/sh linked to /bin/bash Kernel: Linux 2.6.18-3-powerpc Locale: LANG=en_GB.UTF-8, LC_CTYPE=en_GB.UTF-8 (charmap=UTF-8) -- To UNSUBSCRIBE, email to [EMAIL PROTECTED] with a subject of "unsubscribe". Trouble? Contact [EMAIL PROTECTED]