aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2012-02-07 11:58:03 -0500
committerThomas Gleixner <tglx@linutronix.de>2012-02-15 05:56:59 -0500
commitac5637611150281f398bb7a47e3fcb69a09e7803 (patch)
treeb23a336c4409ad3cf00f211f0c709c8c757d9fd3 /kernel/irq
parent7ada1dd62804ca9ce1cb8666c6e563cd92fa50c1 (diff)
genirq: Unmask oneshot irqs when thread was not woken
When the primary handler of an interrupt which is marked IRQ_ONESHOT returns IRQ_HANDLED or IRQ_NONE, then the interrupt thread is not woken and the unmask logic of the interrupt line is never invoked. This keeps the interrupt masked forever. This was not noticed as most IRQ_ONESHOT users wake the thread unconditionally (usually because they cannot access the underlying device from hard interrupt context). Though this behaviour was nowhere documented and not necessarily intentional. Some drivers can avoid the thread wakeup in certain cases and run into the situation where the interrupt line s kept masked. Handle it gracefully. Reported-and-tested-by: Lothar Wassmann <lw@karo-electronics.de> Cc: stable@vger.kernel.org Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Diffstat (limited to 'kernel/irq')
-rw-r--r--kernel/irq/chip.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/kernel/irq/chip.c b/kernel/irq/chip.c
index f7c543a801d9..b742edc0bdd4 100644
--- a/kernel/irq/chip.c
+++ b/kernel/irq/chip.c
@@ -330,6 +330,24 @@ out_unlock:
330} 330}
331EXPORT_SYMBOL_GPL(handle_simple_irq); 331EXPORT_SYMBOL_GPL(handle_simple_irq);
332 332
333/*
334 * Called unconditionally from handle_level_irq() and only for oneshot
335 * interrupts from handle_fasteoi_irq()
336 */
337static void cond_unmask_irq(struct irq_desc *desc)
338{
339 /*
340 * We need to unmask in the following cases:
341 * - Standard level irq (IRQF_ONESHOT is not set)
342 * - Oneshot irq which did not wake the thread (caused by a
343 * spurious interrupt or a primary handler handling it
344 * completely).
345 */
346 if (!irqd_irq_disabled(&desc->irq_data) &&
347 irqd_irq_masked(&desc->irq_data) && !desc->threads_oneshot)
348 unmask_irq(desc);
349}
350
333/** 351/**
334 * handle_level_irq - Level type irq handler 352 * handle_level_irq - Level type irq handler
335 * @irq: the interrupt number 353 * @irq: the interrupt number
@@ -362,8 +380,8 @@ handle_level_irq(unsigned int irq, struct irq_desc *desc)
362 380
363 handle_irq_event(desc); 381 handle_irq_event(desc);
364 382
365 if (!irqd_irq_disabled(&desc->irq_data) && !(desc->istate & IRQS_ONESHOT)) 383 cond_unmask_irq(desc);
366 unmask_irq(desc); 384
367out_unlock: 385out_unlock:
368 raw_spin_unlock(&desc->lock); 386 raw_spin_unlock(&desc->lock);
369} 387}
@@ -417,6 +435,9 @@ handle_fasteoi_irq(unsigned int irq, struct irq_desc *desc)
417 preflow_handler(desc); 435 preflow_handler(desc);
418 handle_irq_event(desc); 436 handle_irq_event(desc);
419 437
438 if (desc->istate & IRQS_ONESHOT)
439 cond_unmask_irq(desc);
440
420out_eoi: 441out_eoi:
421 desc->irq_data.chip->irq_eoi(&desc->irq_data); 442 desc->irq_data.chip->irq_eoi(&desc->irq_data);
422out_unlock: 443out_unlock: