aboutsummaryrefslogtreecommitdiffstats
path: root/kernel/softirq.c
diff options
context:
space:
mode:
Diffstat (limited to 'kernel/softirq.c')
-rw-r--r--kernel/softirq.c195
1 files changed, 113 insertions, 82 deletions
diff --git a/kernel/softirq.c b/kernel/softirq.c
index 07b4f1b1a73a..fca82c32042b 100644
--- a/kernel/softirq.c
+++ b/kernel/softirq.c
@@ -54,11 +54,11 @@ EXPORT_SYMBOL(irq_stat);
54 54
55static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp; 55static struct softirq_action softirq_vec[NR_SOFTIRQS] __cacheline_aligned_in_smp;
56 56
57static DEFINE_PER_CPU(struct task_struct *, ksoftirqd); 57DEFINE_PER_CPU(struct task_struct *, ksoftirqd);
58 58
59char *softirq_to_name[NR_SOFTIRQS] = { 59char *softirq_to_name[NR_SOFTIRQS] = {
60 "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL", 60 "HI", "TIMER", "NET_TX", "NET_RX", "BLOCK", "BLOCK_IOPOLL",
61 "TASKLET", "SCHED", "HRTIMER", "RCU" 61 "TASKLET", "SCHED", "HRTIMER", "RCU"
62}; 62};
63 63
64/* 64/*
@@ -67,21 +67,31 @@ char *softirq_to_name[NR_SOFTIRQS] = {
67 * to the pending events, so lets the scheduler to balance 67 * to the pending events, so lets the scheduler to balance
68 * the softirq load for us. 68 * the softirq load for us.
69 */ 69 */
70void wakeup_softirqd(void) 70static void wakeup_softirqd(void)
71{ 71{
72 /* Interrupts are disabled: no need to stop preemption */ 72 /* Interrupts are disabled: no need to stop preemption */
73 struct task_struct *tsk = __get_cpu_var(ksoftirqd); 73 struct task_struct *tsk = __this_cpu_read(ksoftirqd);
74 74
75 if (tsk && tsk->state != TASK_RUNNING) 75 if (tsk && tsk->state != TASK_RUNNING)
76 wake_up_process(tsk); 76 wake_up_process(tsk);
77} 77}
78 78
79/* 79/*
80 * preempt_count and SOFTIRQ_OFFSET usage:
81 * - preempt_count is changed by SOFTIRQ_OFFSET on entering or leaving
82 * softirq processing.
83 * - preempt_count is changed by SOFTIRQ_DISABLE_OFFSET (= 2 * SOFTIRQ_OFFSET)
84 * on local_bh_disable or local_bh_enable.
85 * This lets us distinguish between whether we are currently processing
86 * softirq and whether we just have bh disabled.
87 */
88
89/*
80 * This one is for softirq.c-internal use, 90 * This one is for softirq.c-internal use,
81 * where hardirqs are disabled legitimately: 91 * where hardirqs are disabled legitimately:
82 */ 92 */
83#ifdef CONFIG_TRACE_IRQFLAGS 93#ifdef CONFIG_TRACE_IRQFLAGS
84static void __local_bh_disable(unsigned long ip) 94static void __local_bh_disable(unsigned long ip, unsigned int cnt)
85{ 95{
86 unsigned long flags; 96 unsigned long flags;
87 97
@@ -95,32 +105,43 @@ static void __local_bh_disable(unsigned long ip)
95 * We must manually increment preempt_count here and manually 105 * We must manually increment preempt_count here and manually
96 * call the trace_preempt_off later. 106 * call the trace_preempt_off later.
97 */ 107 */
98 preempt_count() += SOFTIRQ_OFFSET; 108 preempt_count() += cnt;
99 /* 109 /*
100 * Were softirqs turned off above: 110 * Were softirqs turned off above:
101 */ 111 */
102 if (softirq_count() == SOFTIRQ_OFFSET) 112 if (softirq_count() == cnt)
103 trace_softirqs_off(ip); 113 trace_softirqs_off(ip);
104 raw_local_irq_restore(flags); 114 raw_local_irq_restore(flags);
105 115
106 if (preempt_count() == SOFTIRQ_OFFSET) 116 if (preempt_count() == cnt)
107 trace_preempt_off(CALLER_ADDR0, get_parent_ip(CALLER_ADDR1)); 117 trace_preempt_off(CALLER_ADDR0, get_parent_ip(CALLER_ADDR1));
108} 118}
109#else /* !CONFIG_TRACE_IRQFLAGS */ 119#else /* !CONFIG_TRACE_IRQFLAGS */
110static inline void __local_bh_disable(unsigned long ip) 120static inline void __local_bh_disable(unsigned long ip, unsigned int cnt)
111{ 121{
112 add_preempt_count(SOFTIRQ_OFFSET); 122 add_preempt_count(cnt);
113 barrier(); 123 barrier();
114} 124}
115#endif /* CONFIG_TRACE_IRQFLAGS */ 125#endif /* CONFIG_TRACE_IRQFLAGS */
116 126
117void local_bh_disable(void) 127void local_bh_disable(void)
118{ 128{
119 __local_bh_disable((unsigned long)__builtin_return_address(0)); 129 __local_bh_disable((unsigned long)__builtin_return_address(0),
130 SOFTIRQ_DISABLE_OFFSET);
120} 131}
121 132
122EXPORT_SYMBOL(local_bh_disable); 133EXPORT_SYMBOL(local_bh_disable);
123 134
135static void __local_bh_enable(unsigned int cnt)
136{
137 WARN_ON_ONCE(in_irq());
138 WARN_ON_ONCE(!irqs_disabled());
139
140 if (softirq_count() == cnt)
141 trace_softirqs_on((unsigned long)__builtin_return_address(0));
142 sub_preempt_count(cnt);
143}
144
124/* 145/*
125 * Special-case - softirqs can safely be enabled in 146 * Special-case - softirqs can safely be enabled in
126 * cond_resched_softirq(), or by __do_softirq(), 147 * cond_resched_softirq(), or by __do_softirq(),
@@ -128,12 +149,7 @@ EXPORT_SYMBOL(local_bh_disable);
128 */ 149 */
129void _local_bh_enable(void) 150void _local_bh_enable(void)
130{ 151{
131 WARN_ON_ONCE(in_irq()); 152 __local_bh_enable(SOFTIRQ_DISABLE_OFFSET);
132 WARN_ON_ONCE(!irqs_disabled());
133
134 if (softirq_count() == SOFTIRQ_OFFSET)
135 trace_softirqs_on((unsigned long)__builtin_return_address(0));
136 sub_preempt_count(SOFTIRQ_OFFSET);
137} 153}
138 154
139EXPORT_SYMBOL(_local_bh_enable); 155EXPORT_SYMBOL(_local_bh_enable);
@@ -147,13 +163,13 @@ static inline void _local_bh_enable_ip(unsigned long ip)
147 /* 163 /*
148 * Are softirqs going to be turned on now: 164 * Are softirqs going to be turned on now:
149 */ 165 */
150 if (softirq_count() == SOFTIRQ_OFFSET) 166 if (softirq_count() == SOFTIRQ_DISABLE_OFFSET)
151 trace_softirqs_on(ip); 167 trace_softirqs_on(ip);
152 /* 168 /*
153 * Keep preemption disabled until we are done with 169 * Keep preemption disabled until we are done with
154 * softirq processing: 170 * softirq processing:
155 */ 171 */
156 sub_preempt_count(SOFTIRQ_OFFSET - 1); 172 sub_preempt_count(SOFTIRQ_DISABLE_OFFSET - 1);
157 173
158 if (unlikely(!in_interrupt() && local_softirq_pending())) 174 if (unlikely(!in_interrupt() && local_softirq_pending()))
159 do_softirq(); 175 do_softirq();
@@ -198,7 +214,8 @@ asmlinkage void __do_softirq(void)
198 pending = local_softirq_pending(); 214 pending = local_softirq_pending();
199 account_system_vtime(current); 215 account_system_vtime(current);
200 216
201 __local_bh_disable((unsigned long)__builtin_return_address(0)); 217 __local_bh_disable((unsigned long)__builtin_return_address(0),
218 SOFTIRQ_OFFSET);
202 lockdep_softirq_enter(); 219 lockdep_softirq_enter();
203 220
204 cpu = smp_processor_id(); 221 cpu = smp_processor_id();
@@ -212,18 +229,20 @@ restart:
212 229
213 do { 230 do {
214 if (pending & 1) { 231 if (pending & 1) {
232 unsigned int vec_nr = h - softirq_vec;
215 int prev_count = preempt_count(); 233 int prev_count = preempt_count();
216 kstat_incr_softirqs_this_cpu(h - softirq_vec);
217 234
218 trace_softirq_entry(h, softirq_vec); 235 kstat_incr_softirqs_this_cpu(vec_nr);
236
237 trace_softirq_entry(vec_nr);
219 h->action(h); 238 h->action(h);
220 trace_softirq_exit(h, softirq_vec); 239 trace_softirq_exit(vec_nr);
221 if (unlikely(prev_count != preempt_count())) { 240 if (unlikely(prev_count != preempt_count())) {
222 printk(KERN_ERR "huh, entered softirq %td %s %p" 241 printk(KERN_ERR "huh, entered softirq %u %s %p"
223 "with preempt_count %08x," 242 "with preempt_count %08x,"
224 " exited with %08x?\n", h - softirq_vec, 243 " exited with %08x?\n", vec_nr,
225 softirq_to_name[h - softirq_vec], 244 softirq_to_name[vec_nr], h->action,
226 h->action, prev_count, preempt_count()); 245 prev_count, preempt_count());
227 preempt_count() = prev_count; 246 preempt_count() = prev_count;
228 } 247 }
229 248
@@ -245,7 +264,7 @@ restart:
245 lockdep_softirq_exit(); 264 lockdep_softirq_exit();
246 265
247 account_system_vtime(current); 266 account_system_vtime(current);
248 _local_bh_enable(); 267 __local_bh_enable(SOFTIRQ_OFFSET);
249} 268}
250 269
251#ifndef __ARCH_HAS_DO_SOFTIRQ 270#ifndef __ARCH_HAS_DO_SOFTIRQ
@@ -279,16 +298,42 @@ void irq_enter(void)
279 298
280 rcu_irq_enter(); 299 rcu_irq_enter();
281 if (idle_cpu(cpu) && !in_interrupt()) { 300 if (idle_cpu(cpu) && !in_interrupt()) {
282 __irq_enter(); 301 /*
302 * Prevent raise_softirq from needlessly waking up ksoftirqd
303 * here, as softirq will be serviced on return from interrupt.
304 */
305 local_bh_disable();
283 tick_check_idle(cpu); 306 tick_check_idle(cpu);
284 } else 307 _local_bh_enable();
285 __irq_enter(); 308 }
309
310 __irq_enter();
286} 311}
287 312
288#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED 313#ifdef __ARCH_IRQ_EXIT_IRQS_DISABLED
289# define invoke_softirq() __do_softirq() 314static inline void invoke_softirq(void)
315{
316 if (!force_irqthreads)
317 __do_softirq();
318 else {
319 __local_bh_disable((unsigned long)__builtin_return_address(0),
320 SOFTIRQ_OFFSET);
321 wakeup_softirqd();
322 __local_bh_enable(SOFTIRQ_OFFSET);
323 }
324}
290#else 325#else
291# define invoke_softirq() do_softirq() 326static inline void invoke_softirq(void)
327{
328 if (!force_irqthreads)
329 do_softirq();
330 else {
331 __local_bh_disable((unsigned long)__builtin_return_address(0),
332 SOFTIRQ_OFFSET);
333 wakeup_softirqd();
334 __local_bh_enable(SOFTIRQ_OFFSET);
335 }
336}
292#endif 337#endif
293 338
294/* 339/*
@@ -363,8 +408,8 @@ void __tasklet_schedule(struct tasklet_struct *t)
363 408
364 local_irq_save(flags); 409 local_irq_save(flags);
365 t->next = NULL; 410 t->next = NULL;
366 *__get_cpu_var(tasklet_vec).tail = t; 411 *__this_cpu_read(tasklet_vec.tail) = t;
367 __get_cpu_var(tasklet_vec).tail = &(t->next); 412 __this_cpu_write(tasklet_vec.tail, &(t->next));
368 raise_softirq_irqoff(TASKLET_SOFTIRQ); 413 raise_softirq_irqoff(TASKLET_SOFTIRQ);
369 local_irq_restore(flags); 414 local_irq_restore(flags);
370} 415}
@@ -377,8 +422,8 @@ void __tasklet_hi_schedule(struct tasklet_struct *t)
377 422
378 local_irq_save(flags); 423 local_irq_save(flags);
379 t->next = NULL; 424 t->next = NULL;
380 *__get_cpu_var(tasklet_hi_vec).tail = t; 425 *__this_cpu_read(tasklet_hi_vec.tail) = t;
381 __get_cpu_var(tasklet_hi_vec).tail = &(t->next); 426 __this_cpu_write(tasklet_hi_vec.tail, &(t->next));
382 raise_softirq_irqoff(HI_SOFTIRQ); 427 raise_softirq_irqoff(HI_SOFTIRQ);
383 local_irq_restore(flags); 428 local_irq_restore(flags);
384} 429}
@@ -389,8 +434,8 @@ void __tasklet_hi_schedule_first(struct tasklet_struct *t)
389{ 434{
390 BUG_ON(!irqs_disabled()); 435 BUG_ON(!irqs_disabled());
391 436
392 t->next = __get_cpu_var(tasklet_hi_vec).head; 437 t->next = __this_cpu_read(tasklet_hi_vec.head);
393 __get_cpu_var(tasklet_hi_vec).head = t; 438 __this_cpu_write(tasklet_hi_vec.head, t);
394 __raise_softirq_irqoff(HI_SOFTIRQ); 439 __raise_softirq_irqoff(HI_SOFTIRQ);
395} 440}
396 441
@@ -401,9 +446,9 @@ static void tasklet_action(struct softirq_action *a)
401 struct tasklet_struct *list; 446 struct tasklet_struct *list;
402 447
403 local_irq_disable(); 448 local_irq_disable();
404 list = __get_cpu_var(tasklet_vec).head; 449 list = __this_cpu_read(tasklet_vec.head);
405 __get_cpu_var(tasklet_vec).head = NULL; 450 __this_cpu_write(tasklet_vec.head, NULL);
406 __get_cpu_var(tasklet_vec).tail = &__get_cpu_var(tasklet_vec).head; 451 __this_cpu_write(tasklet_vec.tail, &__get_cpu_var(tasklet_vec).head);
407 local_irq_enable(); 452 local_irq_enable();
408 453
409 while (list) { 454 while (list) {
@@ -424,8 +469,8 @@ static void tasklet_action(struct softirq_action *a)
424 469
425 local_irq_disable(); 470 local_irq_disable();
426 t->next = NULL; 471 t->next = NULL;
427 *__get_cpu_var(tasklet_vec).tail = t; 472 *__this_cpu_read(tasklet_vec.tail) = t;
428 __get_cpu_var(tasklet_vec).tail = &(t->next); 473 __this_cpu_write(tasklet_vec.tail, &(t->next));
429 __raise_softirq_irqoff(TASKLET_SOFTIRQ); 474 __raise_softirq_irqoff(TASKLET_SOFTIRQ);
430 local_irq_enable(); 475 local_irq_enable();
431 } 476 }
@@ -436,9 +481,9 @@ static void tasklet_hi_action(struct softirq_action *a)
436 struct tasklet_struct *list; 481 struct tasklet_struct *list;
437 482
438 local_irq_disable(); 483 local_irq_disable();
439 list = __get_cpu_var(tasklet_hi_vec).head; 484 list = __this_cpu_read(tasklet_hi_vec.head);
440 __get_cpu_var(tasklet_hi_vec).head = NULL; 485 __this_cpu_write(tasklet_hi_vec.head, NULL);
441 __get_cpu_var(tasklet_hi_vec).tail = &__get_cpu_var(tasklet_hi_vec).head; 486 __this_cpu_write(tasklet_hi_vec.tail, &__get_cpu_var(tasklet_hi_vec).head);
442 local_irq_enable(); 487 local_irq_enable();
443 488
444 while (list) { 489 while (list) {
@@ -459,8 +504,8 @@ static void tasklet_hi_action(struct softirq_action *a)
459 504
460 local_irq_disable(); 505 local_irq_disable();
461 t->next = NULL; 506 t->next = NULL;
462 *__get_cpu_var(tasklet_hi_vec).tail = t; 507 *__this_cpu_read(tasklet_hi_vec.tail) = t;
463 __get_cpu_var(tasklet_hi_vec).tail = &(t->next); 508 __this_cpu_write(tasklet_hi_vec.tail, &(t->next));
464 __raise_softirq_irqoff(HI_SOFTIRQ); 509 __raise_softirq_irqoff(HI_SOFTIRQ);
465 local_irq_enable(); 510 local_irq_enable();
466 } 511 }
@@ -530,7 +575,7 @@ static void __tasklet_hrtimer_trampoline(unsigned long data)
530/** 575/**
531 * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks 576 * tasklet_hrtimer_init - Init a tasklet/hrtimer combo for softirq callbacks
532 * @ttimer: tasklet_hrtimer which is initialized 577 * @ttimer: tasklet_hrtimer which is initialized
533 * @function: hrtimer callback funtion which gets called from softirq context 578 * @function: hrtimer callback function which gets called from softirq context
534 * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME) 579 * @which_clock: clock id (CLOCK_MONOTONIC/CLOCK_REALTIME)
535 * @mode: hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL) 580 * @mode: hrtimer mode (HRTIMER_MODE_ABS/HRTIMER_MODE_REL)
536 */ 581 */
@@ -712,7 +757,10 @@ static int run_ksoftirqd(void * __bind_cpu)
712 don't process */ 757 don't process */
713 if (cpu_is_offline((long)__bind_cpu)) 758 if (cpu_is_offline((long)__bind_cpu))
714 goto wait_to_die; 759 goto wait_to_die;
715 do_softirq(); 760 local_irq_disable();
761 if (local_softirq_pending())
762 __do_softirq();
763 local_irq_enable();
716 preempt_enable_no_resched(); 764 preempt_enable_no_resched();
717 cond_resched(); 765 cond_resched();
718 preempt_disable(); 766 preempt_disable();
@@ -776,16 +824,16 @@ static void takeover_tasklets(unsigned int cpu)
776 824
777 /* Find end, append list for that CPU. */ 825 /* Find end, append list for that CPU. */
778 if (&per_cpu(tasklet_vec, cpu).head != per_cpu(tasklet_vec, cpu).tail) { 826 if (&per_cpu(tasklet_vec, cpu).head != per_cpu(tasklet_vec, cpu).tail) {
779 *(__get_cpu_var(tasklet_vec).tail) = per_cpu(tasklet_vec, cpu).head; 827 *__this_cpu_read(tasklet_vec.tail) = per_cpu(tasklet_vec, cpu).head;
780 __get_cpu_var(tasklet_vec).tail = per_cpu(tasklet_vec, cpu).tail; 828 this_cpu_write(tasklet_vec.tail, per_cpu(tasklet_vec, cpu).tail);
781 per_cpu(tasklet_vec, cpu).head = NULL; 829 per_cpu(tasklet_vec, cpu).head = NULL;
782 per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head; 830 per_cpu(tasklet_vec, cpu).tail = &per_cpu(tasklet_vec, cpu).head;
783 } 831 }
784 raise_softirq_irqoff(TASKLET_SOFTIRQ); 832 raise_softirq_irqoff(TASKLET_SOFTIRQ);
785 833
786 if (&per_cpu(tasklet_hi_vec, cpu).head != per_cpu(tasklet_hi_vec, cpu).tail) { 834 if (&per_cpu(tasklet_hi_vec, cpu).head != per_cpu(tasklet_hi_vec, cpu).tail) {
787 *__get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).head; 835 *__this_cpu_read(tasklet_hi_vec.tail) = per_cpu(tasklet_hi_vec, cpu).head;
788 __get_cpu_var(tasklet_hi_vec).tail = per_cpu(tasklet_hi_vec, cpu).tail; 836 __this_cpu_write(tasklet_hi_vec.tail, per_cpu(tasklet_hi_vec, cpu).tail);
789 per_cpu(tasklet_hi_vec, cpu).head = NULL; 837 per_cpu(tasklet_hi_vec, cpu).head = NULL;
790 per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head; 838 per_cpu(tasklet_hi_vec, cpu).tail = &per_cpu(tasklet_hi_vec, cpu).head;
791 } 839 }
@@ -805,7 +853,10 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
805 switch (action) { 853 switch (action) {
806 case CPU_UP_PREPARE: 854 case CPU_UP_PREPARE:
807 case CPU_UP_PREPARE_FROZEN: 855 case CPU_UP_PREPARE_FROZEN:
808 p = kthread_create(run_ksoftirqd, hcpu, "ksoftirqd/%d", hotcpu); 856 p = kthread_create_on_node(run_ksoftirqd,
857 hcpu,
858 cpu_to_node(hotcpu),
859 "ksoftirqd/%d", hotcpu);
809 if (IS_ERR(p)) { 860 if (IS_ERR(p)) {
810 printk("ksoftirqd for %i failed\n", hotcpu); 861 printk("ksoftirqd for %i failed\n", hotcpu);
811 return notifier_from_errno(PTR_ERR(p)); 862 return notifier_from_errno(PTR_ERR(p));
@@ -827,7 +878,9 @@ static int __cpuinit cpu_callback(struct notifier_block *nfb,
827 cpumask_any(cpu_online_mask)); 878 cpumask_any(cpu_online_mask));
828 case CPU_DEAD: 879 case CPU_DEAD:
829 case CPU_DEAD_FROZEN: { 880 case CPU_DEAD_FROZEN: {
830 struct sched_param param = { .sched_priority = MAX_RT_PRIO-1 }; 881 static const struct sched_param param = {
882 .sched_priority = MAX_RT_PRIO-1
883 };
831 884
832 p = per_cpu(ksoftirqd, hotcpu); 885 p = per_cpu(ksoftirqd, hotcpu);
833 per_cpu(ksoftirqd, hotcpu) = NULL; 886 per_cpu(ksoftirqd, hotcpu) = NULL;
@@ -857,25 +910,6 @@ static __init int spawn_ksoftirqd(void)
857} 910}
858early_initcall(spawn_ksoftirqd); 911early_initcall(spawn_ksoftirqd);
859 912
860#ifdef CONFIG_SMP
861/*
862 * Call a function on all processors
863 */
864int on_each_cpu(void (*func) (void *info), void *info, int wait)
865{
866 int ret = 0;
867
868 preempt_disable();
869 ret = smp_call_function(func, info, wait);
870 local_irq_disable();
871 func(info);
872 local_irq_enable();
873 preempt_enable();
874 return ret;
875}
876EXPORT_SYMBOL(on_each_cpu);
877#endif
878
879/* 913/*
880 * [ These __weak aliases are kept in a separate compilation unit, so that 914 * [ These __weak aliases are kept in a separate compilation unit, so that
881 * GCC does not inline them incorrectly. ] 915 * GCC does not inline them incorrectly. ]
@@ -886,17 +920,14 @@ int __init __weak early_irq_init(void)
886 return 0; 920 return 0;
887} 921}
888 922
923#ifdef CONFIG_GENERIC_HARDIRQS
889int __init __weak arch_probe_nr_irqs(void) 924int __init __weak arch_probe_nr_irqs(void)
890{ 925{
891 return 0; 926 return NR_IRQS_LEGACY;
892} 927}
893 928
894int __init __weak arch_early_irq_init(void) 929int __init __weak arch_early_irq_init(void)
895{ 930{
896 return 0; 931 return 0;
897} 932}
898 933#endif
899int __weak arch_init_chip_data(struct irq_desc *desc, int node)
900{
901 return 0;
902}