aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/manage.c
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 /kernel/irq/manage.c
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>
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r--kernel/irq/manage.c33
1 files changed, 33 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);