diff options
author | Russ Anderson <rja@sgi.com> | 2007-11-14 20:00:15 -0500 |
---|---|---|
committer | Linus Torvalds <torvalds@woody.linux-foundation.org> | 2007-11-14 21:45:43 -0500 |
commit | c642b8391cf8efc3622cc97329a0f46e7cbb70b8 (patch) | |
tree | 34a8892a55563c3885cfed1500f9933b49f04abe /kernel | |
parent | 57d5f66b86079efac5c9a7843cce2a9bcbe58fb8 (diff) |
__do_IRQ does not check IRQ_DISABLED when IRQ_PER_CPU is set
In __do_IRQ(), the normal case is that IRQ_DISABLED is checked and if set
the handler (handle_IRQ_event()) is not called.
Earlier in __do_IRQ(), if IRQ_PER_CPU is set the code does not check
IRQ_DISABLED and calls the handler even though IRQ_DISABLED is set. This
behavior seems unintentional.
One user encountering this behavior is the CPE handler (in
arch/ia64/kernel/mca.c). When the CPE handler encounters too many CPEs
(such as a solid single bit error), it sets up a polling timer and disables
the CPE interrupt (to avoid excessive overhead logging the stream of single
bit errors). disable_irq_nosync() is called which sets IRQ_DISABLED. The
IRQ_PER_CPU flag was previously set (in ia64_mca_late_init()). The net
result is the CPE handler gets called even though it is marked disabled.
If the behavior of not checking IRQ_DISABLED when IRQ_PER_CPU is set is
intentional, it would be worthy of a comment describing the intended
behavior. disable_irq_nosync() does call chip->disable() to provide a
chipset specifiec interface for disabling the interrupt, which avoids this
issue when used.
Signed-off-by: Russ Anderson <rja@sgi.com>
Cc: "Luck, Tony" <tony.luck@intel.com>
Cc: Thomas Gleixner <tglx@linutronix.de>
Cc: Ingo Molnar <mingo@elte.hu>
Cc: Bjorn Helgaas <bjorn.helgaas@hp.com>
Signed-off-by: Andrew Morton <akpm@linux-foundation.org>
Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'kernel')
-rw-r--r-- | kernel/irq/handle.c | 8 |
1 files changed, 5 insertions, 3 deletions
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c index e391cbb1f566..dc335ad27525 100644 --- a/kernel/irq/handle.c +++ b/kernel/irq/handle.c | |||
@@ -178,9 +178,11 @@ fastcall unsigned int __do_IRQ(unsigned int irq) | |||
178 | */ | 178 | */ |
179 | if (desc->chip->ack) | 179 | if (desc->chip->ack) |
180 | desc->chip->ack(irq); | 180 | desc->chip->ack(irq); |
181 | action_ret = handle_IRQ_event(irq, desc->action); | 181 | if (likely(!(desc->status & IRQ_DISABLED))) { |
182 | if (!noirqdebug) | 182 | action_ret = handle_IRQ_event(irq, desc->action); |
183 | note_interrupt(irq, desc, action_ret); | 183 | if (!noirqdebug) |
184 | note_interrupt(irq, desc, action_ret); | ||
185 | } | ||
184 | desc->chip->end(irq); | 186 | desc->chip->end(irq); |
185 | return 1; | 187 | return 1; |
186 | } | 188 | } |