xref: /freebsd/sys/kern/kern_intr.c (revision ce4946daa5ce852d28008dac492029500ab2ee95)
1 /*
2  * Copyright (c) 1997, Stefan Esser <se@freebsd.org>
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  *    notice unmodified, this list of conditions, and the following
10  *    disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  *
28  */
29 
30 
31 #include <sys/param.h>
32 #include <sys/bus.h>
33 #include <sys/rtprio.h>
34 #include <sys/systm.h>
35 #include <sys/ipl.h>
36 #include <sys/interrupt.h>
37 #include <sys/kernel.h>
38 #include <sys/kthread.h>
39 #include <sys/ktr.h>
40 #include <sys/lock.h>
41 #include <sys/malloc.h>
42 #include <sys/mutex.h>
43 #include <sys/proc.h>
44 #include <sys/random.h>
45 #include <sys/resourcevar.h>
46 #include <sys/unistd.h>
47 #include <sys/vmmeter.h>
48 #include <machine/atomic.h>
49 #include <machine/cpu.h>
50 #include <machine/md_var.h>
51 #include <machine/stdarg.h>
52 
53 #include <net/netisr.h>		/* prototype for legacy_setsoftnet */
54 
55 struct	int_entropy {
56 	struct	proc *proc;
57 	int	vector;
58 };
59 
60 void	*net_ih;
61 void	*vm_ih;
62 void	*softclock_ih;
63 struct	ithd *clk_ithd;
64 struct	ithd *tty_ithd;
65 
66 static struct	mtx ithread_list_lock;
67 
68 static MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads");
69 
70 static void	ithread_update(struct ithd *);
71 static void	ithread_loop(void *);
72 static void	ithread_init(void *);
73 static void	start_softintr(void *);
74 static void	swi_net(void *);
75 
76 u_char
77 ithread_priority(enum intr_type flags)
78 {
79 	u_char pri;
80 
81 	flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET |
82 	    INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK);
83 	switch (flags) {
84 	case INTR_TYPE_TTY:
85 		pri = PI_TTYLOW;
86 		break;
87 	case INTR_TYPE_BIO:
88 		/*
89 		 * XXX We need to refine this.  BSD/OS distinguishes
90 		 * between tape and disk priorities.
91 		 */
92 		pri = PI_DISK;
93 		break;
94 	case INTR_TYPE_NET:
95 		pri = PI_NET;
96 		break;
97 	case INTR_TYPE_CAM:
98 		pri = PI_DISK;          /* XXX or PI_CAM? */
99 		break;
100 	case INTR_TYPE_CLK:
101 		pri = PI_REALTIME;
102 		break;
103 	case INTR_TYPE_MISC:
104 		pri = PI_DULL;          /* don't care */
105 		break;
106 	default:
107 		/* We didn't specify an interrupt level. */
108 		panic("ithread_priority: no interrupt type in flags");
109 	}
110 
111 	return pri;
112 }
113 
114 /*
115  * Regenerate the name (p_comm) and priority for a threaded interrupt thread.
116  */
117 static void
118 ithread_update(struct ithd *ithd)
119 {
120 	struct intrhand *ih;
121 	struct proc *p;
122 	int entropy;
123 
124 	p = ithd->it_proc;
125 	if (p == NULL)
126 		return;
127 
128 	strncpy(p->p_comm, ithd->it_name, sizeof(ithd->it_name));
129 	ih = TAILQ_FIRST(&ithd->it_handlers);
130 	if (ih == NULL) {
131 		p->p_pri.pri_level = PRI_MAX_ITHD;
132 		ithd->it_flags &= ~IT_ENTROPY;
133 		return;
134 	}
135 
136 	entropy = 0;
137 	p->p_pri.pri_level = ih->ih_pri;
138 	p->p_pri.pri_native = ih->ih_pri;
139 	TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) {
140 		if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 <
141 		    sizeof(p->p_comm)) {
142 			strcat(p->p_comm, " ");
143 			strcat(p->p_comm, ih->ih_name);
144 		} else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) {
145 			if (p->p_comm[sizeof(p->p_comm) - 2] == '+')
146 				p->p_comm[sizeof(p->p_comm) - 2] = '*';
147 			else
148 				p->p_comm[sizeof(p->p_comm) - 2] = '+';
149 		} else
150 			strcat(p->p_comm, "+");
151 		if (ih->ih_flags & IH_ENTROPY)
152 			entropy++;
153 	}
154 
155 	if (entropy)
156 		ithd->it_flags |= IT_ENTROPY;
157 	else
158 		ithd->it_flags &= ~IT_ENTROPY;
159 
160 	CTR1(KTR_INTR, __func__ ": updated %s\n", p->p_comm);
161 }
162 
163 int
164 ithread_create(struct ithd **ithread, int vector, int flags,
165     void (*disable)(int), void (*enable)(int), const char *fmt, ...)
166 {
167 	struct ithd *ithd;
168 	struct proc *p;
169 	int error;
170 	va_list ap;
171 
172 	/* The only valid flag during creation is IT_SOFT. */
173 	if ((flags & ~IT_SOFT) != 0)
174 		return (EINVAL);
175 
176 	ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO);
177 	ithd->it_vector = vector;
178 	ithd->it_disable = disable;
179 	ithd->it_enable = enable;
180 	ithd->it_flags = flags;
181 	TAILQ_INIT(&ithd->it_handlers);
182 
183 	va_start(ap, fmt);
184 	vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap);
185 	va_end(ap);
186 
187 	error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID,
188 	    "%s", ithd->it_name);
189 	if (error) {
190 		free(ithd, M_ITHREAD);
191 		return (error);
192 	}
193 	p->p_pri.pri_class = PRI_ITHD;
194 	p->p_pri.pri_level = PRI_MAX_ITHD;
195 	p->p_stat = SWAIT;
196 	ithd->it_proc = p;
197 	p->p_ithd = ithd;
198 	if (ithread != NULL)
199 		*ithread = ithd;
200 
201 	CTR1(KTR_INTR, __func__ ": created %s", ithd->it_name);
202 	return (0);
203 }
204 
205 int
206 ithread_destroy(struct ithd *ithread)
207 {
208 
209 	if (ithread == NULL || !TAILQ_EMPTY(&ithread->it_handlers))
210 		return (EINVAL);
211 
212 	mtx_lock_spin(&sched_lock);
213 	ithread->it_flags |= IT_DEAD;
214 	if (ithread->it_proc->p_stat == SWAIT) {
215 		ithread->it_proc->p_stat = SRUN;
216 		setrunqueue(ithread->it_proc);
217 	}
218 	mtx_unlock_spin(&sched_lock);
219 	CTR1(KTR_INTR, __func__ ": killing %s", ithread->it_name);
220 	return (0);
221 }
222 
223 int
224 ithread_add_handler(struct ithd* ithread, const char *name,
225     driver_intr_t handler, void *arg, u_char pri, enum intr_type flags,
226     void **cookiep)
227 {
228 	struct intrhand *ih, *temp_ih;
229 
230 	if (ithread == NULL || name == NULL || handler == NULL)
231 		return (EINVAL);
232 	if ((flags & INTR_FAST) !=0)
233 		flags |= INTR_EXCL;
234 
235 	ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_WAITOK | M_ZERO);
236 	ih->ih_handler = handler;
237 	ih->ih_argument = arg;
238 	ih->ih_name = name;
239 	ih->ih_ithread = ithread;
240 	ih->ih_pri = pri;
241 	if (flags & INTR_FAST)
242 		ih->ih_flags = IH_FAST | IH_EXCLUSIVE;
243 	else if (flags & INTR_EXCL)
244 		ih->ih_flags = IH_EXCLUSIVE;
245 	if (flags & INTR_MPSAFE)
246 		ih->ih_flags |= IH_MPSAFE;
247 	if (flags & INTR_ENTROPY)
248 		ih->ih_flags |= IH_ENTROPY;
249 
250 	mtx_lock_spin(&ithread_list_lock);
251 	if ((flags & INTR_EXCL) !=0 && !TAILQ_EMPTY(&ithread->it_handlers))
252 		goto fail;
253 	if (!TAILQ_EMPTY(&ithread->it_handlers) &&
254 	    (TAILQ_FIRST(&ithread->it_handlers)->ih_flags & IH_EXCLUSIVE) != 0)
255 		goto fail;
256 
257 	TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next)
258 	    if (temp_ih->ih_pri > ih->ih_pri)
259 		    break;
260 	if (temp_ih == NULL)
261 		TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next);
262 	else
263 		TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next);
264 	ithread_update(ithread);
265 	mtx_unlock_spin(&ithread_list_lock);
266 
267 	if (cookiep != NULL)
268 		*cookiep = ih;
269 	CTR2(KTR_INTR, __func__ ": added %s to %s", ih->ih_name,
270 	    ithread->it_name);
271 	return (0);
272 
273 fail:
274 	mtx_unlock_spin(&ithread_list_lock);
275 	free(ih, M_ITHREAD);
276 	return (EINVAL);
277 }
278 
279 int
280 ithread_remove_handler(void *cookie)
281 {
282 	struct intrhand *handler = (struct intrhand *)cookie;
283 	struct ithd *ithread;
284 #ifdef INVARIANTS
285 	struct intrhand *ih;
286 #endif
287 
288 	if (handler == NULL)
289 		return (EINVAL);
290 	ithread = handler->ih_ithread;
291 	KASSERT(ithread != NULL,
292 	    ("interrupt handler \"%s\" has a NULL interrupt thread",
293 		handler->ih_name));
294 	CTR2(KTR_INTR, __func__ ": removing %s from %s", handler->ih_name,
295 	    ithread->it_name);
296 	mtx_lock_spin(&ithread_list_lock);
297 #ifdef INVARIANTS
298 	TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next)
299 		if (ih == handler)
300 			goto ok;
301 	mtx_unlock_spin(&ithread_list_lock);
302 	panic("interrupt handler \"%s\" not found in interrupt thread \"%s\"",
303 	    ih->ih_name, ithread->it_name);
304 ok:
305 #endif
306 	/*
307 	 * If the interrupt thread is already running, then just mark this
308 	 * handler as being dead and let the ithread do the actual removal.
309 	 */
310 	mtx_lock_spin(&sched_lock);
311 	if (ithread->it_proc->p_stat != SWAIT) {
312 		handler->ih_flags |= IH_DEAD;
313 
314 		/*
315 		 * Ensure that the thread will process the handler list
316 		 * again and remove this handler if it has already passed
317 		 * it on the list.
318 		 */
319 		ithread->it_need = 1;
320 	} else {
321 		TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next);
322 		ithread_update(ithread);
323 	}
324 	mtx_unlock_spin(&sched_lock);
325 	mtx_unlock_spin(&ithread_list_lock);
326 
327 	if ((handler->ih_flags & IH_DEAD) == 0)
328 		free(handler, M_ITHREAD);
329 	return (0);
330 }
331 
332 int
333 ithread_schedule(struct ithd *ithread, int do_switch)
334 {
335 	struct int_entropy entropy;
336 	struct proc *p;
337 	critical_t savecrit;
338 
339 	/*
340 	 * If no ithread or no handlers, then we have a stray interrupt.
341 	 */
342 	if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers))
343 		return (EINVAL);
344 
345 	/*
346 	 * If any of the handlers for this ithread claim to be good
347 	 * sources of entropy, then gather some.
348 	 */
349 	if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) {
350 		entropy.vector = ithread->it_vector;
351 		entropy.proc = CURPROC;
352 		random_harvest(&entropy, sizeof(entropy), 2, 0,
353 		    RANDOM_INTERRUPT);
354 	}
355 
356 	p = ithread->it_proc;
357 	KASSERT(p != NULL, ("ithread %s has no process", ithread->it_name));
358 	CTR3(KTR_INTR, __func__ ": pid %d: (%s) need = %d", p->p_pid, p->p_comm,
359 	    ithread->it_need);
360 
361 	/*
362 	 * Set it_need to tell the thread to keep running if it is already
363 	 * running.  Then, grab sched_lock and see if we actually need to
364 	 * put this thread on the runqueue.  If so and the do_switch flag is
365 	 * true, then switch to the ithread immediately.  Otherwise, use
366 	 * need_resched() to guarantee that this ithread will run before any
367 	 * userland processes.
368 	 */
369 	ithread->it_need = 1;
370 	mtx_lock_spin(&sched_lock);
371 	if (p->p_stat == SWAIT) {
372 		CTR1(KTR_INTR, __func__ ": setrunqueue %d", p->p_pid);
373 		p->p_stat = SRUN;
374 		setrunqueue(p);
375 		if (do_switch && curproc->p_stat == SRUN) {
376 			savecrit = sched_lock.mtx_savecrit;
377 			mtx_intr_enable(&sched_lock);
378 			if (curproc != PCPU_GET(idleproc))
379 				setrunqueue(curproc);
380 			curproc->p_stats->p_ru.ru_nvcsw++;
381 			mi_switch();
382 			sched_lock.mtx_savecrit = savecrit;
383 		} else
384 			need_resched(curproc);
385 	} else {
386 		CTR3(KTR_INTR, __func__ ": pid %d: it_need %d, state %d",
387 		    p->p_pid, ithread->it_need, p->p_stat);
388 	}
389 	mtx_unlock_spin(&sched_lock);
390 
391 	return (0);
392 }
393 
394 int
395 swi_add(struct ithd **ithdp, const char *name, driver_intr_t handler,
396 	    void *arg, int pri, enum intr_type flags, void **cookiep)
397 {
398 	struct ithd *ithd;
399 	int error;
400 
401 	if (flags & (INTR_FAST | INTR_ENTROPY))
402 		return (EINVAL);
403 
404 	ithd = (ithdp != NULL) ? *ithdp : NULL;
405 
406 	if (ithd != NULL) {
407 		if ((ithd->it_flags & IT_SOFT) == 0)
408 			return(EINVAL);
409 	} else {
410 		error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL,
411 		    "swi%d:", pri);
412 		if (error)
413 			return (error);
414 
415 		if (ithdp != NULL)
416 			*ithdp = ithd;
417 	}
418 	return (ithread_add_handler(ithd, name, handler, arg,
419 		    (pri * RQ_PPQ) + PI_SOFT, flags, cookiep));
420 }
421 
422 
423 /*
424  * Schedule a heavyweight software interrupt process.
425  */
426 void
427 swi_sched(void *cookie, int flags)
428 {
429 	struct intrhand *ih = (struct intrhand *)cookie;
430 	struct ithd *it = ih->ih_ithread;
431 	int error;
432 
433 	atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */
434 
435 	CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d",
436 		it->it_proc->p_pid, it->it_proc->p_comm, it->it_need);
437 
438 	/*
439 	 * Set ih_need for this handler so that if the ithread is already
440 	 * running it will execute this handler on the next pass.  Otherwise,
441 	 * it will execute it the next time it runs.
442 	 */
443 	atomic_store_rel_int(&ih->ih_need, 1);
444 	if (!(flags & SWI_DELAY)) {
445 		error = ithread_schedule(it, !cold && flags & SWI_SWITCH);
446 		KASSERT(error == 0, ("stray software interrupt"));
447 	}
448 }
449 
450 /*
451  * This is the main code for interrupt threads.
452  */
453 void
454 ithread_loop(void *arg)
455 {
456 	struct ithd *ithd;		/* our thread context */
457 	struct intrhand *ih;		/* and our interrupt handler chain */
458 	struct proc *p;
459 
460 	p = curproc;
461 	ithd = (struct ithd *)arg;	/* point to myself */
462 	KASSERT(ithd->it_proc == p && p->p_ithd == ithd,
463 	    (__func__ ": ithread and proc linkage out of sync"));
464 
465 	/*
466 	 * As long as we have interrupts outstanding, go through the
467 	 * list of handlers, giving each one a go at it.
468 	 */
469 	for (;;) {
470 		/*
471 		 * If we are an orphaned thread, then just die.
472 		 */
473 		if (ithd->it_flags & IT_DEAD) {
474 			CTR2(KTR_INTR, __func__ ": pid %d: (%s) exiting",
475 			    p->p_pid, p->p_comm);
476 			p->p_ithd = NULL;
477 			mtx_lock(&Giant);
478 			free(ithd, M_ITHREAD);
479 			kthread_exit(0);
480 		}
481 
482 		CTR3(KTR_INTR, __func__ ": pid %d: (%s) need=%d",
483 		     p->p_pid, p->p_comm, ithd->it_need);
484 		while (ithd->it_need) {
485 			/*
486 			 * Service interrupts.  If another interrupt
487 			 * arrives while we are running, they will set
488 			 * it_need to denote that we should make
489 			 * another pass.
490 			 */
491 			atomic_store_rel_int(&ithd->it_need, 0);
492 restart:
493 			TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) {
494 				if (ithd->it_flags & IT_SOFT && !ih->ih_need)
495 					continue;
496 				atomic_store_rel_int(&ih->ih_need, 0);
497 				CTR5(KTR_INTR,
498 				    __func__ ": pid %d ih=%p: %p(%p) flg=%x",
499 				    p->p_pid, (void *)ih,
500 				    (void *)ih->ih_handler, ih->ih_argument,
501 				    ih->ih_flags);
502 
503 				if ((ih->ih_flags & IH_MPSAFE) == 0)
504 					mtx_lock(&Giant);
505 				if ((ih->ih_flags & IH_DEAD) != 0) {
506 					mtx_lock_spin(&ithread_list_lock);
507 					TAILQ_REMOVE(&ithd->it_handlers, ih,
508 					    ih_next);
509 					ithread_update(ithd);
510 					mtx_unlock_spin(&ithread_list_lock);
511 					if (!mtx_owned(&Giant))
512 						mtx_lock(&Giant);
513 					free(ih, M_ITHREAD);
514 					mtx_unlock(&Giant);
515 					goto restart;
516 				}
517 				ih->ih_handler(ih->ih_argument);
518 				if ((ih->ih_flags & IH_MPSAFE) == 0)
519 					mtx_unlock(&Giant);
520 			}
521 		}
522 
523 		/*
524 		 * Processed all our interrupts.  Now get the sched
525 		 * lock.  This may take a while and it_need may get
526 		 * set again, so we have to check it again.
527 		 */
528 		mtx_assert(&Giant, MA_NOTOWNED);
529 		mtx_lock_spin(&sched_lock);
530 		if (!ithd->it_need) {
531 			/*
532 			 * Should we call this earlier in the loop above?
533 			 */
534 			if (ithd->it_enable != NULL)
535 				ithd->it_enable(ithd->it_vector);
536 			p->p_stat = SWAIT; /* we're idle */
537 			CTR1(KTR_INTR, __func__ ": pid %d: done", p->p_pid);
538 			mi_switch();
539 			CTR1(KTR_INTR, __func__ ": pid %d: resumed", p->p_pid);
540 		}
541 		mtx_unlock_spin(&sched_lock);
542 	}
543 }
544 
545 /*
546  * Initialize mutex used to protect ithread handler lists.
547  */
548 static void
549 ithread_init(void *dummy)
550 {
551 
552 	mtx_init(&ithread_list_lock, "ithread list lock", MTX_SPIN);
553 }
554 SYSINIT(ithread_init, SI_SUB_INTR, SI_ORDER_FIRST, ithread_init, NULL);
555 
556 /*
557  * Start standard software interrupt threads
558  */
559 static void
560 start_softintr(void *dummy)
561 {
562 
563 	if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, 0, &net_ih) ||
564 	    swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK,
565 		INTR_MPSAFE, &softclock_ih) ||
566 	    swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, 0, &vm_ih))
567 		panic("died while creating standard software ithreads");
568 
569 	PROC_LOCK(clk_ithd->it_proc);
570 	clk_ithd->it_proc->p_flag |= P_NOLOAD;
571 	PROC_UNLOCK(clk_ithd->it_proc);
572 }
573 SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL)
574 
575 void
576 legacy_setsoftnet(void)
577 {
578 	swi_sched(net_ih, SWI_NOSWITCH);
579 }
580 
581 /*
582  * XXX: This should really be in the network code somewhere and installed
583  * via a SI_SUB_SOFINTR, SI_ORDER_MIDDLE sysinit.
584  */
585 void	(*netisrs[32]) __P((void));
586 u_int	netisr;
587 
588 int
589 register_netisr(num, handler)
590 	int num;
591 	netisr_t *handler;
592 {
593 
594 	if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) {
595 		printf("register_netisr: bad isr number: %d\n", num);
596 		return (EINVAL);
597 	}
598 	netisrs[num] = handler;
599 	return (0);
600 }
601 
602 int
603 unregister_netisr(num)
604 	int num;
605 {
606 
607 	if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) {
608 		printf("unregister_netisr: bad isr number: %d\n", num);
609 		return (EINVAL);
610 	}
611 	netisrs[num] = NULL;
612 	return (0);
613 }
614 
615 static void
616 swi_net(void *dummy)
617 {
618 	u_int bits;
619 	int i;
620 
621 	bits = atomic_readandclear_int(&netisr);
622 	while ((i = ffs(bits)) != 0) {
623 		i--;
624 		if (netisrs[i] != NULL)
625 			netisrs[i]();
626 		else
627 			printf("swi_net: unregistered isr number: %d.\n", i);
628 		bits &= ~(1 << i);
629 	}
630 }
631