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