summaryrefslogtreecommitdiffstats
path: root/kernel/irq/manage.c
diff options
context:
space:
mode:
authorDavid Woodhouse <dwmw2@infradead.org>2007-02-12 00:52:00 -0800
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-02-12 09:48:28 -0800
commita304e1b82808904c561b7b149b467e338c53fcce (patch)
tree068b68c37f6f11de116288886eb211f267d790f7 /kernel/irq/manage.c
parentf9e4acf3befd3b2903e01b3ef1bd344f03299826 (diff)
downloadlinux-a304e1b82808904c561b7b149b467e338c53fcce.tar.bz2
[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)
struct irq_desc *desc;
struct irqaction **p;
unsigned long flags;
+ irqreturn_t (*handler)(int, void *) = NULL;
WARN_ON(in_interrupt());
if (irq >= NR_IRQS)
@@ -396,6 +397,8 @@ void free_irq(unsigned int irq, void *dev_id)
/* Make sure it's not being used on another CPU */
synchronize_irq(irq);
+ if (action->flags & IRQF_SHARED)
+ handler = action->handler;
kfree(action);
return;
}
@@ -403,6 +406,17 @@ void free_irq(unsigned int irq, void *dev_id)
spin_unlock_irqrestore(&desc->lock, flags);
return;
}
+#ifdef CONFIG_DEBUG_SHIRQ
+ if (handler) {
+ /*
+ * It's a shared IRQ -- the driver ought to be prepared for it
+ * to happen even now it's being freed, so let's make sure....
+ * We do this after actually deregistering it, to make sure that
+ * a 'real' IRQ doesn't run in parallel with our fake
+ */
+ handler(irq, dev_id);
+ }
+#endif
}
EXPORT_SYMBOL(free_irq);
@@ -475,6 +489,25 @@ int request_irq(unsigned int irq, irq_handler_t handler,
select_smp_affinity(irq);
+#ifdef CONFIG_DEBUG_SHIRQ
+ if (irqflags & IRQF_SHARED) {
+ /*
+ * It's a shared IRQ -- the driver ought to be prepared for it
+ * to happen immediately, so let's make sure....
+ * We do this before actually registering it, to make sure that
+ * a 'real' IRQ doesn't run in parallel with our fake
+ */
+ if (irqflags & IRQF_DISABLED) {
+ unsigned long flags;
+
+ local_irq_save(flags);
+ handler(irq, dev_id);
+ local_irq_restore(flags);
+ } else
+ handler(irq, dev_id);
+ }
+#endif
+
retval = setup_irq(irq, action);
if (retval)
kfree(action);