kern_softint.c revision 1.1.2.2 1 /* $NetBSD: kern_softint.c,v 1.1.2.2 2007/07/01 21:31:32 ad Exp $ */
2
3 /*-
4 * Copyright (c) 2007 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Andrew Doran.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed by the NetBSD
21 * Foundation, Inc. and its contributors.
22 * 4. Neither the name of The NetBSD Foundation nor the names of its
23 * contributors may be used to endorse or promote products derived
24 * from this software without specific prior written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39 /*
40 * Generic software interrupt framework.
41 *
42 * Overview
43 *
44 * The soft interrupt framework provides a mechanism to schedule a
45 * low priority callback that runs with thread context. It allows
46 * for dynamic registration of software interrupts, and for fair
47 * queueing and prioritization of those interrupts. The callbacks
48 * can be scheduled to run from nearly any point in the kernel: by
49 * code running with thread context, by code running from a
50 * hardware interrupt handler, and at any interrupt priority
51 * level.
52 *
53 * Priority levels
54 *
55 * Since soft interrupt dispatch can be tied to the underlying
56 * architecture's interrupt dispatch code, it may be limited by
57 * both by the capabilities of the hardware and the capabilities
58 * of the interrupt dispatch code itself. Therefore the number of
59 * levels is restricted to four. In order of priority (lowest to
60 * highest) the levels are: clock, bio, net, serial.
61 *
62 * The symbolic names are provided only as guide and in isolation
63 * do not have any direct connection with a particular kind of
64 * device activity.
65 *
66 * The four priority levels map directly to scheduler priority
67 * levels, and where the architecture implements 'fast' software
68 * interrupts, they also map onto interrupt priorities. The
69 * interrupt priorities are intended to be hidden from machine
70 * independent code, which should use multiprocessor and
71 * preemption aware mechanisms to synchronize with software
72 * interrupts (for example: mutexes).
73 *
74 * Capabilities
75 *
76 * As with hardware interrupt handlers, software interrupts run
77 * with limited machine context. In particular, they do not
78 * posess any VM (virtual memory) context, and should therefore
79 * not try to operate on user space addresses, or to use virtual
80 * memory facilities other than those noted as interrupt safe.
81 *
82 * Unlike hardware interrupts, software interrupts do have thread
83 * context. They may block on synchronization objects, sleep, and
84 * resume execution at a later time. Since software interrupts
85 * are a limited resource and (typically) run with higher priority
86 * than all other threads in the system, all block-and-resume
87 * activity by a software interrupt must be kept short in order to
88 * allow futher processing at that level to continue. The kernel
89 * does not allow software interrupts to use facilities or perform
90 * actions that may block for a significant amount of time. This
91 * means that it's not valid for a software interrupt to: sleep on
92 * condition variables, use the lockmgr() facility, or wait for
93 * resources to become available (for example, memory).
94 *
95 * Software interrupts may block to await ownership of locks,
96 * which are typically owned only for a short perioid of time:
97 * mutexes and reader/writer locks. By extension, code running in
98 * the bottom half of the kernel must take care to ensure that any
99 * lock that may be taken from a software interrupt can not be
100 * held for more than a short period of time.
101 *
102 * Per-CPU operation
103 *
104 * Soft interrupts are strictly per-CPU. If a soft interrupt is
105 * triggered on a CPU, it will only be dispatched on that CPU.
106 * Each LWP dedicated to handling a soft interrupt is bound to
107 * it's home CPU, so if the LWP blocks and needs to run again, it
108 * can only run there. Nearly all data structures used to manage
109 * software interrupts are per-CPU.
110 *
111 * Soft interrupts can occur many thousands of times per second.
112 * In light of this, the per-CPU requirement is intended to solve
113 * three problems:
114 *
115 * 1) For passing work down from a hardware interrupt handler to a
116 * software interrupt (for example, using a queue) spinlocks need
117 * not be used to guarantee data integrity. Adjusting the CPU
118 * local interrupt priority level is sufficient. Acquiring
119 * spinlocks is computationally expensive, as it increases traffic
120 * on the system bus and can stall processors with long execution
121 * pipelines.
122 *
123 * 2) Often hardware interrupt handlers manipulate data structures
124 * and then pass those to a software interrupt for further
125 * processing. If those data structures are immediately passed to
126 * another CPU, the associated cache lines may be forced across
127 * the system bus, generating more bus traffic.
128 *
129 * 3) The data structures used to manage soft interrupts are also
130 * CPU local, again to reduce unnecessary bus traffic.
131 *
132 * Generic implementation
133 *
134 * A generic, low performance implementation is provided that
135 * works across all architectures, with no machine-dependent
136 * modifications needed. This implementation uses the scheduler,
137 * and so has a number of restrictions:
138 *
139 * 1) Since software interrupts can be triggered from any priority
140 * level, on architectures where the generic implementation is
141 * used IPL_SCHED must be equal to IPL_HIGH.
142 *
143 * 2) The software interrupts are not preemptive, and so must wait
144 * for the currently executing thread to yield the CPU. This
145 * can introduce latency.
146 *
147 * 3) A context switch is required for each soft interrupt to be
148 * handled, which can be quite expensive.
149 *
150 * 'Fast' software interrupts
151 *
152 * XXX
153 *
154 * The !__HAVE_FAST_SOFTINTS case assumes splhigh == splsched.
155 */
156
157 #include <sys/cdefs.h>
158 __KERNEL_RCSID(0, "$NetBSD: kern_softint.c,v 1.1.2.2 2007/07/01 21:31:32 ad Exp $");
159
160 #include <sys/param.h>
161 #include <sys/malloc.h>
162 #include <sys/proc.h>
163 #include <sys/intr.h>
164 #include <sys/mutex.h>
165 #include <sys/kthread.h>
166 #include <sys/evcnt.h>
167 #include <sys/cpu.h>
168
169 #include <net/netisr.h>
170
171 #include <uvm/uvm_extern.h>
172
173 #define PRI_SOFTCLOCK PRI_INTERRUPT
174 #define PRI_SOFTBIO (PRI_INTERRUPT + 4)
175 #define PRI_SOFTNET (PRI_INTERRUPT + 8)
176 #define PRI_SOFTSERIAL (PRI_INTERRUPT + 12)
177
178 /* This could overlap with signal info in struct lwp. */
179 typedef struct softint {
180 TAILQ_HEAD(, softhand) si_q;
181 struct lwp *si_lwp;
182 struct cpu_info *si_cpu;
183 uintptr_t si_machdep;
184 struct evcnt si_evcnt;
185 int si_active;
186 char si_name[8];
187 } softint_t;
188
189 typedef struct softhand {
190 TAILQ_ENTRY(softhand) sh_q;
191 void (*sh_func)(void *);
192 void *sh_arg;
193 softint_t *sh_isr;
194 u_int sh_pending;
195 u_int sh_flags;
196 } softhand_t;
197
198 typedef struct softcpu {
199 struct cpu_info *sc_cpu;
200 softint_t sc_int[SOFTINT_COUNT];
201 softhand_t sc_hand[1];
202 } softcpu_t;
203
204 static void softint_thread(void *);
205 static void softint_netisr(void *);
206
207 u_int softint_bytes = 8192;
208 static u_int softint_max;
209 static kmutex_t softint_lock;
210 static void *softint_netisr_sih;
211 struct evcnt softint_block;
212
213 /*
214 * softint_init_isr:
215 *
216 * Initialize a single interrupt level for a single CPU.
217 */
218 static void
219 softint_init_isr(softcpu_t *sc, const char *desc, pri_t pri, u_int level)
220 {
221 struct cpu_info *ci;
222 softint_t *si;
223 int error;
224
225 si = &sc->sc_int[level];
226 ci = sc->sc_cpu;
227 si->si_cpu = ci;
228
229 TAILQ_INIT(&si->si_q);
230
231 error = kthread_create(pri, KTHREAD_MPSAFE | KTHREAD_INTR |
232 KTHREAD_IDLE, ci, softint_thread, si, &si->si_lwp,
233 "soft%s/%d", desc, (int)ci->ci_cpuid);
234 if (error != 0)
235 panic("softint_init_isr: error %d", error);
236
237 snprintf(si->si_name, sizeof(si->si_name), "%s/%d", desc,
238 (int)ci->ci_cpuid);
239 evcnt_attach_dynamic(&si->si_evcnt, EVCNT_TYPE_INTR, NULL,
240 "softint", si->si_name);
241
242 softint_init_md(si->si_lwp, level, &si->si_machdep, si);
243
244 #ifdef __HAVE_FAST_SOFTINTS
245 si->si_lwp->l_mutex = &ci->ci_schedstate.spc_lwplock;
246 #endif
247 }
248
249 /*
250 * softint_init_md:
251 *
252 * Perform machine-dependent initialization. Arguments:
253 *
254 * l
255 *
256 * LWP to handle the interrupt
257 *
258 * level
259 *
260 * Symbolic level: SOFTINT_*
261 *
262 * machdep
263 *
264 * Private value for machine dependent code,
265 * passed by MI code to softint_trigger().
266 *
267 * cookie
268 *
269 * Value to be passed to softint_execute() by
270 * MD code when an interrupt is being handled.
271 */
272 #ifndef __HAVE_FAST_SOFTINTS
273 void
274 softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep, void *cookie)
275 {
276
277 *machdep = (lwp_t)l;
278
279 lwp_lock(l);
280 /* Cheat and make the KASSERT in softint_thread() happy. */
281 ((softint_t *)cookie)->si_active = 1;
282 l->l_stat = LSRUN;
283 sched_enqueue(l, false);
284 lwp_unlock(l);
285 }
286 #endif /* !__HAVE_FAST_SOFTINTS */
287
288 /*
289 * softint_init:
290 *
291 * Initialize per-CPU data structures. Called from mi_cpu_attach().
292 */
293 void
294 softint_init(struct cpu_info *ci)
295 {
296 static struct cpu_info *first;
297 softcpu_t *sc, *scfirst;
298 softhand_t *sh, *shmax;
299
300 if (first == NULL) {
301 /* Boot CPU. */
302 first = ci;
303 mutex_init(&softint_lock, MUTEX_DEFAULT, IPL_NONE);
304 softint_bytes = round_page(softint_bytes);
305 softint_max = (softint_bytes - sizeof(softcpu_t)) /
306 sizeof(softhand_t);
307 evcnt_attach_dynamic(&softint_block, EVCNT_TYPE_INTR,
308 NULL, "softint", "block");
309 }
310
311 sc = (softcpu_t *)uvm_km_alloc(kernel_map, softint_bytes, 0,
312 UVM_KMF_WIRED | UVM_KMF_ZERO);
313 if (sc == NULL)
314 panic("softint_init_cpu: cannot allocate memory");
315
316 ci->ci_data.cpu_softcpu = sc;
317 sc->sc_cpu = ci;
318
319 softint_init_isr(sc, "net", PRI_SOFTNET, SOFTINT_NET);
320 softint_init_isr(sc, "bio", PRI_SOFTBIO, SOFTINT_BIO);
321 softint_init_isr(sc, "clk", PRI_SOFTCLOCK, SOFTINT_CLOCK);
322 softint_init_isr(sc, "ser", PRI_SOFTSERIAL, SOFTINT_SERIAL);
323
324 if (first != ci) {
325 /* Don't lock -- autoconfiguration will prevent reentry. */
326 scfirst = first->ci_data.cpu_softcpu;
327 sh = sc->sc_hand;
328 memcpy(sh, scfirst->sc_hand, sizeof(*sh) * softint_max);
329
330 /* Update pointers for this CPU. */
331 for (shmax = sh + softint_max; sh < shmax; sh++) {
332 if (sh->sh_func == NULL)
333 continue;
334 sh->sh_isr =
335 &sc->sc_int[sh->sh_flags & SOFTINT_LVLMASK];
336 }
337 } else {
338 /* Establish a handler for legacy net interrupts. */
339 softint_netisr_sih = softint_establish(SOFTINT_NET,
340 softint_netisr, NULL);
341 KASSERT(softint_netisr_sih != NULL);
342 }
343 }
344
345 /*
346 * softint_establish:
347 *
348 * Register a software interrupt handler.
349 */
350 void *
351 softint_establish(u_int flags, void (*func)(void *), void *arg)
352 {
353 CPU_INFO_ITERATOR cii;
354 struct cpu_info *ci;
355 softcpu_t *sc;
356 softhand_t *sh;
357 u_int level;
358 u_int index;
359
360 level = (flags & SOFTINT_LVLMASK);
361 KASSERT(level < SOFTINT_COUNT);
362
363 mutex_enter(&softint_lock);
364
365 /* Find a free slot. */
366 sc = curcpu()->ci_data.cpu_softcpu;
367 for (index = 1; index < softint_max; index++)
368 if (sc->sc_hand[index].sh_func == NULL)
369 break;
370 if (index == softint_max) {
371 mutex_exit(&softint_lock);
372 printf("WARNING: softint_establish: table full, "
373 "increase softint_bytes\n");
374 return NULL;
375 }
376
377 /* Set up the handler on each CPU. */
378 for (CPU_INFO_FOREACH(cii, ci)) {
379 sc = ci->ci_data.cpu_softcpu;
380 sh = &sc->sc_hand[index];
381
382 sh->sh_isr = &sc->sc_int[level];
383 sh->sh_func = func;
384 sh->sh_arg = arg;
385 sh->sh_flags = flags;
386 sh->sh_pending = 0;
387 }
388
389 mutex_exit(&softint_lock);
390
391 return (void *)index;
392 }
393
394 /*
395 * softint_disestablish:
396 *
397 * Unregister a software interrupt handler.
398 */
399 void
400 softint_disestablish(void *arg)
401 {
402 CPU_INFO_ITERATOR cii;
403 struct cpu_info *ci;
404 softcpu_t *sc;
405 softhand_t *sh;
406 u_int index;
407
408 index = (u_int)arg;
409 KASSERT(index != 0 && index < softint_max);
410
411 mutex_enter(&softint_lock);
412
413 /* Set up the handler on each CPU. */
414 for (CPU_INFO_FOREACH(cii, ci)) {
415 sc = ci->ci_data.cpu_softcpu;
416 sh = &sc->sc_hand[index];
417 KASSERT(sh->sh_func != NULL);
418 KASSERT(sh->sh_pending == 0);
419 sh->sh_func = NULL;
420 }
421
422 mutex_exit(&softint_lock);
423 }
424
425 /*
426 * softint_trigger:
427 *
428 * Cause a soft interrupt handler to begin executing.
429 */
430 #ifndef __HAVE_FAST_SOFTINTS
431 inline void
432 softint_trigger(uintptr_t machdep)
433 {
434 struct cpu_info *ci;
435 lwp_t *l;
436
437 l = (lwp_t *)machdep;
438 ci = l->l_cpu;
439
440 spc_lock(ci);
441 l->l_mutex = ci->ci_schedstate.spc_mutex;
442 l->l_stat = LSRUN;
443 sched_enqueue(l, false);
444 cpu_need_resched(ci, 1);
445 spc_unlock(ci);
446 }
447 #endif /* __HAVE_FAST_SOFTINTS */
448
449 /*
450 * softint_schedule:
451 *
452 * Trigger a software interrupt. Must be called from a hardware
453 * interrupt handler, or with preemption disabled (since we are
454 * using the value of curcpu()).
455 */
456 void
457 softint_schedule(void *arg)
458 {
459 softhand_t *sh;
460 softint_t *si;
461 u_int index;
462 int s;
463
464 /* Find the handler record for this CPU. */
465 index = (u_int)arg;
466 KASSERT(index != 0 && index < softint_max);
467 sh = &((softcpu_t *)curcpu()->ci_data.cpu_softcpu)->sc_hand[index];
468
469 /* If it's already pending there's nothing to do. */
470 if (sh->sh_pending)
471 return;
472
473 /*
474 * Enqueue the handler into the LWP's pending list.
475 * If the LWP is completely idle, then make it run.
476 */
477 s = splhigh();
478 if (!sh->sh_pending) {
479 si = sh->sh_isr;
480 sh->sh_pending = 1;
481 TAILQ_INSERT_TAIL(&si->si_q, sh, sh_q);
482 if (si->si_active == 0) {
483 si->si_active = 1;
484 softint_trigger(si->si_machdep);
485 }
486 }
487 splx(s);
488 }
489
490 /*
491 * softint_thread:
492 *
493 * MI software interrupt dispatch. In the __HAVE_FAST_SOFTINTS
494 * case, the LWP is switched to without restoring any state, so
495 * we should not arrive here - there is a direct handoff between
496 * the interrupt stub and softint_execute().
497 */
498 void
499 softint_thread(void *cookie)
500 {
501 #ifdef __HAVE_FAST_SOFTINTS
502 panic("softint_thread");
503 #else /* __HAVE_FAST_SOFTINTS */
504 lwp_t *l;
505 int s;
506
507 l = curlwp;
508 s = splhigh();
509
510 for (;;) {
511 softint_execute(cookie, s);
512
513 lwp_lock(l);
514 l->l_stat = LSIDL;
515 mi_switch(l);
516 }
517 #endif /* !__HAVE_FAST_SOFTINTS */
518 }
519
520 /*
521 * softint_execute:
522 *
523 * Invoke handlers for the specified soft interrupt.
524 * Must be entered at splhigh. Will drop the priority
525 * to the level specified, but returns back at splhigh.
526 */
527 void
528 softint_execute(void *cookie, int s)
529 {
530 softint_t *si;
531 softhand_t *sh;
532 lwp_t *l, *l2;
533
534 si = cookie;
535 l = si->si_lwp;
536
537 KASSERT(si->si_lwp == curlwp);
538 KASSERT(si->si_cpu == curcpu());
539 KASSERT(si->si_lwp->l_wchan == NULL);
540 KASSERT(!TAILQ_EMPTY(&si->si_q));
541 KASSERT(si->si_active);
542
543 while (!TAILQ_EMPTY(&si->si_q)) {
544 /*
545 * If any interrupted LWP has higher priority then we
546 * must yield immediatley. Note that IPL_HIGH may be
547 * above IPL_SCHED, so we have to drop the interrupt
548 * priority level before yielding.
549 *
550 * XXXAD Optimise this away.
551 */
552 for (l2 = l->l_pinned; l2 != NULL; l2 = l2->l_pinned) {
553 if (lwp_eprio(l2) > l->l_priority)
554 break;
555 }
556 if (l2 != NULL) {
557 splx(s);
558 yield();
559 (void)splhigh();
560 continue;
561 }
562
563 /*
564 * Pick the longest waiting handler to run. We block
565 * interrupts but do not lock in order to do this, as
566 * we are protecting against the local CPU only.
567 */
568 sh = TAILQ_FIRST(&si->si_q);
569 TAILQ_REMOVE(&si->si_q, sh, sh_q);
570 sh->sh_pending = 0;
571 splx(s);
572
573 /* Run the handler. */
574 if ((sh->sh_flags & SOFTINT_MPSAFE) == 0) {
575 KERNEL_LOCK(1, l);
576 }
577 (*sh->sh_func)(sh->sh_arg);
578 if ((sh->sh_flags & SOFTINT_MPSAFE) == 0) {
579 KERNEL_UNLOCK_ONE(l);
580 }
581
582 (void)splhigh();
583 }
584
585 /*
586 * Unlocked, but only for statistics.
587 * Should be per-CPU to prevent cache ping-pong.
588 */
589 uvmexp.softs++;
590
591 si->si_evcnt.ev_count++;
592 si->si_active = 0;
593 }
594
595 /*
596 * schednetisr:
597 *
598 * Trigger a legacy network interrupt. XXX Needs to go away.
599 */
600 void
601 schednetisr(int isr)
602 {
603 int s;
604
605 s = splhigh();
606 curcpu()->ci_data.cpu_netisrs |= (1 << isr);
607 softint_schedule(softint_netisr_sih);
608 splx(s);
609 }
610
611 /*
612 * softintr_netisr:
613 *
614 * Dispatch legacy network interrupts. XXX Needs to go away.
615 */
616 static void
617 softint_netisr(void *cookie)
618 {
619 struct cpu_info *ci;
620 int s, bits;
621
622 ci = curcpu();
623
624 s = splhigh();
625 bits = ci->ci_data.cpu_netisrs;
626 ci->ci_data.cpu_netisrs = 0;
627 splx(s);
628
629 #define DONETISR(which, func) \
630 do { \
631 void func(void); \
632 if ((bits & (1 << which)) != 0) \
633 func(); \
634 } while(0);
635 #include <net/netisr_dispatch.h>
636 #undef DONETISR
637 }
638