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>
This commit is contained in:
@@ -54,24 +54,26 @@ static void warn_no_thread(unsigned int irq, struct irqaction *action)
|
|||||||
irqreturn_t
|
irqreturn_t
|
||||||
handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
|
handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
|
||||||
{
|
{
|
||||||
irqreturn_t ret, retval = IRQ_NONE;
|
irqreturn_t retval = IRQ_NONE;
|
||||||
unsigned int random = 0, irq = desc->irq_data.irq;
|
unsigned int random = 0, irq = desc->irq_data.irq;
|
||||||
|
|
||||||
do {
|
do {
|
||||||
|
irqreturn_t res;
|
||||||
|
|
||||||
trace_irq_handler_entry(irq, action);
|
trace_irq_handler_entry(irq, action);
|
||||||
ret = action->handler(irq, action->dev_id);
|
res = action->handler(irq, action->dev_id);
|
||||||
trace_irq_handler_exit(irq, action, ret);
|
trace_irq_handler_exit(irq, action, res);
|
||||||
|
|
||||||
if (WARN_ON_ONCE(!irqs_disabled()))
|
if (WARN_ON_ONCE(!irqs_disabled()))
|
||||||
local_irq_disable();
|
local_irq_disable();
|
||||||
|
|
||||||
switch (ret) {
|
switch (res) {
|
||||||
case IRQ_WAKE_THREAD:
|
case IRQ_WAKE_THREAD:
|
||||||
/*
|
/*
|
||||||
* Set result to handled so the spurious check
|
* Set result to handled so the spurious check
|
||||||
* does not trigger.
|
* does not trigger.
|
||||||
*/
|
*/
|
||||||
ret = IRQ_HANDLED;
|
res = IRQ_HANDLED;
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Catch drivers which return WAKE_THREAD but
|
* Catch drivers which return WAKE_THREAD but
|
||||||
@@ -105,7 +107,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
retval |= ret;
|
retval |= res;
|
||||||
action = action->next;
|
action = action->next;
|
||||||
} while (action);
|
} while (action);
|
||||||
|
|
||||||
@@ -113,7 +115,7 @@ handle_irq_event_percpu(struct irq_desc *desc, struct irqaction *action)
|
|||||||
add_interrupt_randomness(irq);
|
add_interrupt_randomness(irq);
|
||||||
|
|
||||||
if (!noirqdebug)
|
if (!noirqdebug)
|
||||||
note_interrupt(irq, desc, ret);
|
note_interrupt(irq, desc, retval);
|
||||||
return retval;
|
return retval;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user