diff options
author | David Woodhouse <dwmw2@infradead.org> | 2007-10-17 02:26:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-10-17 11:42:49 -0400 |
commit | 1d99493b3a68e40e56459ea3565d4402fb6e5f3a (patch) | |
tree | 362ebcf8871e0fad07aa754bb5194de3a2cd64d3 | |
parent | f13ef7754f724842dbf5ae6d85d0604fff0d1a84 (diff) |
Fix CONFIG_DEBUG_SHIRQ trigger on free_irq()
Andy Gospodarek pointed out that because we return in the middle of the
free_irq() function, we never actually do call the IRQ handler that just
got deregistered. This should fix it, although I expect Andrew will want
to convert those 'return's to 'break'. That's a separate change though.
Signed-off-by: David Woodhouse <dwmw2@infradead.org>
Cc: Andy Gospodarek <andy@greyhouse.net>
Cc: Fernando Luis Vzquez Cao <fernando@oss.ntt.co.jp>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r-- | kernel/irq/manage.c | 31 |
1 files changed, 15 insertions, 16 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c index 7230d914eaa2..80eab7a04205 100644 --- a/kernel/irq/manage.c +++ b/kernel/irq/manage.c | |||
@@ -405,7 +405,6 @@ void free_irq(unsigned int irq, void *dev_id) | |||
405 | struct irq_desc *desc; | 405 | struct irq_desc *desc; |
406 | struct irqaction **p; | 406 | struct irqaction **p; |
407 | unsigned long flags; | 407 | unsigned long flags; |
408 | irqreturn_t (*handler)(int, void *) = NULL; | ||
409 | 408 | ||
410 | WARN_ON(in_interrupt()); | 409 | WARN_ON(in_interrupt()); |
411 | if (irq >= NR_IRQS) | 410 | if (irq >= NR_IRQS) |
@@ -445,8 +444,21 @@ void free_irq(unsigned int irq, void *dev_id) | |||
445 | 444 | ||
446 | /* Make sure it's not being used on another CPU */ | 445 | /* Make sure it's not being used on another CPU */ |
447 | synchronize_irq(irq); | 446 | synchronize_irq(irq); |
448 | if (action->flags & IRQF_SHARED) | 447 | #ifdef CONFIG_DEBUG_SHIRQ |
449 | handler = action->handler; | 448 | /* |
449 | * It's a shared IRQ -- the driver ought to be | ||
450 | * prepared for it to happen even now it's | ||
451 | * being freed, so let's make sure.... We do | ||
452 | * this after actually deregistering it, to | ||
453 | * make sure that a 'real' IRQ doesn't run in | ||
454 | * parallel with our fake | ||
455 | */ | ||
456 | if (action->flags & IRQF_SHARED) { | ||
457 | local_irq_save(flags); | ||
458 | action->handler(irq, dev_id); | ||
459 | local_irq_restore(flags); | ||
460 | } | ||
461 | #endif | ||
450 | kfree(action); | 462 | kfree(action); |
451 | return; | 463 | return; |
452 | } | 464 | } |
@@ -454,19 +466,6 @@ void free_irq(unsigned int irq, void *dev_id) | |||
454 | spin_unlock_irqrestore(&desc->lock, flags); | 466 | spin_unlock_irqrestore(&desc->lock, flags); |
455 | return; | 467 | return; |
456 | } | 468 | } |
457 | #ifdef CONFIG_DEBUG_SHIRQ | ||
458 | if (handler) { | ||
459 | /* | ||
460 | * It's a shared IRQ -- the driver ought to be prepared for it | ||
461 | * to happen even now it's being freed, so let's make sure.... | ||
462 | * We do this after actually deregistering it, to make sure that | ||
463 | * a 'real' IRQ doesn't run in parallel with our fake | ||
464 | */ | ||
465 | local_irq_save(flags); | ||
466 | handler(irq, dev_id); | ||
467 | local_irq_restore(flags); | ||
468 | } | ||
469 | #endif | ||
470 | } | 469 | } |
471 | EXPORT_SYMBOL(free_irq); | 470 | EXPORT_SYMBOL(free_irq); |
472 | 471 | ||