aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-02-12 03:52:00 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-12 12:48:28 -0500
commita304e1b82808904c561b7b149b467e338c53fcce (patch)
tree068b68c37f6f11de116288886eb211f267d790f7
parentf9e4acf3befd3b2903e01b3ef1bd344f03299826 (diff)
[PATCH] Debug shared irqs
Drivers registering IRQ handlers with SA_SHIRQ really ought to be able to handle an interrupt happening before request_irq() returns. They also ought to be able to handle an interrupt happening during the start of their call to free_irq(). Let's test that hypothesis.... [bunk@stusta.de: Kconfig fixes] Signed-off-by: David Woodhouse <dwmw2@infradead.org> Cc: Arjan van de Ven <arjan@infradead.org> Signed-off-by: Jesper Juhl <jesper.juhl@gmail.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Adrian Bunk <bunk@stusta.de> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
-rw-r--r--kernel/irq/manage.c33
-rw-r--r--lib/Kconfig.debug9
2 files changed, 42 insertions, 0 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index 8b961adc3bd2..400b12a63649 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -357,6 +357,7 @@ void free_irq(unsigned int irq, void *dev_id)
357 struct irq_desc *desc; 357 struct irq_desc *desc;
358 struct irqaction **p; 358 struct irqaction **p;
359 unsigned long flags; 359 unsigned long flags;
360 irqreturn_t (*handler)(int, void *) = NULL;
360 361
361 WARN_ON(in_interrupt()); 362 WARN_ON(in_interrupt());
362 if (irq >= NR_IRQS) 363 if (irq >= NR_IRQS)
@@ -396,6 +397,8 @@ void free_irq(unsigned int irq, void *dev_id)
396 397
397 /* Make sure it's not being used on another CPU */ 398 /* Make sure it's not being used on another CPU */
398 synchronize_irq(irq); 399 synchronize_irq(irq);
400 if (action->flags & IRQF_SHARED)
401 handler = action->handler;
399 kfree(action); 402 kfree(action);
400 return; 403 return;
401 } 404 }
@@ -403,6 +406,17 @@ void free_irq(unsigned int irq, void *dev_id)
403 spin_unlock_irqrestore(&desc->lock, flags); 406 spin_unlock_irqrestore(&desc->lock, flags);
404 return; 407 return;
405 } 408 }
409#ifdef CONFIG_DEBUG_SHIRQ
410 if (handler) {
411 /*
412 * It's a shared IRQ -- the driver ought to be prepared for it
413 * to happen even now it's being freed, so let's make sure....
414 * We do this after actually deregistering it, to make sure that
415 * a 'real' IRQ doesn't run in parallel with our fake
416 */
417 handler(irq, dev_id);
418 }
419#endif
406} 420}
407EXPORT_SYMBOL(free_irq); 421EXPORT_SYMBOL(free_irq);
408 422
@@ -475,6 +489,25 @@ int request_irq(unsigned int irq, irq_handler_t handler,
475 489
476 select_smp_affinity(irq); 490 select_smp_affinity(irq);
477 491
492#ifdef CONFIG_DEBUG_SHIRQ
493 if (irqflags & IRQF_SHARED) {
494 /*
495 * It's a shared IRQ -- the driver ought to be prepared for it
496 * to happen immediately, so let's make sure....
497 * We do this before actually registering it, to make sure that
498 * a 'real' IRQ doesn't run in parallel with our fake
499 */
500 if (irqflags & IRQF_DISABLED) {
501 unsigned long flags;
502
503 local_irq_save(flags);
504 handler(irq, dev_id);
505 local_irq_restore(flags);
506 } else
507 handler(irq, dev_id);
508 }
509#endif
510
478 retval = setup_irq(irq, action); 511 retval = setup_irq(irq, action);
479 if (retval) 512 if (retval)
480 kfree(action); 513 kfree(action);
diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 356a5ab8279c..63f04c15e6f5 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -77,6 +77,15 @@ config DEBUG_KERNEL
77 Say Y here if you are developing drivers or trying to debug and 77 Say Y here if you are developing drivers or trying to debug and
78 identify kernel problems. 78 identify kernel problems.
79 79
80config DEBUG_SHIRQ
81 bool "Debug shared IRQ handlers"
82 depends on DEBUG_KERNEL && GENERIC_HARDIRQS
83 help
84 Enable this to generate a spurious interrupt as soon as a shared
85 interrupt handler is registered, and just before one is deregistered.
86 Drivers ought to be able to handle interrupts coming in at those
87 points; some don't and need to be caught.
88
80config LOG_BUF_SHIFT 89config LOG_BUF_SHIFT
81 int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL 90 int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
82 range 12 21 91 range 12 21