| From: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| Date: Wed, 20 Jan 2016 15:39:05 +0100 |
| Subject: 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> |
| --- |
| include/linux/interrupt.h | 8 ++++++++ |
| kernel/softirq.c | 21 +++++++++++++++++++++ |
| net/core/dev.c | 2 +- |
| 3 files changed, 30 insertions(+), 1 deletion(-) |
| |
| --- a/include/linux/interrupt.h |
| +++ b/include/linux/interrupt.h |
| @@ -508,6 +508,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); |
| --- a/kernel/softirq.c |
| +++ b/kernel/softirq.c |
| @@ -686,6 +686,27 @@ void __raise_softirq_irqoff(unsigned int |
| } |
| |
| /* |
| + * 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) |
| --- a/net/core/dev.c |
| +++ b/net/core/dev.c |
| @@ -5378,7 +5378,7 @@ static __latent_entropy void net_rx_acti |
| 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); |
| out: |