diff options
author | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2016-01-20 15:39:05 +0100 |
---|---|---|
committer | Sebastian Andrzej Siewior <bigeasy@linutronix.de> | 2016-02-13 00:36:23 +0100 |
commit | 3da35b10afa4e352acd8e5fe8ef94eb1ae87053b (patch) | |
tree | 8231a1e4f4f0082a4e78f82186f64b6ab4218e2c | |
parent | b2a4dd2ff01ea79757100a2c846c0a957213288c (diff) | |
download | rt-linux-3da35b10afa4e352acd8e5fe8ef94eb1ae87053b.tar.gz |
net: provide a way to delegate processing a softirq to ksoftirqd
If the NET_RX uses up all of his budget it moves the following NAPI
invocations into the `ksoftirqd`. On -RT it does not do so. Instead it
rises the NET_RX softirq in its current context again.
In order to get closer to mainline's behaviour this patch provides
__raise_softirq_irqoff_ksoft() which raises the softirq in the ksoftird.
Cc: stable-rt@vger.kernel.org
Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
-rw-r--r-- | include/linux/interrupt.h | 8 | ||||
-rw-r--r-- | kernel/softirq.c | 21 | ||||
-rw-r--r-- | net/core/dev.c | 2 |
3 files changed, 30 insertions, 1 deletions
diff --git a/include/linux/interrupt.h b/include/linux/interrupt.h index 79a9622b5a38c..655cee096aed0 100644 --- a/include/linux/interrupt.h +++ b/include/linux/interrupt.h @@ -465,6 +465,14 @@ extern void thread_do_softirq(void); extern void open_softirq(int nr, void (*action)(struct softirq_action *)); extern void softirq_init(void); extern void __raise_softirq_irqoff(unsigned int nr); +#ifdef CONFIG_PREEMPT_RT_FULL +extern void __raise_softirq_irqoff_ksoft(unsigned int nr); +#else +static inline void __raise_softirq_irqoff_ksoft(unsigned int nr) +{ + __raise_softirq_irqoff(nr); +} +#endif extern void raise_softirq_irqoff(unsigned int nr); extern void raise_softirq(unsigned int nr); diff --git a/kernel/softirq.c b/kernel/softirq.c index be746d82608ba..2ca63cc1469e6 100644 --- a/kernel/softirq.c +++ b/kernel/softirq.c @@ -675,6 +675,27 @@ void __raise_softirq_irqoff(unsigned int nr) } /* + * Same as __raise_softirq_irqoff() but will process them in ksoftirqd + */ +void __raise_softirq_irqoff_ksoft(unsigned int nr) +{ + unsigned int mask; + + if (WARN_ON_ONCE(!__this_cpu_read(ksoftirqd) || + !__this_cpu_read(ktimer_softirqd))) + return; + mask = 1UL << nr; + + trace_softirq_raise(nr); + or_softirq_pending(mask); + if (mask & TIMER_SOFTIRQS) + __this_cpu_read(ktimer_softirqd)->softirqs_raised |= mask; + else + __this_cpu_read(ksoftirqd)->softirqs_raised |= mask; + wakeup_proper_softirq(nr); +} + +/* * This function must run with irqs disabled! */ void raise_softirq_irqoff(unsigned int nr) diff --git a/net/core/dev.c b/net/core/dev.c index acb414aeeaa38..ca1c88ceaddd6 100644 --- a/net/core/dev.c +++ b/net/core/dev.c @@ -4924,7 +4924,7 @@ static void net_rx_action(struct softirq_action *h) list_splice_tail(&repoll, &list); list_splice(&list, &sd->poll_list); if (!list_empty(&sd->poll_list)) - __raise_softirq_irqoff(NET_RX_SOFTIRQ); + __raise_softirq_irqoff_ksoft(NET_RX_SOFTIRQ); net_rps_action_and_irq_enable(sd); } |