Skip to content

Commit

Permalink
[PATCH] Debug shared irqs
Browse files Browse the repository at this point in the history
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....

[[email protected]: Kconfig fixes]
Signed-off-by: David Woodhouse <[email protected]>
Cc: Arjan van de Ven <[email protected]>
Signed-off-by: Jesper Juhl <[email protected]>
Signed-off-by: Ingo Molnar <[email protected]>
Signed-off-by: Adrian Bunk <[email protected]>
Signed-off-by: Andrew Morton <[email protected]>
Signed-off-by: Linus Torvalds <[email protected]>
  • Loading branch information
dwmw2 authored and Linus Torvalds committed Feb 12, 2007
1 parent f9e4acf commit a304e1b
Show file tree
Hide file tree
Showing 2 changed files with 42 additions and 0 deletions.
33 changes: 33 additions & 0 deletions kernel/irq/manage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -396,13 +397,26 @@ 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;
}
printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);
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);

Expand Down Expand Up @@ -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);
Expand Down
9 changes: 9 additions & 0 deletions lib/Kconfig.debug
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,15 @@ config DEBUG_KERNEL
Say Y here if you are developing drivers or trying to debug and
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
int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
range 12 21
Expand Down

0 comments on commit a304e1b

Please sign in to comment.