1 /*
2 * linux/kernel/softirq.c
3 *
4 * Copyright (C) 1992 Linus Torvalds
5 *
6 * Fixed a disable_bh()/enable_bh() race (was causing a console lockup)
7 * due bh_mask_count not atomic handling. Copyright (C) 1998 Andrea Arcangeli
8 *
9 * Rewritten. Old one was good in 2.2, but in 2.3 it was immoral. --ANK (990903)
10 */
11
12 #include <linux/config.h>
13 #include <linux/mm.h>
14 #include <linux/kernel_stat.h>
15 #include <linux/interrupt.h>
16 #include <linux/smp_lock.h>
17 #include <linux/init.h>
18 #include <linux/tqueue.h>
19
20 /*
21 - No shared variables, all the data are CPU local.
22 - If a softirq needs serialization, let it serialize itself
23 by its own spinlocks.
24 - Even if softirq is serialized, only local cpu is marked for
25 execution. Hence, we get something sort of weak cpu binding.
26 Though it is still not clear, will it result in better locality
27 or will not.
28 - These softirqs are not masked by global cli() and start_bh_atomic()
29 (by clear reasons). Hence, old parts of code still using global locks
30 MUST NOT use softirqs, but insert interfacing routines acquiring
31 global locks. F.e. look at BHs implementation.
32
33 Examples:
34 - NET RX softirq. It is multithreaded and does not require
35 any global serialization.
36 - NET TX softirq. It kicks software netdevice queues, hence
37 it is logically serialized per device, but this serialization
38 is invisible to common code.
39 - Tasklets: serialized wrt itself.
40 - Bottom halves: globally serialized, grr...
41 */
42
43 irq_cpustat_t irq_stat[NR_CPUS] ____cacheline_aligned;
44
45 static struct softirq_action softirq_vec[32] __cacheline_aligned;
46
47 /*
48 * we cannot loop indefinitely here to avoid userspace starvation,
49 * but we also don't want to introduce a worst case 1/HZ latency
50 * to the pending events, so lets the scheduler to balance
51 * the softirq load for us.
52 */
wakeup_softirqd(unsigned cpu)53 static inline void wakeup_softirqd(unsigned cpu)
54 {
55 struct task_struct * tsk = ksoftirqd_task(cpu);
56
57 if (tsk && tsk->state != TASK_RUNNING)
58 wake_up_process(tsk);
59 }
60
do_softirq()61 asmlinkage void do_softirq()
62 {
63 int cpu = smp_processor_id();
64 __u32 pending;
65 unsigned long flags;
66 __u32 mask;
67
68 if (in_interrupt())
69 return;
70
71 local_irq_save(flags);
72
73 pending = softirq_pending(cpu);
74
75 if (pending) {
76 struct softirq_action *h;
77
78 mask = ~pending;
79 local_bh_disable();
80 restart:
81 /* Reset the pending bitmask before enabling irqs */
82 softirq_pending(cpu) = 0;
83
84 local_irq_enable();
85
86 h = softirq_vec;
87
88 do {
89 if (pending & 1)
90 h->action(h);
91 h++;
92 pending >>= 1;
93 } while (pending);
94
95 local_irq_disable();
96
97 pending = softirq_pending(cpu);
98 if (pending & mask) {
99 mask &= ~pending;
100 goto restart;
101 }
102 __local_bh_enable();
103
104 if (pending)
105 wakeup_softirqd(cpu);
106 }
107
108 local_irq_restore(flags);
109 }
110
111 /*
112 * This function must run with irq disabled!
113 */
cpu_raise_softirq(unsigned int cpu,unsigned int nr)114 inline fastcall void cpu_raise_softirq(unsigned int cpu, unsigned int nr)
115 {
116 __cpu_raise_softirq(cpu, nr);
117
118 /*
119 * If we're in an interrupt or bh, we're done
120 * (this also catches bh-disabled code). We will
121 * actually run the softirq once we return from
122 * the irq or bh.
123 *
124 * Otherwise we wake up ksoftirqd to make sure we
125 * schedule the softirq soon.
126 */
127 if (!(local_irq_count(cpu) | local_bh_count(cpu)))
128 wakeup_softirqd(cpu);
129 }
130
raise_softirq(unsigned int nr)131 void fastcall raise_softirq(unsigned int nr)
132 {
133 unsigned long flags;
134
135 local_irq_save(flags);
136 cpu_raise_softirq(smp_processor_id(), nr);
137 local_irq_restore(flags);
138 }
139
open_softirq(int nr,void (* action)(struct softirq_action *),void * data)140 void open_softirq(int nr, void (*action)(struct softirq_action*), void *data)
141 {
142 softirq_vec[nr].data = data;
143 softirq_vec[nr].action = action;
144 }
145
146
147 /* Tasklets */
148
149 struct tasklet_head tasklet_vec[NR_CPUS] __cacheline_aligned;
150 struct tasklet_head tasklet_hi_vec[NR_CPUS] __cacheline_aligned;
151
__tasklet_schedule(struct tasklet_struct * t)152 void fastcall __tasklet_schedule(struct tasklet_struct *t)
153 {
154 int cpu = smp_processor_id();
155 unsigned long flags;
156
157 local_irq_save(flags);
158 t->next = tasklet_vec[cpu].list;
159 tasklet_vec[cpu].list = t;
160 cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
161 local_irq_restore(flags);
162 }
163
__tasklet_hi_schedule(struct tasklet_struct * t)164 void fastcall __tasklet_hi_schedule(struct tasklet_struct *t)
165 {
166 int cpu = smp_processor_id();
167 unsigned long flags;
168
169 local_irq_save(flags);
170 t->next = tasklet_hi_vec[cpu].list;
171 tasklet_hi_vec[cpu].list = t;
172 cpu_raise_softirq(cpu, HI_SOFTIRQ);
173 local_irq_restore(flags);
174 }
175
tasklet_action(struct softirq_action * a)176 static void tasklet_action(struct softirq_action *a)
177 {
178 int cpu = smp_processor_id();
179 struct tasklet_struct *list;
180
181 local_irq_disable();
182 list = tasklet_vec[cpu].list;
183 tasklet_vec[cpu].list = NULL;
184 local_irq_enable();
185
186 while (list) {
187 struct tasklet_struct *t = list;
188
189 list = list->next;
190
191 if (tasklet_trylock(t)) {
192 if (!atomic_read(&t->count)) {
193 if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
194 BUG();
195 t->func(t->data);
196 tasklet_unlock(t);
197 continue;
198 }
199 tasklet_unlock(t);
200 }
201
202 local_irq_disable();
203 t->next = tasklet_vec[cpu].list;
204 tasklet_vec[cpu].list = t;
205 __cpu_raise_softirq(cpu, TASKLET_SOFTIRQ);
206 local_irq_enable();
207 }
208 }
209
tasklet_hi_action(struct softirq_action * a)210 static void tasklet_hi_action(struct softirq_action *a)
211 {
212 int cpu = smp_processor_id();
213 struct tasklet_struct *list;
214
215 local_irq_disable();
216 list = tasklet_hi_vec[cpu].list;
217 tasklet_hi_vec[cpu].list = NULL;
218 local_irq_enable();
219
220 while (list) {
221 struct tasklet_struct *t = list;
222
223 list = list->next;
224
225 if (tasklet_trylock(t)) {
226 if (!atomic_read(&t->count)) {
227 if (!test_and_clear_bit(TASKLET_STATE_SCHED, &t->state))
228 BUG();
229 t->func(t->data);
230 tasklet_unlock(t);
231 continue;
232 }
233 tasklet_unlock(t);
234 }
235
236 local_irq_disable();
237 t->next = tasklet_hi_vec[cpu].list;
238 tasklet_hi_vec[cpu].list = t;
239 __cpu_raise_softirq(cpu, HI_SOFTIRQ);
240 local_irq_enable();
241 }
242 }
243
244
tasklet_init(struct tasklet_struct * t,void (* func)(unsigned long),unsigned long data)245 void tasklet_init(struct tasklet_struct *t,
246 void (*func)(unsigned long), unsigned long data)
247 {
248 t->next = NULL;
249 t->state = 0;
250 atomic_set(&t->count, 0);
251 t->func = func;
252 t->data = data;
253 }
254
tasklet_kill(struct tasklet_struct * t)255 void tasklet_kill(struct tasklet_struct *t)
256 {
257 if (in_interrupt())
258 printk("Attempt to kill tasklet from interrupt\n");
259
260 while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) {
261 current->state = TASK_RUNNING;
262 do {
263 yield();
264 } while (test_bit(TASKLET_STATE_SCHED, &t->state));
265 }
266 tasklet_unlock_wait(t);
267 clear_bit(TASKLET_STATE_SCHED, &t->state);
268 }
269
270
271
272 /* Old style BHs */
273
274 static void (*bh_base[32])(void);
275 struct tasklet_struct bh_task_vec[32];
276
277 /* BHs are serialized by spinlock global_bh_lock.
278
279 It is still possible to make synchronize_bh() as
280 spin_unlock_wait(&global_bh_lock). This operation is not used
281 by kernel now, so that this lock is not made private only
282 due to wait_on_irq().
283
284 It can be removed only after auditing all the BHs.
285 */
286 spinlock_t global_bh_lock = SPIN_LOCK_UNLOCKED;
287
bh_action(unsigned long nr)288 static void bh_action(unsigned long nr)
289 {
290 int cpu = smp_processor_id();
291
292 if (!spin_trylock(&global_bh_lock))
293 goto resched;
294
295 if (!hardirq_trylock(cpu))
296 goto resched_unlock;
297
298 if (bh_base[nr])
299 bh_base[nr]();
300
301 hardirq_endlock(cpu);
302 spin_unlock(&global_bh_lock);
303 return;
304
305 resched_unlock:
306 spin_unlock(&global_bh_lock);
307 resched:
308 mark_bh(nr);
309 }
310
init_bh(int nr,void (* routine)(void))311 void init_bh(int nr, void (*routine)(void))
312 {
313 bh_base[nr] = routine;
314 mb();
315 }
316
remove_bh(int nr)317 void remove_bh(int nr)
318 {
319 tasklet_kill(bh_task_vec+nr);
320 bh_base[nr] = NULL;
321 }
322
softirq_init()323 void __init softirq_init()
324 {
325 int i;
326
327 for (i=0; i<32; i++)
328 tasklet_init(bh_task_vec+i, bh_action, i);
329
330 open_softirq(TASKLET_SOFTIRQ, tasklet_action, NULL);
331 open_softirq(HI_SOFTIRQ, tasklet_hi_action, NULL);
332 }
333
__run_task_queue(task_queue * list)334 void __run_task_queue(task_queue *list)
335 {
336 struct list_head head, *next;
337 unsigned long flags;
338
339 spin_lock_irqsave(&tqueue_lock, flags);
340 list_add(&head, list);
341 list_del_init(list);
342 spin_unlock_irqrestore(&tqueue_lock, flags);
343
344 next = head.next;
345 while (next != &head) {
346 void (*f) (void *);
347 struct tq_struct *p;
348 void *data;
349
350 p = list_entry(next, struct tq_struct, list);
351 next = next->next;
352 f = p->routine;
353 data = p->data;
354 wmb();
355 p->sync = 0;
356 if (f)
357 f(data);
358 }
359 }
360
ksoftirqd(void * __bind_cpu)361 static int ksoftirqd(void * __bind_cpu)
362 {
363 int bind_cpu = (int) (long) __bind_cpu;
364 int cpu = cpu_logical_map(bind_cpu);
365
366 daemonize();
367 current->nice = 19;
368 sigfillset(¤t->blocked);
369
370 /* Migrate to the right CPU */
371 current->cpus_allowed = 1UL << cpu;
372 while (smp_processor_id() != cpu)
373 schedule();
374
375 sprintf(current->comm, "ksoftirqd_CPU%d", bind_cpu);
376
377 __set_current_state(TASK_INTERRUPTIBLE);
378 mb();
379
380 ksoftirqd_task(cpu) = current;
381
382 for (;;) {
383 if (!softirq_pending(cpu))
384 schedule();
385
386 __set_current_state(TASK_RUNNING);
387
388 while (softirq_pending(cpu)) {
389 do_softirq();
390 if (current->need_resched)
391 schedule();
392 }
393
394 __set_current_state(TASK_INTERRUPTIBLE);
395 }
396 }
397
spawn_ksoftirqd(void)398 static __init int spawn_ksoftirqd(void)
399 {
400 int cpu;
401
402 for (cpu = 0; cpu < smp_num_cpus; cpu++) {
403 if (kernel_thread(ksoftirqd, (void *) (long) cpu,
404 CLONE_FS | CLONE_FILES | CLONE_SIGNAL) < 0)
405 printk("spawn_ksoftirqd() failed for cpu %d\n", cpu);
406 else {
407 while (!ksoftirqd_task(cpu_logical_map(cpu)))
408 yield();
409 }
410 }
411
412 return 0;
413 }
414
415 __initcall(spawn_ksoftirqd);
416