aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/handle.c
diff options
context:
space:
mode:
authorRuss Anderson <rja@sgi.com>2007-11-14 20:00:15 -0500
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-11-14 21:45:43 -0500
commitc642b8391cf8efc3622cc97329a0f46e7cbb70b8 (patch)
tree34a8892a55563c3885cfed1500f9933b49f04abe /kernel/irq/handle.c
parent57d5f66b86079efac5c9a7843cce2a9bcbe58fb8 (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/irq/handle.c')
-rw-r--r--kernel/irq/handle.c8
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 }