blob: 1ed1c55aa2a75bc1243116c047dd04c10e16d459 [file] [log] [blame]
Thomas Gleixner767a67b2019-06-01 10:08:44 +02001// SPDX-License-Identifier: GPL-2.0-only
Linus Torvalds1da177e2005-04-16 15:20:36 -07002/*
3 * linux/kernel/softirq.c
4 *
5 * Copyright (C) 1992 Linus Torvalds
6 *
Pavel Machekb10db7f2008-01-30 13:30:00 +01007 * Rewritten. Old one was good in 2.2, but in 2.3 it was immoral. --ANK (990903)
Linus Torvalds1da177e2005-04-16 15:20:36 -07008 */
9
Joe Perches40322762014-01-27 17:07:15 -080010#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
Paul Gortmaker9984de12011-05-23 14:51:41 -040012#include <linux/export.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070013#include <linux/kernel_stat.h>
14#include <linux/interrupt.h>
15#include <linux/init.h>
Thomas Gleixner8b1c04a2021-03-09 09:55:56 +010016#include <linux/local_lock.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070017#include <linux/mm.h>
18#include <linux/notifier.h>
19#include <linux/percpu.h>
20#include <linux/cpu.h>
Rafael J. Wysocki83144182007-07-17 04:03:35 -070021#include <linux/freezer.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070022#include <linux/kthread.h>
23#include <linux/rcupdate.h>
Steven Rostedt7e49fcc2009-01-22 19:01:40 -050024#include <linux/ftrace.h>
Andrew Morton78eef012006-03-22 00:08:16 -080025#include <linux/smp.h>
Thomas Gleixner3e339b52012-07-16 10:42:37 +000026#include <linux/smpboot.h>
Thomas Gleixner79bf2bb2007-02-16 01:28:03 -080027#include <linux/tick.h>
Thomas Gleixnerd5326762014-03-19 11:19:52 +010028#include <linux/irq.h>
Peter Zijlstrada0447472021-03-09 09:42:08 +010029#include <linux/wait_bit.h>
Heiko Carstensa0e39ed2009-04-29 13:51:39 +020030
Thomas Gleixnerdb1cc7a2021-02-10 00:40:53 +010031#include <asm/softirq_stack.h>
32
Heiko Carstensa0e39ed2009-04-29 13:51:39 +020033#define CREATE_TRACE_POINTS
Steven Rostedtad8d75f2009-04-14 19:39:12 -040034#include <trace/events/irq.h>
Linus Torvalds1da177e2005-04-16 15:20:36 -070035
Linus Torvalds1da177e2005-04-16 15:20:36 -070036/*
37 - No shared variables, all the data are CPU local.
38 - If a softirq needs serialization, let it serialize itself
39 by its own spinlocks.
40 - Even if softirq is serialized, only local cpu is marked for
41 execution. Hence, we get something sort of weak cpu binding.
42 Though it is still not clear, will it result in better locality
43 or will not.
44
45 Examples:
46 - NET RX softirq. It is multithreaded and does not require
47 any global serialization.
48 - NET TX softirq. It kicks software netdevice queues, hence
49 it is logically serialized per device, but this serialization
50 is invisible to common code.
51 - Tasklets: serialized wrt itself.
52 */
53
54#ifndef __ARCH_IRQ_STAT
Frederic Weisbecker0f6f47b2018-05-08 15:38:19 +020055DEFINE_PER_CPU_ALIGNED(irq_cpustat_t, irq_stat);
56EXPORT_PER_CPU_SYMBOL(irq_stat);
Linus Torvalds1da177e2005-04-16 15:20:36 -070057#endif
58
Alexey Dobriyan978b0112008-09-06 20:04:36 +020059static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
Linus Torvalds1da177e2005-04-16 15:20:36 -070060
Venkatesh Pallipadi4dd53d82010-12-21 17:09:00 -080061DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070062
Joe Perchesce85b4f2014-01-27 17:07:16 -080063const char * const softirq_to_name[NR_SOFTIRQS] = {
Sagi Grimbergf660f602016-10-10 15:10:51 +030064 "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "IRQ_POLL",
Shaohua Li09223372011-06-14 13:26:25 +080065 "TASKLET", "SCHED", "HRTIMER", "RCU"
Jason Baron5d592b42009-03-12 14:33:36 -040066};
67
Linus Torvalds1da177e2005-04-16 15:20:36 -070068/*
69 * we cannot loop indefinitely here to avoid userspace starvation,
70 * but we also don't want to introduce a worst case 1/HZ latency
71 * to the pending events, so lets the scheduler to balance
72 * the softirq load for us.
73 */
Thomas Gleixner676cb022009-07-20 23:33:49 +020074static void wakeup_softirqd(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -070075{
76 /* Interrupts are disabled: no need to stop preemption */
Christoph Lameter909ea962010-12-08 16:22:55 +010077 struct task_struct *tsk = __this_cpu_read(ksoftirqd);
Linus Torvalds1da177e2005-04-16 15:20:36 -070078
79 if (tsk && tsk->state != TASK_RUNNING)
80 wake_up_process(tsk);
81}
82
83/*
Eric Dumazet4cd13c22016-08-31 10:42:29 -070084 * If ksoftirqd is scheduled, we do not want to process pending softirqs
Linus Torvalds3c537762018-01-08 11:51:04 -080085 * right now. Let ksoftirqd handle this at its own rate, to get fairness,
86 * unless we're doing some of the synchronous softirqs.
Eric Dumazet4cd13c22016-08-31 10:42:29 -070087 */
Linus Torvalds3c537762018-01-08 11:51:04 -080088#define SOFTIRQ_NOW_MASK ((1 << HI_SOFTIRQ) | (1 << TASKLET_SOFTIRQ))
89static bool ksoftirqd_running(unsigned long pending)
Eric Dumazet4cd13c22016-08-31 10:42:29 -070090{
91 struct task_struct *tsk = __this_cpu_read(ksoftirqd);
92
Linus Torvalds3c537762018-01-08 11:51:04 -080093 if (pending & SOFTIRQ_NOW_MASK)
94 return false;
Matthias Kaehlcke1342d802019-01-28 15:46:25 -080095 return tsk && (tsk->state == TASK_RUNNING) &&
96 !__kthread_should_park(tsk);
Eric Dumazet4cd13c22016-08-31 10:42:29 -070097}
98
Thomas Gleixnerae9ef582020-11-13 15:02:18 +010099#ifdef CONFIG_TRACE_IRQFLAGS
100DEFINE_PER_CPU(int, hardirqs_enabled);
101DEFINE_PER_CPU(int, hardirq_context);
102EXPORT_PER_CPU_SYMBOL_GPL(hardirqs_enabled);
103EXPORT_PER_CPU_SYMBOL_GPL(hardirq_context);
104#endif
105
Eric Dumazet4cd13c22016-08-31 10:42:29 -0700106/*
Thomas Gleixner8b1c04a2021-03-09 09:55:56 +0100107 * SOFTIRQ_OFFSET usage:
108 *
109 * On !RT kernels 'count' is the preempt counter, on RT kernels this applies
110 * to a per CPU counter and to task::softirqs_disabled_cnt.
111 *
112 * - count is changed by SOFTIRQ_OFFSET on entering or leaving softirq
113 * processing.
114 *
115 * - count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET)
Venkatesh Pallipadi75e10562010-10-04 17:03:16 -0700116 * on local_bh_disable or local_bh_enable.
Thomas Gleixner8b1c04a2021-03-09 09:55:56 +0100117 *
Venkatesh Pallipadi75e10562010-10-04 17:03:16 -0700118 * This lets us distinguish between whether we are currently processing
119 * softirq and whether we just have bh disabled.
120 */
Thomas Gleixner8b1c04a2021-03-09 09:55:56 +0100121#ifdef CONFIG_PREEMPT_RT
Venkatesh Pallipadi75e10562010-10-04 17:03:16 -0700122
Thomas Gleixnerae9ef582020-11-13 15:02:18 +0100123/*
Thomas Gleixner8b1c04a2021-03-09 09:55:56 +0100124 * RT accounts for BH disabled sections in task::softirqs_disabled_cnt and
125 * also in per CPU softirq_ctrl::cnt. This is necessary to allow tasks in a
126 * softirq disabled section to be preempted.
127 *
128 * The per task counter is used for softirq_count(), in_softirq() and
129 * in_serving_softirqs() because these counts are only valid when the task
130 * holding softirq_ctrl::lock is running.
131 *
132 * The per CPU counter prevents pointless wakeups of ksoftirqd in case that
133 * the task which is in a softirq disabled section is preempted or blocks.
134 */
135struct softirq_ctrl {
136 local_lock_t lock;
137 int cnt;
138};
139
140static DEFINE_PER_CPU(struct softirq_ctrl, softirq_ctrl) = {
141 .lock = INIT_LOCAL_LOCK(softirq_ctrl.lock),
142};
143
144void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
145{
146 unsigned long flags;
147 int newcnt;
148
149 WARN_ON_ONCE(in_hardirq());
150
151 /* First entry of a task into a BH disabled section? */
152 if (!current->softirq_disable_cnt) {
153 if (preemptible()) {
154 local_lock(&softirq_ctrl.lock);
155 /* Required to meet the RCU bottomhalf requirements. */
156 rcu_read_lock();
157 } else {
158 DEBUG_LOCKS_WARN_ON(this_cpu_read(softirq_ctrl.cnt));
159 }
160 }
161
162 /*
163 * Track the per CPU softirq disabled state. On RT this is per CPU
164 * state to allow preemption of bottom half disabled sections.
165 */
166 newcnt = __this_cpu_add_return(softirq_ctrl.cnt, cnt);
167 /*
168 * Reflect the result in the task state to prevent recursion on the
169 * local lock and to make softirq_count() & al work.
170 */
171 current->softirq_disable_cnt = newcnt;
172
173 if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS) && newcnt == cnt) {
174 raw_local_irq_save(flags);
175 lockdep_softirqs_off(ip);
176 raw_local_irq_restore(flags);
177 }
178}
179EXPORT_SYMBOL(__local_bh_disable_ip);
180
181static void __local_bh_enable(unsigned int cnt, bool unlock)
182{
183 unsigned long flags;
184 int newcnt;
185
186 DEBUG_LOCKS_WARN_ON(current->softirq_disable_cnt !=
187 this_cpu_read(softirq_ctrl.cnt));
188
189 if (IS_ENABLED(CONFIG_TRACE_IRQFLAGS) && softirq_count() == cnt) {
190 raw_local_irq_save(flags);
191 lockdep_softirqs_on(_RET_IP_);
192 raw_local_irq_restore(flags);
193 }
194
195 newcnt = __this_cpu_sub_return(softirq_ctrl.cnt, cnt);
196 current->softirq_disable_cnt = newcnt;
197
198 if (!newcnt && unlock) {
199 rcu_read_unlock();
200 local_unlock(&softirq_ctrl.lock);
201 }
202}
203
204void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
205{
206 bool preempt_on = preemptible();
207 unsigned long flags;
208 u32 pending;
209 int curcnt;
210
211 WARN_ON_ONCE(in_irq());
212 lockdep_assert_irqs_enabled();
213
214 local_irq_save(flags);
215 curcnt = __this_cpu_read(softirq_ctrl.cnt);
216
217 /*
218 * If this is not reenabling soft interrupts, no point in trying to
219 * run pending ones.
220 */
221 if (curcnt != cnt)
222 goto out;
223
224 pending = local_softirq_pending();
225 if (!pending || ksoftirqd_running(pending))
226 goto out;
227
228 /*
229 * If this was called from non preemptible context, wake up the
230 * softirq daemon.
231 */
232 if (!preempt_on) {
233 wakeup_softirqd();
234 goto out;
235 }
236
237 /*
238 * Adjust softirq count to SOFTIRQ_OFFSET which makes
239 * in_serving_softirq() become true.
240 */
241 cnt = SOFTIRQ_OFFSET;
242 __local_bh_enable(cnt, false);
243 __do_softirq();
244
245out:
246 __local_bh_enable(cnt, preempt_on);
247 local_irq_restore(flags);
248}
249EXPORT_SYMBOL(__local_bh_enable_ip);
250
251/*
252 * Invoked from ksoftirqd_run() outside of the interrupt disabled section
253 * to acquire the per CPU local lock for reentrancy protection.
254 */
255static inline void ksoftirqd_run_begin(void)
256{
257 __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
258 local_irq_disable();
259}
260
261/* Counterpart to ksoftirqd_run_begin() */
262static inline void ksoftirqd_run_end(void)
263{
264 __local_bh_enable(SOFTIRQ_OFFSET, true);
265 WARN_ON_ONCE(in_interrupt());
266 local_irq_enable();
267}
268
269static inline void softirq_handle_begin(void) { }
270static inline void softirq_handle_end(void) { }
271
272static inline bool should_wake_ksoftirqd(void)
273{
274 return !this_cpu_read(softirq_ctrl.cnt);
275}
276
277static inline void invoke_softirq(void)
278{
279 if (should_wake_ksoftirqd())
280 wakeup_softirqd();
281}
282
283#else /* CONFIG_PREEMPT_RT */
284
285/*
286 * This one is for softirq.c-internal use, where hardirqs are disabled
Thomas Gleixnerae9ef582020-11-13 15:02:18 +0100287 * legitimately:
288 */
Thomas Gleixner8b1c04a2021-03-09 09:55:56 +0100289#ifdef CONFIG_TRACE_IRQFLAGS
Peter Zijlstra0bd3a172013-11-19 16:13:38 +0100290void __local_bh_disable_ip(unsigned long ip, unsigned int cnt)
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700291{
292 unsigned long flags;
293
294 WARN_ON_ONCE(in_irq());
295
296 raw_local_irq_save(flags);
Steven Rostedt7e49fcc2009-01-22 19:01:40 -0500297 /*
Peter Zijlstrabdb43802013-09-10 12:15:23 +0200298 * The preempt tracer hooks into preempt_count_add and will break
Steven Rostedt7e49fcc2009-01-22 19:01:40 -0500299 * lockdep because it calls back into lockdep after SOFTIRQ_OFFSET
300 * is set and before current->softirq_enabled is cleared.
301 * We must manually increment preempt_count here and manually
302 * call the trace_preempt_off later.
303 */
Peter Zijlstrabdb43802013-09-10 12:15:23 +0200304 __preempt_count_add(cnt);
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700305 /*
306 * Were softirqs turned off above:
307 */
Peter Zijlstra9ea4c382013-11-19 16:13:38 +0100308 if (softirq_count() == (cnt & SOFTIRQ_MASK))
Peter Zijlstra0d384532020-03-20 12:56:41 +0100309 lockdep_softirqs_off(ip);
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700310 raw_local_irq_restore(flags);
Steven Rostedt7e49fcc2009-01-22 19:01:40 -0500311
Heiko Carstens0f1ba9a2015-01-07 10:04:41 +0100312 if (preempt_count() == cnt) {
313#ifdef CONFIG_DEBUG_PREEMPT
Sebastian Andrzej Siewiorf904f582016-02-26 14:54:56 +0100314 current->preempt_disable_ip = get_lock_parent_ip();
Heiko Carstens0f1ba9a2015-01-07 10:04:41 +0100315#endif
Sebastian Andrzej Siewiorf904f582016-02-26 14:54:56 +0100316 trace_preempt_off(CALLER_ADDR0, get_lock_parent_ip());
Heiko Carstens0f1ba9a2015-01-07 10:04:41 +0100317 }
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700318}
Peter Zijlstra0bd3a172013-11-19 16:13:38 +0100319EXPORT_SYMBOL(__local_bh_disable_ip);
Tim Chen3c829c32006-07-30 03:04:02 -0700320#endif /* CONFIG_TRACE_IRQFLAGS */
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700321
Venkatesh Pallipadi75e10562010-10-04 17:03:16 -0700322static void __local_bh_enable(unsigned int cnt)
323{
Frederic Weisbeckerf71b74b2017-11-06 16:01:18 +0100324 lockdep_assert_irqs_disabled();
Venkatesh Pallipadi75e10562010-10-04 17:03:16 -0700325
Joel Fernandes (Google)1a63dcd2018-06-07 13:11:43 -0700326 if (preempt_count() == cnt)
327 trace_preempt_on(CALLER_ADDR0, get_lock_parent_ip());
328
Peter Zijlstra9ea4c382013-11-19 16:13:38 +0100329 if (softirq_count() == (cnt & SOFTIRQ_MASK))
Peter Zijlstra0d384532020-03-20 12:56:41 +0100330 lockdep_softirqs_on(_RET_IP_);
Joel Fernandes (Google)1a63dcd2018-06-07 13:11:43 -0700331
332 __preempt_count_sub(cnt);
Venkatesh Pallipadi75e10562010-10-04 17:03:16 -0700333}
334
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700335/*
Paul E. McKenneyc3442692018-03-05 11:29:40 -0800336 * Special-case - softirqs can safely be enabled by __do_softirq(),
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700337 * without processing still-pending softirqs:
338 */
339void _local_bh_enable(void)
340{
Frederic Weisbecker5d60d3e2013-09-24 04:11:35 +0200341 WARN_ON_ONCE(in_irq());
Venkatesh Pallipadi75e10562010-10-04 17:03:16 -0700342 __local_bh_enable(SOFTIRQ_DISABLE_OFFSET);
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700343}
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700344EXPORT_SYMBOL(_local_bh_enable);
345
Peter Zijlstra0bd3a172013-11-19 16:13:38 +0100346void __local_bh_enable_ip(unsigned long ip, unsigned int cnt)
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700347{
Frederic Weisbeckerf71b74b2017-11-06 16:01:18 +0100348 WARN_ON_ONCE(in_irq());
349 lockdep_assert_irqs_enabled();
Tim Chen3c829c32006-07-30 03:04:02 -0700350#ifdef CONFIG_TRACE_IRQFLAGS
Johannes Berg0f476b6d2008-06-18 09:29:37 +0200351 local_irq_disable();
Tim Chen3c829c32006-07-30 03:04:02 -0700352#endif
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700353 /*
354 * Are softirqs going to be turned on now:
355 */
Venkatesh Pallipadi75e10562010-10-04 17:03:16 -0700356 if (softirq_count() == SOFTIRQ_DISABLE_OFFSET)
Peter Zijlstra0d384532020-03-20 12:56:41 +0100357 lockdep_softirqs_on(ip);
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700358 /*
359 * Keep preemption disabled until we are done with
360 * softirq processing:
Joe Perchesce85b4f2014-01-27 17:07:16 -0800361 */
Peter Zijlstra91ea62d2020-12-18 16:39:14 +0100362 __preempt_count_sub(cnt - 1);
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700363
Frederic Weisbecker0bed6982013-09-05 16:14:00 +0200364 if (unlikely(!in_interrupt() && local_softirq_pending())) {
365 /*
366 * Run softirq if any pending. And do it in its own stack
367 * as we may be calling this deep in a task call stack already.
368 */
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700369 do_softirq();
Frederic Weisbecker0bed6982013-09-05 16:14:00 +0200370 }
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700371
Peter Zijlstrabdb43802013-09-10 12:15:23 +0200372 preempt_count_dec();
Tim Chen3c829c32006-07-30 03:04:02 -0700373#ifdef CONFIG_TRACE_IRQFLAGS
Johannes Berg0f476b6d2008-06-18 09:29:37 +0200374 local_irq_enable();
Tim Chen3c829c32006-07-30 03:04:02 -0700375#endif
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700376 preempt_check_resched();
377}
Peter Zijlstra0bd3a172013-11-19 16:13:38 +0100378EXPORT_SYMBOL(__local_bh_enable_ip);
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700379
Thomas Gleixnerf02fc962021-03-09 09:55:55 +0100380static inline void softirq_handle_begin(void)
381{
382 __local_bh_disable_ip(_RET_IP_, SOFTIRQ_OFFSET);
383}
384
385static inline void softirq_handle_end(void)
386{
387 __local_bh_enable(SOFTIRQ_OFFSET);
388 WARN_ON_ONCE(in_interrupt());
389}
390
391static inline void ksoftirqd_run_begin(void)
392{
393 local_irq_disable();
394}
395
396static inline void ksoftirqd_run_end(void)
397{
398 local_irq_enable();
399}
400
401static inline bool should_wake_ksoftirqd(void)
402{
403 return true;
404}
405
Thomas Gleixnerae9ef582020-11-13 15:02:18 +0100406static inline void invoke_softirq(void)
407{
408 if (ksoftirqd_running(local_softirq_pending()))
409 return;
410
411 if (!force_irqthreads) {
412#ifdef CONFIG_HAVE_IRQ_EXIT_ON_IRQ_STACK
413 /*
414 * We can safely execute softirq on the current stack if
415 * it is the irq stack, because it should be near empty
416 * at this stage.
417 */
418 __do_softirq();
419#else
420 /*
421 * Otherwise, irq_exit() is called on the task stack that can
422 * be potentially deep already. So call softirq in its own stack
423 * to prevent from any overrun.
424 */
425 do_softirq_own_stack();
426#endif
427 } else {
428 wakeup_softirqd();
429 }
430}
431
432asmlinkage __visible void do_softirq(void)
433{
434 __u32 pending;
435 unsigned long flags;
436
437 if (in_interrupt())
438 return;
439
440 local_irq_save(flags);
441
442 pending = local_softirq_pending();
443
444 if (pending && !ksoftirqd_running(pending))
445 do_softirq_own_stack();
446
447 local_irq_restore(flags);
448}
449
Thomas Gleixner8b1c04a2021-03-09 09:55:56 +0100450#endif /* !CONFIG_PREEMPT_RT */
451
Ingo Molnarde30a2b2006-07-03 00:24:42 -0700452/*
Ben Greear34376a52013-06-06 14:29:49 -0700453 * We restart softirq processing for at most MAX_SOFTIRQ_RESTART times,
454 * but break the loop if need_resched() is set or after 2 ms.
455 * The MAX_SOFTIRQ_TIME provides a nice upper bound in most cases, but in
456 * certain cases, such as stop_machine(), jiffies may cease to
457 * increment and so we need the MAX_SOFTIRQ_RESTART limit as
458 * well to make sure we eventually return from this method.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700459 *
Eric Dumazetc10d73672013-01-10 15:26:34 -0800460 * These limits have been established via experimentation.
Linus Torvalds1da177e2005-04-16 15:20:36 -0700461 * The two things to balance is latency against fairness -
462 * we want to handle softirqs as soon as possible, but they
463 * should not be able to lock up the box.
464 */
Eric Dumazetc10d73672013-01-10 15:26:34 -0800465#define MAX_SOFTIRQ_TIME msecs_to_jiffies(2)
Ben Greear34376a52013-06-06 14:29:49 -0700466#define MAX_SOFTIRQ_RESTART 10
Linus Torvalds1da177e2005-04-16 15:20:36 -0700467
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100468#ifdef CONFIG_TRACE_IRQFLAGS
469/*
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100470 * When we run softirqs from irq_exit() and thus on the hardirq stack we need
471 * to keep the lockdep irq context tracking as tight as possible in order to
472 * not miss-qualify lock contexts and miss possible deadlocks.
473 */
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100474
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100475static inline bool lockdep_softirq_start(void)
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100476{
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100477 bool in_hardirq = false;
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100478
Peter Zijlstraf9ad4a52020-05-27 13:03:26 +0200479 if (lockdep_hardirq_context()) {
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100480 in_hardirq = true;
Thomas Gleixner2502ec32020-03-20 12:56:40 +0100481 lockdep_hardirq_exit();
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100482 }
483
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100484 lockdep_softirq_enter();
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100485
486 return in_hardirq;
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100487}
488
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100489static inline void lockdep_softirq_end(bool in_hardirq)
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100490{
491 lockdep_softirq_exit();
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100492
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100493 if (in_hardirq)
Thomas Gleixner2502ec32020-03-20 12:56:40 +0100494 lockdep_hardirq_enter();
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100495}
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100496#else
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100497static inline bool lockdep_softirq_start(void) { return false; }
498static inline void lockdep_softirq_end(bool in_hardirq) { }
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100499#endif
500
Alexander Potapenkobe7635e2016-03-25 14:22:05 -0700501asmlinkage __visible void __softirq_entry __do_softirq(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700502{
Eric Dumazetc10d73672013-01-10 15:26:34 -0800503 unsigned long end = jiffies + MAX_SOFTIRQ_TIME;
Mel Gorman907aed42012-07-31 16:44:07 -0700504 unsigned long old_flags = current->flags;
Ben Greear34376a52013-06-06 14:29:49 -0700505 int max_restart = MAX_SOFTIRQ_RESTART;
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100506 struct softirq_action *h;
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100507 bool in_hardirq;
Peter Zijlstraf1a83e62013-11-19 16:42:47 +0100508 __u32 pending;
Joe Perches2e702b92014-01-27 17:07:14 -0800509 int softirq_bit;
Mel Gorman907aed42012-07-31 16:44:07 -0700510
511 /*
Yangtao Lie45506a2018-10-18 10:21:33 -0400512 * Mask out PF_MEMALLOC as the current task context is borrowed for the
513 * softirq. A softirq handled, such as network RX, might set PF_MEMALLOC
514 * again if the socket is related to swapping.
Mel Gorman907aed42012-07-31 16:44:07 -0700515 */
516 current->flags &= ~PF_MEMALLOC;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700517
518 pending = local_softirq_pending();
Paul Mackerras829035fd2006-07-03 00:25:40 -0700519
Thomas Gleixnerf02fc962021-03-09 09:55:55 +0100520 softirq_handle_begin();
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100521 in_hardirq = lockdep_softirq_start();
Frederic Weisbeckerd3759e72020-12-02 12:57:31 +0100522 account_softirq_enter(current);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700523
Linus Torvalds1da177e2005-04-16 15:20:36 -0700524restart:
525 /* Reset the pending bitmask before enabling irqs */
Andi Kleen3f744782005-09-12 18:49:24 +0200526 set_softirq_pending(0);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700527
Andrew Mortonc70f5d62005-07-30 10:22:49 -0700528 local_irq_enable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700529
530 h = softirq_vec;
531
Joe Perches2e702b92014-01-27 17:07:14 -0800532 while ((softirq_bit = ffs(pending))) {
533 unsigned int vec_nr;
534 int prev_count;
Thomas Gleixner8e85b4b2008-10-02 10:50:53 +0200535
Joe Perches2e702b92014-01-27 17:07:14 -0800536 h += softirq_bit - 1;
Thomas Gleixnerf4bc6bb2010-10-19 15:00:13 +0200537
Joe Perches2e702b92014-01-27 17:07:14 -0800538 vec_nr = h - softirq_vec;
539 prev_count = preempt_count();
Thomas Gleixner8e85b4b2008-10-02 10:50:53 +0200540
Joe Perches2e702b92014-01-27 17:07:14 -0800541 kstat_incr_softirqs_this_cpu(vec_nr);
542
543 trace_softirq_entry(vec_nr);
544 h->action(h);
545 trace_softirq_exit(vec_nr);
546 if (unlikely(prev_count != preempt_count())) {
Joe Perches40322762014-01-27 17:07:15 -0800547 pr_err("huh, entered softirq %u %s %p with preempt_count %08x, exited with %08x?\n",
Joe Perches2e702b92014-01-27 17:07:14 -0800548 vec_nr, softirq_to_name[vec_nr], h->action,
549 prev_count, preempt_count());
550 preempt_count_set(prev_count);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700551 }
552 h++;
Joe Perches2e702b92014-01-27 17:07:14 -0800553 pending >>= softirq_bit;
554 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700555
Thomas Gleixner8b1c04a2021-03-09 09:55:56 +0100556 if (!IS_ENABLED(CONFIG_PREEMPT_RT) &&
557 __this_cpu_read(ksoftirqd) == current)
Paul E. McKenneyd28139c2018-06-28 14:45:25 -0700558 rcu_softirq_qs();
Thomas Gleixner8b1c04a2021-03-09 09:55:56 +0100559
Andrew Mortonc70f5d62005-07-30 10:22:49 -0700560 local_irq_disable();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700561
562 pending = local_softirq_pending();
Eric Dumazetc10d73672013-01-10 15:26:34 -0800563 if (pending) {
Ben Greear34376a52013-06-06 14:29:49 -0700564 if (time_before(jiffies, end) && !need_resched() &&
565 --max_restart)
Eric Dumazetc10d73672013-01-10 15:26:34 -0800566 goto restart;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700567
Linus Torvalds1da177e2005-04-16 15:20:36 -0700568 wakeup_softirqd();
Eric Dumazetc10d73672013-01-10 15:26:34 -0800569 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700570
Frederic Weisbeckerd3759e72020-12-02 12:57:31 +0100571 account_softirq_exit(current);
Frederic Weisbecker5c4853b2013-11-20 01:07:34 +0100572 lockdep_softirq_end(in_hardirq);
Thomas Gleixnerf02fc962021-03-09 09:55:55 +0100573 softirq_handle_end();
NeilBrown717a94b2017-04-07 10:03:26 +1000574 current_restore_flags(old_flags, PF_MEMALLOC);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700575}
576
Thomas Gleixner8a6bc472020-05-21 22:05:21 +0200577/**
578 * irq_enter_rcu - Enter an interrupt context with RCU watching
Ingo Molnardde4b2b2007-02-16 01:27:45 -0800579 */
Thomas Gleixner8a6bc472020-05-21 22:05:21 +0200580void irq_enter_rcu(void)
Ingo Molnardde4b2b2007-02-16 01:27:45 -0800581{
Frederic Weisbeckerd14ce742020-12-02 12:57:32 +0100582 __irq_enter_raw();
583
584 if (is_idle_task(current) && (irq_count() == HARDIRQ_OFFSET))
Frederic Weisbecker5acac1b2013-12-04 18:28:20 +0100585 tick_irq_enter();
Frederic Weisbeckerd14ce742020-12-02 12:57:32 +0100586
587 account_hardirq_enter(current);
Ingo Molnardde4b2b2007-02-16 01:27:45 -0800588}
589
Thomas Gleixner8a6bc472020-05-21 22:05:21 +0200590/**
591 * irq_enter - Enter an interrupt context including RCU update
592 */
593void irq_enter(void)
594{
595 rcu_irq_enter();
596 irq_enter_rcu();
597}
598
Frederic Weisbecker67826ea2013-04-20 17:43:13 +0200599static inline void tick_irq_exit(void)
600{
601#ifdef CONFIG_NO_HZ_COMMON
602 int cpu = smp_processor_id();
603
604 /* Make sure that timer wheel updates are propagated */
605 if ((idle_cpu(cpu) && !need_resched()) || tick_nohz_full_cpu(cpu)) {
Frederic Weisbecker0a0e0822018-08-03 15:31:34 +0200606 if (!in_irq())
Frederic Weisbecker67826ea2013-04-20 17:43:13 +0200607 tick_nohz_irq_exit();
608 }
609#endif
610}
611
Peter Zijlstra59bc3002020-05-29 23:27:39 +0200612static inline void __irq_exit_rcu(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700613{
Thomas Gleixner74eed012013-02-20 22:00:48 +0100614#ifndef __ARCH_IRQ_EXIT_IRQS_DISABLED
Frederic Weisbecker4cd5d112013-02-28 20:00:43 +0100615 local_irq_disable();
Thomas Gleixner74eed012013-02-20 22:00:48 +0100616#else
Frederic Weisbeckerf71b74b2017-11-06 16:01:18 +0100617 lockdep_assert_irqs_disabled();
Thomas Gleixner74eed012013-02-20 22:00:48 +0100618#endif
Frederic Weisbeckerd3759e72020-12-02 12:57:31 +0100619 account_hardirq_exit(current);
Peter Zijlstrabdb43802013-09-10 12:15:23 +0200620 preempt_count_sub(HARDIRQ_OFFSET);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700621 if (!in_interrupt() && local_softirq_pending())
622 invoke_softirq();
Thomas Gleixner79bf2bb2007-02-16 01:28:03 -0800623
Frederic Weisbecker67826ea2013-04-20 17:43:13 +0200624 tick_irq_exit();
Thomas Gleixner8a6bc472020-05-21 22:05:21 +0200625}
626
627/**
Peter Zijlstra59bc3002020-05-29 23:27:39 +0200628 * irq_exit_rcu() - Exit an interrupt context without updating RCU
629 *
630 * Also processes softirqs if needed and possible.
631 */
632void irq_exit_rcu(void)
633{
634 __irq_exit_rcu();
635 /* must be last! */
636 lockdep_hardirq_exit();
637}
638
639/**
Thomas Gleixner8a6bc472020-05-21 22:05:21 +0200640 * irq_exit - Exit an interrupt context, update RCU and lockdep
641 *
642 * Also processes softirqs if needed and possible.
643 */
644void irq_exit(void)
645{
Peter Zijlstra59bc3002020-05-29 23:27:39 +0200646 __irq_exit_rcu();
Frederic Weisbecker416eb332011-10-07 16:31:02 -0700647 rcu_irq_exit();
Thomas Gleixner2502ec32020-03-20 12:56:40 +0100648 /* must be last! */
649 lockdep_hardirq_exit();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700650}
651
652/*
653 * This function must run with irqs disabled!
654 */
Harvey Harrison7ad5b3a2008-02-08 04:19:53 -0800655inline void raise_softirq_irqoff(unsigned int nr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700656{
657 __raise_softirq_irqoff(nr);
658
659 /*
660 * If we're in an interrupt or softirq, we're done
661 * (this also catches softirq-disabled code). We will
662 * actually run the softirq once we return from
663 * the irq or softirq.
664 *
665 * Otherwise we wake up ksoftirqd to make sure we
666 * schedule the softirq soon.
667 */
Thomas Gleixnerf02fc962021-03-09 09:55:55 +0100668 if (!in_interrupt() && should_wake_ksoftirqd())
Linus Torvalds1da177e2005-04-16 15:20:36 -0700669 wakeup_softirqd();
670}
671
Harvey Harrison7ad5b3a2008-02-08 04:19:53 -0800672void raise_softirq(unsigned int nr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700673{
674 unsigned long flags;
675
676 local_irq_save(flags);
677 raise_softirq_irqoff(nr);
678 local_irq_restore(flags);
679}
680
Steven Rostedtf0696862012-01-25 20:18:55 -0500681void __raise_softirq_irqoff(unsigned int nr)
682{
Jiafei Pancdabce2e2020-08-14 12:55:22 +0800683 lockdep_assert_irqs_disabled();
Steven Rostedtf0696862012-01-25 20:18:55 -0500684 trace_softirq_raise(nr);
685 or_softirq_pending(1UL << nr);
686}
687
Carlos R. Mafra962cf362008-05-15 11:15:37 -0300688void open_softirq(int nr, void (*action)(struct softirq_action *))
Linus Torvalds1da177e2005-04-16 15:20:36 -0700689{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700690 softirq_vec[nr].action = action;
691}
692
Peter Zijlstra9ba5f002009-07-22 14:18:35 +0200693/*
694 * Tasklets
695 */
Joe Perchesce85b4f2014-01-27 17:07:16 -0800696struct tasklet_head {
Olof Johansson48f20a92008-03-04 15:23:25 -0800697 struct tasklet_struct *head;
698 struct tasklet_struct **tail;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700699};
700
Vegard Nossum4620b492008-06-12 23:21:53 +0200701static DEFINE_PER_CPU(struct tasklet_head, tasklet_vec);
702static DEFINE_PER_CPU(struct tasklet_head, tasklet_hi_vec);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700703
Ingo Molnar6498dda2018-02-27 17:48:07 +0100704static void __tasklet_schedule_common(struct tasklet_struct *t,
705 struct tasklet_head __percpu *headp,
706 unsigned int softirq_nr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700707{
Ingo Molnar6498dda2018-02-27 17:48:07 +0100708 struct tasklet_head *head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700709 unsigned long flags;
710
711 local_irq_save(flags);
Ingo Molnar6498dda2018-02-27 17:48:07 +0100712 head = this_cpu_ptr(headp);
Olof Johansson48f20a92008-03-04 15:23:25 -0800713 t->next = NULL;
Ingo Molnar6498dda2018-02-27 17:48:07 +0100714 *head->tail = t;
715 head->tail = &(t->next);
716 raise_softirq_irqoff(softirq_nr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700717 local_irq_restore(flags);
718}
Ingo Molnar6498dda2018-02-27 17:48:07 +0100719
720void __tasklet_schedule(struct tasklet_struct *t)
721{
722 __tasklet_schedule_common(t, &tasklet_vec,
723 TASKLET_SOFTIRQ);
724}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700725EXPORT_SYMBOL(__tasklet_schedule);
726
Harvey Harrison7ad5b3a2008-02-08 04:19:53 -0800727void __tasklet_hi_schedule(struct tasklet_struct *t)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700728{
Ingo Molnar6498dda2018-02-27 17:48:07 +0100729 __tasklet_schedule_common(t, &tasklet_hi_vec,
730 HI_SOFTIRQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700731}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700732EXPORT_SYMBOL(__tasklet_hi_schedule);
733
Peter Zijlstra697d8c62021-03-09 09:42:09 +0100734static bool tasklet_clear_sched(struct tasklet_struct *t)
Dirk Behme6b2c3392021-03-17 11:20:12 +0100735{
Peter Zijlstra697d8c62021-03-09 09:42:09 +0100736 if (test_and_clear_bit(TASKLET_STATE_SCHED, &t->state)) {
737 wake_up_var(&t->state);
Dirk Behme6b2c3392021-03-17 11:20:12 +0100738 return true;
Peter Zijlstra697d8c62021-03-09 09:42:09 +0100739 }
Dirk Behme6b2c3392021-03-17 11:20:12 +0100740
741 WARN_ONCE(1, "tasklet SCHED state not set: %s %pS\n",
742 t->use_callback ? "callback" : "func",
743 t->use_callback ? (void *)t->callback : (void *)t->func);
744
745 return false;
746}
747
Ingo Molnar82b691b2018-02-27 17:48:08 +0100748static void tasklet_action_common(struct softirq_action *a,
749 struct tasklet_head *tl_head,
750 unsigned int softirq_nr)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700751{
752 struct tasklet_struct *list;
753
754 local_irq_disable();
Ingo Molnar82b691b2018-02-27 17:48:08 +0100755 list = tl_head->head;
756 tl_head->head = NULL;
757 tl_head->tail = &tl_head->head;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700758 local_irq_enable();
759
760 while (list) {
761 struct tasklet_struct *t = list;
762
763 list = list->next;
764
765 if (tasklet_trylock(t)) {
766 if (!atomic_read(&t->count)) {
Peter Zijlstra697d8c62021-03-09 09:42:09 +0100767 if (tasklet_clear_sched(t)) {
Dirk Behme6b2c3392021-03-17 11:20:12 +0100768 if (t->use_callback)
769 t->callback(t);
770 else
771 t->func(t->data);
772 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700773 tasklet_unlock(t);
774 continue;
775 }
776 tasklet_unlock(t);
777 }
778
779 local_irq_disable();
Olof Johansson48f20a92008-03-04 15:23:25 -0800780 t->next = NULL;
Ingo Molnar82b691b2018-02-27 17:48:08 +0100781 *tl_head->tail = t;
782 tl_head->tail = &t->next;
783 __raise_softirq_irqoff(softirq_nr);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700784 local_irq_enable();
785 }
786}
787
Ingo Molnar82b691b2018-02-27 17:48:08 +0100788static __latent_entropy void tasklet_action(struct softirq_action *a)
789{
790 tasklet_action_common(a, this_cpu_ptr(&tasklet_vec), TASKLET_SOFTIRQ);
791}
792
Emese Revfy0766f782016-06-20 20:42:34 +0200793static __latent_entropy void tasklet_hi_action(struct softirq_action *a)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700794{
Ingo Molnar82b691b2018-02-27 17:48:08 +0100795 tasklet_action_common(a, this_cpu_ptr(&tasklet_hi_vec), HI_SOFTIRQ);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700796}
797
Romain Perier12cc9232019-09-29 18:30:13 +0200798void tasklet_setup(struct tasklet_struct *t,
799 void (*callback)(struct tasklet_struct *))
800{
801 t->next = NULL;
802 t->state = 0;
803 atomic_set(&t->count, 0);
804 t->callback = callback;
805 t->use_callback = true;
806 t->data = 0;
807}
808EXPORT_SYMBOL(tasklet_setup);
809
Linus Torvalds1da177e2005-04-16 15:20:36 -0700810void tasklet_init(struct tasklet_struct *t,
811 void (*func)(unsigned long), unsigned long data)
812{
813 t->next = NULL;
814 t->state = 0;
815 atomic_set(&t->count, 0);
816 t->func = func;
Romain Perier12cc9232019-09-29 18:30:13 +0200817 t->use_callback = false;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700818 t->data = data;
819}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700820EXPORT_SYMBOL(tasklet_init);
821
Thomas Gleixnereb2dafb2021-03-09 09:42:10 +0100822#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
823/*
824 * Do not use in new code. Waiting for tasklets from atomic contexts is
825 * error prone and should be avoided.
826 */
827void tasklet_unlock_spin_wait(struct tasklet_struct *t)
828{
829 while (test_bit(TASKLET_STATE_RUN, &(t)->state)) {
830 if (IS_ENABLED(CONFIG_PREEMPT_RT)) {
831 /*
832 * Prevent a live lock when current preempted soft
833 * interrupt processing or prevents ksoftirqd from
834 * running. If the tasklet runs on a different CPU
835 * then this has no effect other than doing the BH
836 * disable/enable dance for nothing.
837 */
838 local_bh_disable();
839 local_bh_enable();
840 } else {
841 cpu_relax();
842 }
843 }
844}
845EXPORT_SYMBOL(tasklet_unlock_spin_wait);
846#endif
847
Linus Torvalds1da177e2005-04-16 15:20:36 -0700848void tasklet_kill(struct tasklet_struct *t)
849{
850 if (in_interrupt())
Joe Perches40322762014-01-27 17:07:15 -0800851 pr_notice("Attempt to kill tasklet from interrupt\n");
Linus Torvalds1da177e2005-04-16 15:20:36 -0700852
Peter Zijlstra697d8c62021-03-09 09:42:09 +0100853 while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state))
854 wait_var_event(&t->state, !test_bit(TASKLET_STATE_SCHED, &t->state));
855
Linus Torvalds1da177e2005-04-16 15:20:36 -0700856 tasklet_unlock_wait(t);
Peter Zijlstra697d8c62021-03-09 09:42:09 +0100857 tasklet_clear_sched(t);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700858}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700859EXPORT_SYMBOL(tasklet_kill);
860
Thomas Gleixnereb2dafb2021-03-09 09:42:10 +0100861#if defined(CONFIG_SMP) || defined(CONFIG_PREEMPT_RT)
Peter Zijlstrada0447472021-03-09 09:42:08 +0100862void tasklet_unlock(struct tasklet_struct *t)
863{
864 smp_mb__before_atomic();
865 clear_bit(TASKLET_STATE_RUN, &t->state);
866 smp_mb__after_atomic();
867 wake_up_var(&t->state);
868}
869EXPORT_SYMBOL_GPL(tasklet_unlock);
870
871void tasklet_unlock_wait(struct tasklet_struct *t)
872{
873 wait_var_event(&t->state, !test_bit(TASKLET_STATE_RUN, &t->state));
874}
875EXPORT_SYMBOL_GPL(tasklet_unlock_wait);
876#endif
877
Linus Torvalds1da177e2005-04-16 15:20:36 -0700878void __init softirq_init(void)
879{
Olof Johansson48f20a92008-03-04 15:23:25 -0800880 int cpu;
881
882 for_each_possible_cpu(cpu) {
883 per_cpu(tasklet_vec, cpu).tail =
884 &per_cpu(tasklet_vec, cpu).head;
885 per_cpu(tasklet_hi_vec, cpu).tail =
886 &per_cpu(tasklet_hi_vec, cpu).head;
887 }
888
Carlos R. Mafra962cf362008-05-15 11:15:37 -0300889 open_softirq(TASKLET_SOFTIRQ, tasklet_action);
890 open_softirq(HI_SOFTIRQ, tasklet_hi_action);
Linus Torvalds1da177e2005-04-16 15:20:36 -0700891}
892
Thomas Gleixner3e339b52012-07-16 10:42:37 +0000893static int ksoftirqd_should_run(unsigned int cpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700894{
Thomas Gleixner3e339b52012-07-16 10:42:37 +0000895 return local_softirq_pending();
896}
Linus Torvalds1da177e2005-04-16 15:20:36 -0700897
Thomas Gleixner3e339b52012-07-16 10:42:37 +0000898static void run_ksoftirqd(unsigned int cpu)
899{
Thomas Gleixnerf02fc962021-03-09 09:55:55 +0100900 ksoftirqd_run_begin();
Thomas Gleixner3e339b52012-07-16 10:42:37 +0000901 if (local_softirq_pending()) {
Frederic Weisbecker0bed6982013-09-05 16:14:00 +0200902 /*
903 * We can safely run softirq on inline stack, as we are not deep
904 * in the task stack here.
905 */
Thomas Gleixner3e339b52012-07-16 10:42:37 +0000906 __do_softirq();
Thomas Gleixnerf02fc962021-03-09 09:55:55 +0100907 ksoftirqd_run_end();
Paul E. McKenneyedf22f42017-10-24 08:31:12 -0700908 cond_resched();
Thomas Gleixner3e339b52012-07-16 10:42:37 +0000909 return;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700910 }
Thomas Gleixnerf02fc962021-03-09 09:55:55 +0100911 ksoftirqd_run_end();
Linus Torvalds1da177e2005-04-16 15:20:36 -0700912}
913
914#ifdef CONFIG_HOTPLUG_CPU
Sebastian Andrzej Siewiorc4544db2016-08-18 14:57:21 +0200915static int takeover_tasklets(unsigned int cpu)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700916{
Linus Torvalds1da177e2005-04-16 15:20:36 -0700917 /* CPU is dead, so no lock needed. */
918 local_irq_disable();
919
920 /* Find end, append list for that CPU. */
Christian Borntraegere5e41722008-05-01 04:34:23 -0700921 if (&per_cpu(tasklet_vec, cpu).head != per_cpu(tasklet_vec, cpu).tail) {
Christoph Lameter909ea962010-12-08 16:22:55 +0100922 *__this_cpu_read(tasklet_vec.tail) = per_cpu(tasklet_vec, cpu).head;
Muchun Song8afecaa2019-06-18 22:33:05 +0800923 __this_cpu_write(tasklet_vec.tail, per_cpu(tasklet_vec, cpu).tail);
Christian Borntraegere5e41722008-05-01 04:34:23 -0700924 per_cpu(tasklet_vec, cpu).head = NULL;
925 per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
926 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700927 raise_softirq_irqoff(TASKLET_SOFTIRQ);
928
Christian Borntraegere5e41722008-05-01 04:34:23 -0700929 if (&per_cpu(tasklet_hi_vec, cpu).head != per_cpu(tasklet_hi_vec, cpu).tail) {
Christoph Lameter909ea962010-12-08 16:22:55 +0100930 *__this_cpu_read(tasklet_hi_vec.tail) = per_cpu(tasklet_hi_vec, cpu).head;
931 __this_cpu_write(tasklet_hi_vec.tail, per_cpu(tasklet_hi_vec, cpu).tail);
Christian Borntraegere5e41722008-05-01 04:34:23 -0700932 per_cpu(tasklet_hi_vec, cpu).head = NULL;
933 per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head;
934 }
Linus Torvalds1da177e2005-04-16 15:20:36 -0700935 raise_softirq_irqoff(HI_SOFTIRQ);
936
937 local_irq_enable();
Sebastian Andrzej Siewiorc4544db2016-08-18 14:57:21 +0200938 return 0;
Linus Torvalds1da177e2005-04-16 15:20:36 -0700939}
Sebastian Andrzej Siewiorc4544db2016-08-18 14:57:21 +0200940#else
941#define takeover_tasklets NULL
Linus Torvalds1da177e2005-04-16 15:20:36 -0700942#endif /* CONFIG_HOTPLUG_CPU */
943
Thomas Gleixner3e339b52012-07-16 10:42:37 +0000944static struct smp_hotplug_thread softirq_threads = {
945 .store = &ksoftirqd,
946 .thread_should_run = ksoftirqd_should_run,
947 .thread_fn = run_ksoftirqd,
948 .thread_comm = "ksoftirqd/%u",
949};
950
Eduard - Gabriel Munteanu7babe8d2008-07-25 19:45:11 -0700951static __init int spawn_ksoftirqd(void)
Linus Torvalds1da177e2005-04-16 15:20:36 -0700952{
Sebastian Andrzej Siewiorc4544db2016-08-18 14:57:21 +0200953 cpuhp_setup_state_nocalls(CPUHP_SOFTIRQ_DEAD, "softirq:dead", NULL,
954 takeover_tasklets);
Thomas Gleixner3e339b52012-07-16 10:42:37 +0000955 BUG_ON(smpboot_register_percpu_thread(&softirq_threads));
956
Linus Torvalds1da177e2005-04-16 15:20:36 -0700957 return 0;
958}
Eduard - Gabriel Munteanu7babe8d2008-07-25 19:45:11 -0700959early_initcall(spawn_ksoftirqd);
Andrew Morton78eef012006-03-22 00:08:16 -0800960
Yinghai Lu43a25632008-12-28 16:01:13 -0800961/*
962 * [ These __weak aliases are kept in a separate compilation unit, so that
963 * GCC does not inline them incorrectly. ]
964 */
965
966int __init __weak early_irq_init(void)
967{
968 return 0;
969}
970
Yinghai Lu4a046d12009-01-12 17:39:24 -0800971int __init __weak arch_probe_nr_irqs(void)
972{
Thomas Gleixnerb683de22010-09-27 20:55:03 +0200973 return NR_IRQS_LEGACY;
Yinghai Lu4a046d12009-01-12 17:39:24 -0800974}
975
Yinghai Lu43a25632008-12-28 16:01:13 -0800976int __init __weak arch_early_irq_init(void)
977{
978 return 0;
979}
Thomas Gleixner62a08ae2014-04-24 09:50:53 +0200980
981unsigned int __weak arch_dynirq_lower_bound(unsigned int from)
982{
983 return from;
984}