Commit a304e1b82808904c561b7b149b467e338c53fcce

Authored by David Woodhouse
Committed by Linus Torvalds
1 parent f9e4acf3be

[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>

Showing 2 changed files with 42 additions and 0 deletions Side-by-side Diff

... ... @@ -357,6 +357,7 @@
357 357 struct irq_desc *desc;
358 358 struct irqaction **p;
359 359 unsigned long flags;
  360 + irqreturn_t (*handler)(int, void *) = NULL;
360 361  
361 362 WARN_ON(in_interrupt());
362 363 if (irq >= NR_IRQS)
... ... @@ -396,6 +397,8 @@
396 397  
397 398 /* Make sure it's not being used on another CPU */
398 399 synchronize_irq(irq);
  400 + if (action->flags & IRQF_SHARED)
  401 + handler = action->handler;
399 402 kfree(action);
400 403 return;
401 404 }
... ... @@ -403,6 +406,17 @@
403 406 spin_unlock_irqrestore(&desc->lock, flags);
404 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 }
407 421 EXPORT_SYMBOL(free_irq);
408 422  
... ... @@ -474,6 +488,25 @@
474 488 action->dev_id = dev_id;
475 489  
476 490 select_smp_affinity(irq);
  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
477 510  
478 511 retval = setup_irq(irq, action);
479 512 if (retval)
... ... @@ -77,6 +77,15 @@
77 77 Say Y here if you are developing drivers or trying to debug and
78 78 identify kernel problems.
79 79  
  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 +
80 89 config LOG_BUF_SHIFT
81 90 int "Kernel log buffer size (16 => 64KB, 17 => 128KB)" if DEBUG_KERNEL
82 91 range 12 21