Commit a304e1b8 authored by David Woodhouse's avatar David Woodhouse Committed by Linus Torvalds

[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: default avatarDavid Woodhouse <dwmw2@infradead.org>
Cc: Arjan van de Ven <arjan@infradead.org>
Signed-off-by: default avatarJesper Juhl <jesper.juhl@gmail.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Signed-off-by: default avatarAdrian Bunk <bunk@stusta.de>
Signed-off-by: default avatarAndrew Morton <akpm@linux-foundation.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@linux-foundation.org>
parent f9e4acf3
...@@ -357,6 +357,7 @@ void free_irq(unsigned int irq, void *dev_id) ...@@ -357,6 +357,7 @@ void free_irq(unsigned int irq, void *dev_id)
struct irq_desc *desc; struct irq_desc *desc;
struct irqaction **p; struct irqaction **p;
unsigned long flags; unsigned long flags;
irqreturn_t (*handler)(int, void *) = NULL;
WARN_ON(in_interrupt()); WARN_ON(in_interrupt());
if (irq >= NR_IRQS) if (irq >= NR_IRQS)
...@@ -396,6 +397,8 @@ void free_irq(unsigned int irq, void *dev_id) ...@@ -396,6 +397,8 @@ void free_irq(unsigned int irq, void *dev_id)
/* Make sure it's not being used on another CPU */ /* Make sure it's not being used on another CPU */
synchronize_irq(irq); synchronize_irq(irq);
if (action->flags & IRQF_SHARED)
handler = action->handler;
kfree(action); kfree(action);
return; return;
} }
...@@ -403,6 +406,17 @@ void free_irq(unsigned int irq, void *dev_id) ...@@ -403,6 +406,17 @@ void free_irq(unsigned int irq, void *dev_id)
spin_unlock_irqrestore(&desc->lock, flags); spin_unlock_irqrestore(&desc->lock, flags);
return; 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); EXPORT_SYMBOL(free_irq);
...@@ -475,6 +489,25 @@ int request_irq(unsigned int irq, irq_handler_t handler, ...@@ -475,6 +489,25 @@ int request_irq(unsigned int irq, irq_handler_t handler,
select_smp_affinity(irq); 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); retval = setup_irq(irq, action);
if (retval) if (retval)
kfree(action); kfree(action);
......
...@@ -77,6 +77,15 @@ config DEBUG_KERNEL ...@@ -77,6 +77,15 @@ config DEBUG_KERNEL
Say Y here if you are developing drivers or trying to debug and Say Y here if you are developing drivers or trying to debug and
identify kernel problems. identify kernel problems.
config DEBUG_SHIRQ
bool "Debug shared IRQ handlers"
depends on DEBUG_KERNEL && GENERIC_HARDIRQS
help
Enable this to generate a spurious interrupt as soon as a shared
interrupt handler is registered, and just before one is deregistered.
Drivers ought to be able to handle interrupts coming in at those
points; some don't and need to be caught.
config LOG_BUF_SHIFT config LOG_BUF_SHIFT
int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
range 12 21 range 12 21
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment