Skip to content

Commit a304e1b

Browse files
dwmw2Linus Torvalds
authored andcommitted
[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.... [[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]>
1 parent f9e4acf commit a304e1b

File tree

2 files changed

+42
-0
lines changed

2 files changed

+42
-0
lines changed

kernel/irq/manage.c

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,7 @@ void free_irq(unsigned int irq, void *dev_id)
357357
struct irq_desc *desc;
358358
struct irqaction **p;
359359
unsigned long flags;
360+
irqreturn_t (*handler)(int, void *) = NULL;
360361

361362
WARN_ON(in_interrupt());
362363
if (irq >= NR_IRQS)
@@ -396,13 +397,26 @@ void free_irq(unsigned int irq, void *dev_id)
396397

397398
/* Make sure it's not being used on another CPU */
398399
synchronize_irq(irq);
400+
if (action->flags & IRQF_SHARED)
401+
handler = action->handler;
399402
kfree(action);
400403
return;
401404
}
402405
printk(KERN_ERR "Trying to free already-free IRQ %d\n", irq);
403406
spin_unlock_irqrestore(&desc->lock, flags);
404407
return;
405408
}
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
406420
}
407421
EXPORT_SYMBOL(free_irq);
408422

@@ -475,6 +489,25 @@ int request_irq(unsigned int irq, irq_handler_t handler,
475489

476490
select_smp_affinity(irq);
477491

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+
478511
retval = setup_irq(irq, action);
479512
if (retval)
480513
kfree(action);

lib/Kconfig.debug

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,15 @@ config DEBUG_KERNEL
7777
Say Y here if you are developing drivers or trying to debug and
7878
identify kernel problems.
7979

80+
config 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+
8089
config LOG_BUF_SHIFT
8190
int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
8291
range 12 21

0 commit comments

Comments
 (0)