diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 10:06:00 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-04-27 10:06:00 +0000 |
commit | b15a952c52a6825376d3e7f6c1bf5c886c6d8b74 (patch) | |
tree | 1500f2f8f276908a36d8126cb632c0d6b1276764 /debian/patches-rt/0307-irq_work-Allow-irq_work_sync-to-sleep-if-irq_work-no.patch | |
parent | Adding upstream version 5.10.209. (diff) | |
download | linux-debian.tar.xz linux-debian.zip |
Adding debian version 5.10.209-2.debian/5.10.209-2debian
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'debian/patches-rt/0307-irq_work-Allow-irq_work_sync-to-sleep-if-irq_work-no.patch')
-rw-r--r-- | debian/patches-rt/0307-irq_work-Allow-irq_work_sync-to-sleep-if-irq_work-no.patch | 100 |
1 files changed, 100 insertions, 0 deletions
diff --git a/debian/patches-rt/0307-irq_work-Allow-irq_work_sync-to-sleep-if-irq_work-no.patch b/debian/patches-rt/0307-irq_work-Allow-irq_work_sync-to-sleep-if-irq_work-no.patch new file mode 100644 index 000000000..2c0ed1db3 --- /dev/null +++ b/debian/patches-rt/0307-irq_work-Allow-irq_work_sync-to-sleep-if-irq_work-no.patch @@ -0,0 +1,100 @@ +From cf4bb976aef7af85b7134aa7cffdfa8e058dc5c6 Mon Sep 17 00:00:00 2001 +From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> +Date: Wed, 24 Nov 2021 17:12:19 +0100 +Subject: [PATCH 307/323] irq_work: Allow irq_work_sync() to sleep if + irq_work() no IRQ support. +Origin: https://www.kernel.org/pub/linux/kernel/projects/rt/5.10/older/patches-5.10.204-rt100.tar.xz + +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> +Signed-off-by: Peter Zijlstra (Intel) <peterz@infradead.org> +Link: https://lkml.kernel.org/r/20211006111852.1514359-3-bigeasy@linutronix.de +Signed-off-by: Steven Rostedt (VMware) <rostedt@goodmis.org> +--- + include/linux/irq_work.h | 10 +++++++++- + kernel/irq_work.c | 10 ++++++++++ + 2 files changed, 19 insertions(+), 1 deletion(-) + +diff --git a/include/linux/irq_work.h b/include/linux/irq_work.h +index f941f2d7d71c..3c6d3a96bca0 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: +@@ -22,6 +23,7 @@ struct irq_work { + }; + }; + void (*func)(struct irq_work *); ++ struct rcuwait irqwait; + }; + + static inline +@@ -29,13 +31,19 @@ void init_irq_work(struct irq_work *work, void (*func)(struct irq_work *)) + { + atomic_set(&work->flags, 0); + work->func = func; ++ rcuwait_init(&work->irqwait); + } + + #define DEFINE_IRQ_WORK(name, _f) struct irq_work name = { \ + .flags = ATOMIC_INIT(0), \ +- .func = (_f) \ ++ .func = (_f), \ ++ .irqwait = __RCUWAIT_INITIALIZER(irqwait), \ + } + ++static inline bool irq_work_is_busy(struct irq_work *work) ++{ ++ return atomic_read(&work->flags) & IRQ_WORK_BUSY; ++} + + bool irq_work_queue(struct irq_work *work); + bool irq_work_queue_on(struct irq_work *work, int cpu); +diff --git a/kernel/irq_work.c b/kernel/irq_work.c +index 8183d30e1bb1..8969aff790e2 100644 +--- a/kernel/irq_work.c ++++ b/kernel/irq_work.c +@@ -165,6 +165,9 @@ void irq_work_single(void *arg) + */ + flags &= ~IRQ_WORK_PENDING; + (void)atomic_cmpxchg(&work->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) +@@ -231,6 +234,13 @@ void irq_work_tick_soft(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 (atomic_read(&work->flags) & IRQ_WORK_BUSY) + cpu_relax(); +-- +2.43.0 + |