lkml.org 
[lkml]   [2021]   [Oct]   [6]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v2 2/4] irq_work: Allow irq_work_sync() to sleep if irq_work() no IRQ support.
    Date
    irq_work() triggers instantly an interrupt if supported by the
    architecture. Otherwise the work will be processed on the next timer
    tick. In worst case irq_work_sync() could spin up to a jiffy.

    irq_work_sync() is usually used in tear down context which is fully
    preemptible. Based on review irq_work_sync() is invoked from preemptible
    context and there is one waiter at a time. This qualifies it to use
    rcuwait for synchronisation.

    Let irq_work_sync() synchronize with rcuwait if the architecture
    processes irqwork via the timer tick.

    Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
    ---
    include/linux/irq_work.h | 3 +++
    kernel/irq_work.c | 10 ++++++++++
    2 files changed, 13 insertions(+)

    diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h
    index ec2a47a81e423..b48955e9c920e 100644
    --- a/include/linux/irq_work.h
    +++ b/include/linux/irq_work.h
    @@ -3,6 +3,7 @@
    #define _LINUX_IRQ_WORK_H

    #include <linux/smp_types.h>
    +#include <linux/rcuwait.h>

    /*
    * An entry can be in one of four states:
    @@ -16,11 +17,13 @@
    struct irq_work {
    struct __call_single_node node;
    void (*func)(struct irq_work *);
    + struct rcuwait irqwait;
    };

    #define __IRQ_WORK_INIT(_func, _flags) (struct irq_work){ \
    .node = { .u_flags = (_flags), }, \
    .func = (_func), \
    + .irqwait = __RCUWAIT_INITIALIZER(irqwait), \
    }

    #define IRQ_WORK_INIT(_func) __IRQ_WORK_INIT(_func, 0)
    diff --git a/kernel/irq_work.c b/kernel/irq_work.c
    index db8c248ebc8c8..e789beda8297d 100644
    --- a/kernel/irq_work.c
    +++ b/kernel/irq_work.c
    @@ -160,6 +160,9 @@ void irq_work_single(void *arg)
    * else claimed it meanwhile.
    */
    (void)atomic_cmpxchg(&work->node.a_flags, flags, flags & ~IRQ_WORK_BUSY);
    +
    + if (!arch_irq_work_has_interrupt())
    + rcuwait_wake_up(&work->irqwait);
    }

    static void irq_work_run_list(struct llist_head *list)
    @@ -204,6 +207,13 @@ void irq_work_tick(void)
    void irq_work_sync(struct irq_work *work)
    {
    lockdep_assert_irqs_enabled();
    + might_sleep();
    +
    + if (!arch_irq_work_has_interrupt()) {
    + rcuwait_wait_event(&work->irqwait, !irq_work_is_busy(work),
    + TASK_UNINTERRUPTIBLE);
    + return;
    + }

    while (irq_work_is_busy(work))
    cpu_relax();
    --
    2.33.0
    \
     
     \ /
      Last update: 2021-10-06 13:20    [W:3.264 / U:0.172 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site