aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/handle.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2011-02-22 06:50:12 -0500
committerThomas Gleixner <tglx@linutronix.de>2011-02-22 07:02:03 -0500
commit70433c01613c2a44756c7b25f7bdd6c1c77b119f (patch)
tree27fb95b4ccaa498a7bbae135835b8a0472147d1b /kernel/irq/handle.c
parent8fff39e06987492da3d4a0b9ec7cdbd245b6762b (diff)
genirq: Use the correct variable for note_interrupt
note_interrupt wants to be called with the combined result of all handlers called, not with the last one. If it's a shared interrupt then the last handler might return IRQ_NONE often enough to trigger the spurious dectector which turns off a perfectly fine working interrupt line. Bug was introduced in commit 1277a532(genirq: Simplify handle_irq_event()). Yes, I really messed up there. First the variable ret should not have been named differently to avoid similarity with retval. Second it should have been declared in the do {} loop. Rename it to res and move it into the do {} loop and vanish under a huge brown paperbag. Reported-bisected-tested-by: Ingo Molnar <mingo@elte.hu> Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/irq/handle.c')
-rw-r--r--kernel/irq/handle.c16
1 files changed, 9 insertions, 7 deletions
diff --git a/kernel/irq/handle.c b/kernel/irq/handle.c
index cb62e2d0df4e..e099e9e9de0b 100644
--- a/kernel/irq/handle.c
+++ b/kernel/irq/handle.c
@@ -54,24 +54,26 @@ static void warn_no_thread(unsigned int irq, struct irqaction *action)
54irqreturn_t 54irqreturn_t
55handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action) 55handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
56{ 56{
57 irqreturn_t ret, retval = IRQ_NONE; 57 irqreturn_t retval = IRQ_NONE;
58 unsigned int random = 0, irq = desc->irq_data.irq; 58 unsigned int random = 0, irq = desc->irq_data.irq;
59 59
60 do { 60 do {
61 irqreturn_t res;
62
61 trace_irq_handler_entry(irq, action); 63 trace_irq_handler_entry(irq, action);
62 ret = action->handler(irq, action->dev_id); 64 res = action->handler(irq, action->dev_id);
63 trace_irq_handler_exit(irq, action, ret); 65 trace_irq_handler_exit(irq, action, res);
64 66
65 if (WARN_ON_ONCE(!irqs_disabled())) 67 if (WARN_ON_ONCE(!irqs_disabled()))
66 local_irq_disable(); 68 local_irq_disable();
67 69
68 switch (ret) { 70 switch (res) {
69 case IRQ_WAKE_THREAD: 71 case IRQ_WAKE_THREAD:
70 /* 72 /*
71 * Set result to handled so the spurious check 73 * Set result to handled so the spurious check
72 * does not trigger. 74 * does not trigger.
73 */ 75 */
74 ret = IRQ_HANDLED; 76 res = IRQ_HANDLED;
75 77
76 /* 78 /*
77 * Catch drivers which return WAKE_THREAD but 79 * Catch drivers which return WAKE_THREAD but
@@ -105,7 +107,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
105 break; 107 break;
106 } 108 }
107 109
108 retval |= ret; 110 retval |= res;
109 action = action->next; 111 action = action->next;
110 } while (action); 112 } while (action);
111 113
@@ -113,7 +115,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
113 add_interrupt_randomness(irq); 115 add_interrupt_randomness(irq);
114 116
115 if (!noirqdebug) 117 if (!noirqdebug)
116 note_interrupt(irq, desc, ret); 118 note_interrupt(irq, desc, retval);
117 return retval; 119 return retval;
118} 120}
119 121