Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S932577Ab0G3Rmz (ORCPT ); Fri, 30 Jul 2010 13:42:55 -0400 Received: from kroah.org ([198.145.64.141]:36207 "EHLO coco.kroah.org" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S932477Ab0G3RgI (ORCPT ); Fri, 30 Jul 2010 13:36:08 -0400 X-Mailbox-Line: From gregkh@clark.site Fri Jul 30 10:31:14 2010 Message-Id: <20100730173114.216192225@clark.site> User-Agent: quilt/0.48-11.2 Date: Fri, 30 Jul 2010 10:31:33 -0700 From: Greg KH To: linux-kernel@vger.kernel.org, stable@kernel.org Cc: stable-review@kernel.org, torvalds@linux-foundation.org, akpm@linux-foundation.org, alan@lxorguk.ukuu.org.uk, Ben Hutchings , "David S. Miller" Subject: [128/140] 3c503: Fix IRQ probing In-Reply-To: <20100730173205.GA22581@kroah.com> Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 3422 Lines: 111 2.6.33-stable review patch. If anyone has any objections, please let us know. ------------------ From: Ben Hutchings commit b0cf4dfb7cd21556efd9a6a67edcba0840b4d98d upstream. The driver attempts to select an IRQ for the NIC automatically by testing which of the supported IRQs are available and then probing each available IRQ with probe_irq_{on,off}(). There are obvious race conditions here, besides which: 1. The test for availability is done by passing a NULL handler, which now always returns -EINVAL, thus the device cannot be opened: 2. probe_irq_off() will report only the first ISA IRQ handled, potentially leading to a false negative. There was another bug that meant it ignored all error codes from request_irq() except -EBUSY, so it would 'succeed' despite this (possibly causing conflicts with other ISA devices). This was fixed by ab08999d6029bb2c79c16be5405d63d2bedbdfea 'WARNING: some request_irq() failures ignored in el2_open()', which exposed bug 1. This patch: 1. Replaces the use of probe_irq_{on,off}() with a real interrupt handler 2. Adds a delay before checking the interrupt-seen flag 3. Disables interrupts on all failure paths 4. Distinguishes error codes from the second request_irq() call, consistently with the first Compile-tested only. Signed-off-by: Ben Hutchings Signed-off-by: David S. Miller Signed-off-by: Greg Kroah-Hartman --- drivers/net/3c503.c | 42 ++++++++++++++++++++++++++++++------------ 1 file changed, 30 insertions(+), 12 deletions(-) --- a/drivers/net/3c503.c +++ b/drivers/net/3c503.c @@ -380,6 +380,12 @@ out: return retval; } +static irqreturn_t el2_probe_interrupt(int irq, void *seen) +{ + *(bool *)seen = true; + return IRQ_HANDLED; +} + static int el2_open(struct net_device *dev) { @@ -391,23 +397,35 @@ el2_open(struct net_device *dev) outb(EGACFR_NORM, E33G_GACFR); /* Enable RAM and interrupts. */ do { - retval = request_irq(*irqp, NULL, 0, "bogus", dev); - if (retval >= 0) { + bool seen; + + retval = request_irq(*irqp, el2_probe_interrupt, 0, + dev->name, &seen); + if (retval == -EBUSY) + continue; + if (retval < 0) + goto err_disable; + /* Twinkle the interrupt, and check if it's seen. */ - unsigned long cookie = probe_irq_on(); + seen = false; + smp_wmb(); outb_p(0x04 << ((*irqp == 9) ? 2 : *irqp), E33G_IDCFR); outb_p(0x00, E33G_IDCFR); - if (*irqp == probe_irq_off(cookie) && /* It's a good IRQ line! */ - ((retval = request_irq(dev->irq = *irqp, - eip_interrupt, 0, - dev->name, dev)) == 0)) - break; - } else { - if (retval != -EBUSY) - return retval; - } + msleep(1); + free_irq(*irqp, el2_probe_interrupt); + if (!seen) + continue; + + retval = request_irq(dev->irq = *irqp, eip_interrupt, 0, + dev->name, dev); + if (retval == -EBUSY) + continue; + if (retval < 0) + goto err_disable; } while (*++irqp); + if (*irqp == 0) { + err_disable: outb(EGACFR_IRQOFF, E33G_GACFR); /* disable interrupts. */ return -EAGAIN; } -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/