lkml.org 
[lkml]   [2012]   [Mar]   [9]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    Date
    From
    Subject[ 23/95] genirq: Clear action->thread_mask if IRQ_ONESHOT is not set
    3.2-stable review patch.  If anyone has any objections, please let me know.

    ------------------

    From: Thomas Gleixner <tglx@linutronix.de>

    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>

    ---
    kernel/irq/manage.c | 44 ++++++++++++++++++++++++++++++++++++++------
    1 file changed, 38 insertions(+), 6 deletions(-)

    --- a/kernel/irq/manage.c
    +++ b/kernel/irq/manage.c
    @@ -985,6 +985,11 @@ __setup_irq(unsigned int irq, struct irq

    /* add new interrupt at end of irq queue */
    do {
    + /*
    + * Or all existing action->thread_mask bits,
    + * so we can find the next zero bit for this
    + * new action.
    + */
    thread_mask |= old->thread_mask;
    old_ptr = &old->next;
    old = *old_ptr;
    @@ -993,14 +998,41 @@ __setup_irq(unsigned int irq, struct irq
    }

    /*
    - * Setup the thread mask for this irqaction. Unlikely to have
    - * 32 resp 64 irqs sharing one line, but who knows.
    + * Setup the thread mask for this irqaction for ONESHOT. For
    + * !ONESHOT irqs the thread mask is 0 so we can avoid a
    + * conditional in irq_wake_thread().
    */
    - if (new->flags & IRQF_ONESHOT && thread_mask == ~0UL) {
    - ret = -EBUSY;
    - goto out_mask;
    + if (new->flags & IRQF_ONESHOT) {
    + /*
    + * Unlikely to have 32 resp 64 irqs sharing one line,
    + * but who knows.
    + */
    + if (thread_mask == ~0UL) {
    + ret = -EBUSY;
    + goto out_mask;
    + }
    + /*
    + * The thread_mask for the action is or'ed to
    + * desc->thread_active to indicate that the
    + * IRQF_ONESHOT thread handler has been woken, but not
    + * yet finished. The bit is cleared when a thread
    + * completes. When all threads of a shared interrupt
    + * line have completed desc->threads_active becomes
    + * zero and the interrupt line is unmasked. See
    + * handle.c:irq_wake_thread() for further information.
    + *
    + * If no thread is woken by primary (hard irq context)
    + * interrupt handlers, then desc->threads_active is
    + * also checked for zero to unmask the irq line in the
    + * affected hard irq flow handlers
    + * (handle_[fasteoi|level]_irq).
    + *
    + * The new action gets the first zero bit of
    + * thread_mask assigned. See the loop above which or's
    + * all existing action->thread_mask bits.
    + */
    + new->thread_mask = 1 << ffz(thread_mask);
    }
    - new->thread_mask = 1 << ffz(thread_mask);

    if (!shared) {
    init_waitqueue_head(&desc->wait_for_threads);



    \
     
     \ /
      Last update: 2012-03-09 20:51    [W:0.024 / U:29.936 seconds]
    ©2003-2016 Jasper Spaans. hosted at Digital OceanAdvertise on this site