aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/irq/manage.c
diff options
context:
space:
mode:
authorThomas Gleixner <tglx@linutronix.de>2012-03-06 17:18:54 -0500
committerLuis Henriques <luis.henriques@canonical.com>2012-03-26 05:26:51 -0400
commitfdb0f08a199ec80276586872d0df9e1072057732 (patch)
treef6c1eae3c3c3749a12b66db6b3cf6c5e647e1875 /kernel/irq/manage.c
parent30a7a8f897757abd8f7fbbf4aed70f61fbf8de2d (diff)
genirq: Clear action->thread_mask if IRQ_ONESHOT is not set
BugLink: http://bugs.launchpad.net/bugs/954576 commit 52abb700e16a9aa4cbc03f3d7f80206cbbc80680 upstream. Xommit ac5637611(genirq: Unmask oneshot irqs when thread was not woken) fails to unmask when a !IRQ_ONESHOT threaded handler is handled by handle_level_irq. This happens because thread_mask is or'ed unconditionally in irq_wake_thread(), but for !IRQ_ONESHOT interrupts never cleared. So the check for !desc->thread_active fails and keeps the interrupt disabled. Keep the thread_mask zero for !IRQ_ONESHOT interrupts. Document the thread_mask magic while at it. Reported-and-tested-by: Sven Joachim <svenjoac@gmx.de> Reported-and-tested-by: Stefan Lippers-Hollmann <s.l-h@gmx.de> Signed-off-by: Thomas Gleixner <tglx@linutronix.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'kernel/irq/manage.c')
-rw-r--r--kernel/irq/manage.c44
1 files changed, 38 insertions, 6 deletions
diff --git a/kernel/irq/manage.c b/kernel/irq/manage.c
index def3406fb43..e4eedb16197 100644
--- a/kernel/irq/manage.c
+++ b/kernel/irq/manage.c
@@ -976,6 +976,11 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
976 976
977 /* add new interrupt at end of irq queue */ 977 /* add new interrupt at end of irq queue */
978 do { 978 do {
979 /*
980 * Or all existing action->thread_mask bits,
981 * so we can find the next zero bit for this
982 * new action.
983 */
979 thread_mask |= old->thread_mask; 984 thread_mask |= old->thread_mask;
980 old_ptr = &old->next; 985 old_ptr = &old->next;
981 old = *old_ptr; 986 old = *old_ptr;
@@ -984,14 +989,41 @@ __setup_irq(unsigned int irq, struct irq_desc *desc, struct irqaction *new)
984 } 989 }
985 990
986 /* 991 /*
987 * Setup the thread mask for this irqaction. Unlikely to have 992 * Setup the thread mask for this irqaction for ONESHOT. For
988 * 32 resp 64 irqs sharing one line, but who knows. 993 * !ONESHOT irqs the thread mask is 0 so we can avoid a
994 * conditional in irq_wake_thread().
989 */ 995 */
990 if (new->flags & IRQF_ONESHOT && thread_mask == ~0UL) { 996 if (new->flags & IRQF_ONESHOT) {
991 ret = -EBUSY; 997 /*
992 goto out_mask; 998 * Unlikely to have 32 resp 64 irqs sharing one line,
999 * but who knows.
1000 */
1001 if (thread_mask == ~0UL) {
1002 ret = -EBUSY;
1003 goto out_mask;
1004 }
1005 /*
1006 * The thread_mask for the action is or'ed to
1007 * desc->thread_active to indicate that the
1008 * IRQF_ONESHOT thread handler has been woken, but not
1009 * yet finished. The bit is cleared when a thread
1010 * completes. When all threads of a shared interrupt
1011 * line have completed desc->threads_active becomes
1012 * zero and the interrupt line is unmasked. See
1013 * handle.c:irq_wake_thread() for further information.
1014 *
1015 * If no thread is woken by primary (hard irq context)
1016 * interrupt handlers, then desc->threads_active is
1017 * also checked for zero to unmask the irq line in the
1018 * affected hard irq flow handlers
1019 * (handle_[fasteoi|level]_irq).
1020 *
1021 * The new action gets the first zero bit of
1022 * thread_mask assigned. See the loop above which or's
1023 * all existing action->thread_mask bits.
1024 */
1025 new->thread_mask = 1 << ffz(thread_mask);
993 } 1026 }
994 new->thread_mask = 1 << ffz(thread_mask);
995 1027
996 if (!shared) { 1028 if (!shared) {
997 init_waitqueue_head(&desc->wait_for_threads); 1029 init_waitqueue_head(&desc->wait_for_threads);