1425f9fdaSStefan Eßer /* 2425f9fdaSStefan Eßer * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3425f9fdaSStefan Eßer * All rights reserved. 4425f9fdaSStefan Eßer * 5425f9fdaSStefan Eßer * Redistribution and use in source and binary forms, with or without 6425f9fdaSStefan Eßer * modification, are permitted provided that the following conditions 7425f9fdaSStefan Eßer * are met: 8425f9fdaSStefan Eßer * 1. Redistributions of source code must retain the above copyright 9425f9fdaSStefan Eßer * notice unmodified, this list of conditions, and the following 10425f9fdaSStefan Eßer * disclaimer. 11425f9fdaSStefan Eßer * 2. Redistributions in binary form must reproduce the above copyright 12425f9fdaSStefan Eßer * notice, this list of conditions and the following disclaimer in the 13425f9fdaSStefan Eßer * documentation and/or other materials provided with the distribution. 14425f9fdaSStefan Eßer * 15425f9fdaSStefan Eßer * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16425f9fdaSStefan Eßer * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17425f9fdaSStefan Eßer * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18425f9fdaSStefan Eßer * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19425f9fdaSStefan Eßer * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20425f9fdaSStefan Eßer * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21425f9fdaSStefan Eßer * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22425f9fdaSStefan Eßer * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23425f9fdaSStefan Eßer * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24425f9fdaSStefan Eßer * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25425f9fdaSStefan Eßer * 26c3aac50fSPeter Wemm * $FreeBSD$ 27425f9fdaSStefan Eßer * 28425f9fdaSStefan Eßer */ 29425f9fdaSStefan Eßer 303900ddb2SDoug Rabson 311c5bb3eaSPeter Wemm #include <sys/param.h> 329a94c9c5SJohn Baldwin #include <sys/bus.h> 339a94c9c5SJohn Baldwin #include <sys/rtprio.h> 34425f9fdaSStefan Eßer #include <sys/systm.h> 351931cf94SJohn Baldwin #include <sys/ipl.h> 3668352337SDoug Rabson #include <sys/interrupt.h> 371931cf94SJohn Baldwin #include <sys/kernel.h> 381931cf94SJohn Baldwin #include <sys/kthread.h> 391931cf94SJohn Baldwin #include <sys/ktr.h> 40f34fa851SJohn Baldwin #include <sys/lock.h> 411931cf94SJohn Baldwin #include <sys/malloc.h> 4235e0e5b3SJohn Baldwin #include <sys/mutex.h> 431931cf94SJohn Baldwin #include <sys/proc.h> 443e5da754SJohn Baldwin #include <sys/random.h> 45b4151f71SJohn Baldwin #include <sys/resourcevar.h> 461931cf94SJohn Baldwin #include <sys/unistd.h> 471931cf94SJohn Baldwin #include <sys/vmmeter.h> 481931cf94SJohn Baldwin #include <machine/atomic.h> 491931cf94SJohn Baldwin #include <machine/cpu.h> 508088699fSJohn Baldwin #include <machine/md_var.h> 51b4151f71SJohn Baldwin #include <machine/stdarg.h> 52425f9fdaSStefan Eßer 538088699fSJohn Baldwin #include <net/netisr.h> /* prototype for legacy_setsoftnet */ 5418c5a6c4SBruce Evans 553e5da754SJohn Baldwin struct int_entropy { 563e5da754SJohn Baldwin struct proc *proc; 573e5da754SJohn Baldwin int vector; 583e5da754SJohn Baldwin }; 593e5da754SJohn Baldwin 60b4151f71SJohn Baldwin void *net_ih; 61b4151f71SJohn Baldwin void *vm_ih; 62b4151f71SJohn Baldwin void *softclock_ih; 638088699fSJohn Baldwin struct ithd *clk_ithd; 648088699fSJohn Baldwin struct ithd *tty_ithd; 651931cf94SJohn Baldwin 66b4151f71SJohn Baldwin static struct mtx ithread_list_lock; 67b4151f71SJohn Baldwin 68b4151f71SJohn Baldwin static MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads"); 69b4151f71SJohn Baldwin 70b4151f71SJohn Baldwin static void ithread_update(struct ithd *); 71b4151f71SJohn Baldwin static void ithread_loop(void *); 72b4151f71SJohn Baldwin static void ithread_init(void *); 731931cf94SJohn Baldwin static void start_softintr(void *); 748088699fSJohn Baldwin static void swi_net(void *); 7518c5a6c4SBruce Evans 76b4151f71SJohn Baldwin u_char 77b4151f71SJohn Baldwin ithread_priority(enum intr_type flags) 789a94c9c5SJohn Baldwin { 79b4151f71SJohn Baldwin u_char pri; 809a94c9c5SJohn Baldwin 81b4151f71SJohn Baldwin flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET | 82b4151f71SJohn Baldwin INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK); 839a94c9c5SJohn Baldwin switch (flags) { 84b4151f71SJohn Baldwin case INTR_TYPE_TTY: 859a94c9c5SJohn Baldwin pri = PI_TTYLOW; 869a94c9c5SJohn Baldwin break; 879a94c9c5SJohn Baldwin case INTR_TYPE_BIO: 889a94c9c5SJohn Baldwin /* 899a94c9c5SJohn Baldwin * XXX We need to refine this. BSD/OS distinguishes 909a94c9c5SJohn Baldwin * between tape and disk priorities. 919a94c9c5SJohn Baldwin */ 929a94c9c5SJohn Baldwin pri = PI_DISK; 939a94c9c5SJohn Baldwin break; 949a94c9c5SJohn Baldwin case INTR_TYPE_NET: 959a94c9c5SJohn Baldwin pri = PI_NET; 969a94c9c5SJohn Baldwin break; 979a94c9c5SJohn Baldwin case INTR_TYPE_CAM: 989a94c9c5SJohn Baldwin pri = PI_DISK; /* XXX or PI_CAM? */ 999a94c9c5SJohn Baldwin break; 100b4151f71SJohn Baldwin case INTR_TYPE_CLK: 101b4151f71SJohn Baldwin pri = PI_REALTIME; 102b4151f71SJohn Baldwin break; 1039a94c9c5SJohn Baldwin case INTR_TYPE_MISC: 1049a94c9c5SJohn Baldwin pri = PI_DULL; /* don't care */ 1059a94c9c5SJohn Baldwin break; 1069a94c9c5SJohn Baldwin default: 107b4151f71SJohn Baldwin /* We didn't specify an interrupt level. */ 1089a94c9c5SJohn Baldwin panic("ithread_priority: no interrupt type in flags"); 1099a94c9c5SJohn Baldwin } 1109a94c9c5SJohn Baldwin 1119a94c9c5SJohn Baldwin return pri; 1129a94c9c5SJohn Baldwin } 1139a94c9c5SJohn Baldwin 114b4151f71SJohn Baldwin /* 115b4151f71SJohn Baldwin * Regenerate the name (p_comm) and priority for a threaded interrupt thread. 116b4151f71SJohn Baldwin */ 117b4151f71SJohn Baldwin static void 118b4151f71SJohn Baldwin ithread_update(struct ithd *ithd) 119b4151f71SJohn Baldwin { 120b4151f71SJohn Baldwin struct intrhand *ih; 121b4151f71SJohn Baldwin struct proc *p; 122b4151f71SJohn Baldwin int entropy; 1238088699fSJohn Baldwin 124b4151f71SJohn Baldwin p = ithd->it_proc; 125b4151f71SJohn Baldwin if (p == NULL) 126b4151f71SJohn Baldwin return; 127b4151f71SJohn Baldwin 128b4151f71SJohn Baldwin strncpy(p->p_comm, ithd->it_name, sizeof(ithd->it_name)); 129b4151f71SJohn Baldwin ih = TAILQ_FIRST(&ithd->it_handlers); 130b4151f71SJohn Baldwin if (ih == NULL) { 131d5a08a60SJake Burkholder p->p_pri.pri_level = PRI_MAX_ITHD; 132b4151f71SJohn Baldwin ithd->it_flags &= ~IT_ENTROPY; 133b4151f71SJohn Baldwin return; 134b4151f71SJohn Baldwin } 135b4151f71SJohn Baldwin 136b4151f71SJohn Baldwin entropy = 0; 137d5a08a60SJake Burkholder p->p_pri.pri_level = ih->ih_pri; 1385b270b2aSJake Burkholder p->p_pri.pri_native = ih->ih_pri; 139b4151f71SJohn Baldwin TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 140b4151f71SJohn Baldwin if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 < 141b4151f71SJohn Baldwin sizeof(p->p_comm)) { 142b4151f71SJohn Baldwin strcat(p->p_comm, " "); 143b4151f71SJohn Baldwin strcat(p->p_comm, ih->ih_name); 144b4151f71SJohn Baldwin } else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) { 145b4151f71SJohn Baldwin if (p->p_comm[sizeof(p->p_comm) - 2] == '+') 146b4151f71SJohn Baldwin p->p_comm[sizeof(p->p_comm) - 2] = '*'; 147b4151f71SJohn Baldwin else 148b4151f71SJohn Baldwin p->p_comm[sizeof(p->p_comm) - 2] = '+'; 149b4151f71SJohn Baldwin } else 150b4151f71SJohn Baldwin strcat(p->p_comm, "+"); 151b4151f71SJohn Baldwin if (ih->ih_flags & IH_ENTROPY) 152b4151f71SJohn Baldwin entropy++; 153b4151f71SJohn Baldwin } 154b4151f71SJohn Baldwin 1553e5da754SJohn Baldwin if (entropy) 156b4151f71SJohn Baldwin ithd->it_flags |= IT_ENTROPY; 157b4151f71SJohn Baldwin else 158b4151f71SJohn Baldwin ithd->it_flags &= ~IT_ENTROPY; 159addec20cSJohn Baldwin 160addec20cSJohn Baldwin CTR1(KTR_INTR, __func__ ": updated %s\n", p->p_comm); 161b4151f71SJohn Baldwin } 162b4151f71SJohn Baldwin 163b4151f71SJohn Baldwin int 164b4151f71SJohn Baldwin ithread_create(struct ithd **ithread, int vector, int flags, 165b4151f71SJohn Baldwin void (*disable)(int), void (*enable)(int), const char *fmt, ...) 166b4151f71SJohn Baldwin { 167b4151f71SJohn Baldwin struct ithd *ithd; 168b4151f71SJohn Baldwin struct proc *p; 169b4151f71SJohn Baldwin int error; 170b4151f71SJohn Baldwin va_list ap; 171b4151f71SJohn Baldwin 1723e5da754SJohn Baldwin /* The only valid flag during creation is IT_SOFT. */ 1733e5da754SJohn Baldwin if ((flags & ~IT_SOFT) != 0) 1743e5da754SJohn Baldwin return (EINVAL); 1753e5da754SJohn Baldwin 176b4151f71SJohn Baldwin ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO); 177b4151f71SJohn Baldwin ithd->it_vector = vector; 178b4151f71SJohn Baldwin ithd->it_disable = disable; 179b4151f71SJohn Baldwin ithd->it_enable = enable; 180b4151f71SJohn Baldwin ithd->it_flags = flags; 181b4151f71SJohn Baldwin TAILQ_INIT(&ithd->it_handlers); 182b4151f71SJohn Baldwin 183b4151f71SJohn Baldwin va_start(ap, fmt); 184b4151f71SJohn Baldwin vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap); 185b4151f71SJohn Baldwin va_end(ap); 186b4151f71SJohn Baldwin 187b4151f71SJohn Baldwin error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID, 1881f723035SJohn Baldwin "%s", ithd->it_name); 189b4151f71SJohn Baldwin if (error) { 190b4151f71SJohn Baldwin free(ithd, M_ITHREAD); 191b4151f71SJohn Baldwin return (error); 192b4151f71SJohn Baldwin } 193d5a08a60SJake Burkholder p->p_pri.pri_class = PRI_ITHD; 194d5a08a60SJake Burkholder p->p_pri.pri_level = PRI_MAX_ITHD; 195b4151f71SJohn Baldwin p->p_stat = SWAIT; 196b4151f71SJohn Baldwin ithd->it_proc = p; 197b4151f71SJohn Baldwin p->p_ithd = ithd; 198b4151f71SJohn Baldwin if (ithread != NULL) 199b4151f71SJohn Baldwin *ithread = ithd; 200b4151f71SJohn Baldwin 201addec20cSJohn Baldwin CTR1(KTR_INTR, __func__ ": created %s", ithd->it_name); 202b4151f71SJohn Baldwin return (0); 203b4151f71SJohn Baldwin } 204b4151f71SJohn Baldwin 205b4151f71SJohn Baldwin int 206b4151f71SJohn Baldwin ithread_destroy(struct ithd *ithread) 207b4151f71SJohn Baldwin { 208b4151f71SJohn Baldwin 209b4151f71SJohn Baldwin if (ithread == NULL || !TAILQ_EMPTY(&ithread->it_handlers)) 210b4151f71SJohn Baldwin return (EINVAL); 211b4151f71SJohn Baldwin 212b4151f71SJohn Baldwin mtx_lock_spin(&sched_lock); 213b4151f71SJohn Baldwin ithread->it_flags |= IT_DEAD; 214b4151f71SJohn Baldwin if (ithread->it_proc->p_stat == SWAIT) { 215b4151f71SJohn Baldwin ithread->it_proc->p_stat = SRUN; 216b4151f71SJohn Baldwin setrunqueue(ithread->it_proc); 217b4151f71SJohn Baldwin } 218b4151f71SJohn Baldwin mtx_unlock_spin(&sched_lock); 219addec20cSJohn Baldwin CTR1(KTR_INTR, __func__ ": killing %s", ithread->it_name); 220b4151f71SJohn Baldwin return (0); 221b4151f71SJohn Baldwin } 222b4151f71SJohn Baldwin 223b4151f71SJohn Baldwin int 224b4151f71SJohn Baldwin ithread_add_handler(struct ithd* ithread, const char *name, 225b4151f71SJohn Baldwin driver_intr_t handler, void *arg, u_char pri, enum intr_type flags, 226b4151f71SJohn Baldwin void **cookiep) 227b4151f71SJohn Baldwin { 228b4151f71SJohn Baldwin struct intrhand *ih, *temp_ih; 229b4151f71SJohn Baldwin 230b4151f71SJohn Baldwin if (ithread == NULL || name == NULL || handler == NULL) 231b4151f71SJohn Baldwin return (EINVAL); 232b4151f71SJohn Baldwin if ((flags & INTR_FAST) !=0) 233b4151f71SJohn Baldwin flags |= INTR_EXCL; 234b4151f71SJohn Baldwin 235b4151f71SJohn Baldwin ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_WAITOK | M_ZERO); 236b4151f71SJohn Baldwin ih->ih_handler = handler; 237b4151f71SJohn Baldwin ih->ih_argument = arg; 238b4151f71SJohn Baldwin ih->ih_name = name; 239b4151f71SJohn Baldwin ih->ih_ithread = ithread; 240b4151f71SJohn Baldwin ih->ih_pri = pri; 241b4151f71SJohn Baldwin if (flags & INTR_FAST) 242b4151f71SJohn Baldwin ih->ih_flags = IH_FAST | IH_EXCLUSIVE; 243b4151f71SJohn Baldwin else if (flags & INTR_EXCL) 244b4151f71SJohn Baldwin ih->ih_flags = IH_EXCLUSIVE; 245b4151f71SJohn Baldwin if (flags & INTR_MPSAFE) 246b4151f71SJohn Baldwin ih->ih_flags |= IH_MPSAFE; 247b4151f71SJohn Baldwin if (flags & INTR_ENTROPY) 248b4151f71SJohn Baldwin ih->ih_flags |= IH_ENTROPY; 249b4151f71SJohn Baldwin 250b4151f71SJohn Baldwin mtx_lock_spin(&ithread_list_lock); 251b4151f71SJohn Baldwin if ((flags & INTR_EXCL) !=0 && !TAILQ_EMPTY(&ithread->it_handlers)) 252b4151f71SJohn Baldwin goto fail; 253b4151f71SJohn Baldwin if (!TAILQ_EMPTY(&ithread->it_handlers) && 254b4151f71SJohn Baldwin (TAILQ_FIRST(&ithread->it_handlers)->ih_flags & IH_EXCLUSIVE) != 0) 255b4151f71SJohn Baldwin goto fail; 256b4151f71SJohn Baldwin 257b4151f71SJohn Baldwin TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next) 258b4151f71SJohn Baldwin if (temp_ih->ih_pri > ih->ih_pri) 259b4151f71SJohn Baldwin break; 260b4151f71SJohn Baldwin if (temp_ih == NULL) 261b4151f71SJohn Baldwin TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next); 262b4151f71SJohn Baldwin else 263b4151f71SJohn Baldwin TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next); 264b4151f71SJohn Baldwin ithread_update(ithread); 265b4151f71SJohn Baldwin mtx_unlock_spin(&ithread_list_lock); 266b4151f71SJohn Baldwin 267b4151f71SJohn Baldwin if (cookiep != NULL) 268b4151f71SJohn Baldwin *cookiep = ih; 269addec20cSJohn Baldwin CTR2(KTR_INTR, __func__ ": added %s to %s", ih->ih_name, 270addec20cSJohn Baldwin ithread->it_name); 271b4151f71SJohn Baldwin return (0); 272b4151f71SJohn Baldwin 273b4151f71SJohn Baldwin fail: 274b4151f71SJohn Baldwin mtx_unlock_spin(&ithread_list_lock); 275b4151f71SJohn Baldwin free(ih, M_ITHREAD); 276b4151f71SJohn Baldwin return (EINVAL); 277b4151f71SJohn Baldwin } 278b4151f71SJohn Baldwin 279b4151f71SJohn Baldwin int 280b4151f71SJohn Baldwin ithread_remove_handler(void *cookie) 281b4151f71SJohn Baldwin { 282b4151f71SJohn Baldwin struct intrhand *handler = (struct intrhand *)cookie; 283b4151f71SJohn Baldwin struct ithd *ithread; 284b4151f71SJohn Baldwin #ifdef INVARIANTS 285b4151f71SJohn Baldwin struct intrhand *ih; 286b4151f71SJohn Baldwin #endif 287b4151f71SJohn Baldwin 2883e5da754SJohn Baldwin if (handler == NULL) 289b4151f71SJohn Baldwin return (EINVAL); 29076bd604eSJohn Baldwin ithread = handler->ih_ithread; 29176bd604eSJohn Baldwin KASSERT(ithread != NULL, 2923e5da754SJohn Baldwin ("interrupt handler \"%s\" has a NULL interrupt thread", 2933e5da754SJohn Baldwin handler->ih_name)); 294addec20cSJohn Baldwin CTR2(KTR_INTR, __func__ ": removing %s from %s", handler->ih_name, 295addec20cSJohn Baldwin ithread->it_name); 296b4151f71SJohn Baldwin mtx_lock_spin(&ithread_list_lock); 297b4151f71SJohn Baldwin #ifdef INVARIANTS 298b4151f71SJohn Baldwin TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next) 2993e5da754SJohn Baldwin if (ih == handler) 3003e5da754SJohn Baldwin goto ok; 301b4151f71SJohn Baldwin mtx_unlock_spin(&ithread_list_lock); 3023e5da754SJohn Baldwin panic("interrupt handler \"%s\" not found in interrupt thread \"%s\"", 3033e5da754SJohn Baldwin ih->ih_name, ithread->it_name); 3043e5da754SJohn Baldwin ok: 305b4151f71SJohn Baldwin #endif 306de271f01SJohn Baldwin /* 307de271f01SJohn Baldwin * If the interrupt thread is already running, then just mark this 308de271f01SJohn Baldwin * handler as being dead and let the ithread do the actual removal. 309de271f01SJohn Baldwin */ 310de271f01SJohn Baldwin mtx_lock_spin(&sched_lock); 311de271f01SJohn Baldwin if (ithread->it_proc->p_stat != SWAIT) { 312de271f01SJohn Baldwin handler->ih_flags |= IH_DEAD; 313de271f01SJohn Baldwin 314de271f01SJohn Baldwin /* 315de271f01SJohn Baldwin * Ensure that the thread will process the handler list 316de271f01SJohn Baldwin * again and remove this handler if it has already passed 317de271f01SJohn Baldwin * it on the list. 318de271f01SJohn Baldwin */ 319de271f01SJohn Baldwin ithread->it_need = 1; 320de271f01SJohn Baldwin } else { 321b4151f71SJohn Baldwin TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next); 322b4151f71SJohn Baldwin ithread_update(ithread); 323de271f01SJohn Baldwin } 324de271f01SJohn Baldwin mtx_unlock_spin(&sched_lock); 325b4151f71SJohn Baldwin mtx_unlock_spin(&ithread_list_lock); 326b4151f71SJohn Baldwin 327de271f01SJohn Baldwin if ((handler->ih_flags & IH_DEAD) == 0) 328b4151f71SJohn Baldwin free(handler, M_ITHREAD); 329b4151f71SJohn Baldwin return (0); 330b4151f71SJohn Baldwin } 331b4151f71SJohn Baldwin 332b4151f71SJohn Baldwin int 3333e5da754SJohn Baldwin ithread_schedule(struct ithd *ithread, int do_switch) 3343e5da754SJohn Baldwin { 3353e5da754SJohn Baldwin struct int_entropy entropy; 3363e5da754SJohn Baldwin struct proc *p; 337b944b903SJohn Baldwin critical_t savecrit; 3383e5da754SJohn Baldwin 3393e5da754SJohn Baldwin /* 3403e5da754SJohn Baldwin * If no ithread or no handlers, then we have a stray interrupt. 3413e5da754SJohn Baldwin */ 3423e5da754SJohn Baldwin if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers)) 3433e5da754SJohn Baldwin return (EINVAL); 3443e5da754SJohn Baldwin 3453e5da754SJohn Baldwin /* 3463e5da754SJohn Baldwin * If any of the handlers for this ithread claim to be good 3473e5da754SJohn Baldwin * sources of entropy, then gather some. 3483e5da754SJohn Baldwin */ 3493e5da754SJohn Baldwin if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) { 3503e5da754SJohn Baldwin entropy.vector = ithread->it_vector; 3513e5da754SJohn Baldwin entropy.proc = CURPROC; 3523e5da754SJohn Baldwin random_harvest(&entropy, sizeof(entropy), 2, 0, 3533e5da754SJohn Baldwin RANDOM_INTERRUPT); 3543e5da754SJohn Baldwin } 3553e5da754SJohn Baldwin 3563e5da754SJohn Baldwin p = ithread->it_proc; 357653dd8c2SJohn Baldwin KASSERT(p != NULL, ("ithread %s has no process", ithread->it_name)); 3583e5da754SJohn Baldwin CTR3(KTR_INTR, __func__ ": pid %d: (%s) need = %d", p->p_pid, p->p_comm, 3593e5da754SJohn Baldwin ithread->it_need); 3603e5da754SJohn Baldwin 3613e5da754SJohn Baldwin /* 3623e5da754SJohn Baldwin * Set it_need to tell the thread to keep running if it is already 3633e5da754SJohn Baldwin * running. Then, grab sched_lock and see if we actually need to 3643e5da754SJohn Baldwin * put this thread on the runqueue. If so and the do_switch flag is 3653e5da754SJohn Baldwin * true, then switch to the ithread immediately. Otherwise, use 3663e5da754SJohn Baldwin * need_resched() to guarantee that this ithread will run before any 3673e5da754SJohn Baldwin * userland processes. 3683e5da754SJohn Baldwin */ 3693e5da754SJohn Baldwin ithread->it_need = 1; 3703e5da754SJohn Baldwin mtx_lock_spin(&sched_lock); 3713e5da754SJohn Baldwin if (p->p_stat == SWAIT) { 3723e5da754SJohn Baldwin CTR1(KTR_INTR, __func__ ": setrunqueue %d", p->p_pid); 3733e5da754SJohn Baldwin p->p_stat = SRUN; 3743e5da754SJohn Baldwin setrunqueue(p); 375653dd8c2SJohn Baldwin if (do_switch && curproc->p_stat == SRUN) { 376b944b903SJohn Baldwin savecrit = sched_lock.mtx_savecrit; 3773e5da754SJohn Baldwin mtx_intr_enable(&sched_lock); 3783e5da754SJohn Baldwin if (curproc != PCPU_GET(idleproc)) 3793e5da754SJohn Baldwin setrunqueue(curproc); 3803e5da754SJohn Baldwin curproc->p_stats->p_ru.ru_nvcsw++; 3813e5da754SJohn Baldwin mi_switch(); 382b944b903SJohn Baldwin sched_lock.mtx_savecrit = savecrit; 3833e5da754SJohn Baldwin } else 3843e5da754SJohn Baldwin need_resched(); 3853e5da754SJohn Baldwin } else { 3863e5da754SJohn Baldwin CTR3(KTR_INTR, __func__ ": pid %d: it_need %d, state %d", 3873e5da754SJohn Baldwin p->p_pid, ithread->it_need, p->p_stat); 3883e5da754SJohn Baldwin } 3893e5da754SJohn Baldwin mtx_unlock_spin(&sched_lock); 3903e5da754SJohn Baldwin 3913e5da754SJohn Baldwin return (0); 3923e5da754SJohn Baldwin } 3933e5da754SJohn Baldwin 3943e5da754SJohn Baldwin int 395b4151f71SJohn Baldwin swi_add(struct ithd **ithdp, const char *name, driver_intr_t handler, 396b4151f71SJohn Baldwin void *arg, int pri, enum intr_type flags, void **cookiep) 3978088699fSJohn Baldwin { 3988088699fSJohn Baldwin struct ithd *ithd; 399b4151f71SJohn Baldwin int error; 4008088699fSJohn Baldwin 4013e5da754SJohn Baldwin if (flags & (INTR_FAST | INTR_ENTROPY)) 4023e5da754SJohn Baldwin return (EINVAL); 4033e5da754SJohn Baldwin 4048088699fSJohn Baldwin ithd = (ithdp != NULL) ? *ithdp : NULL; 4058088699fSJohn Baldwin 4063e5da754SJohn Baldwin if (ithd != NULL) { 4073e5da754SJohn Baldwin if ((ithd->it_flags & IT_SOFT) == 0) 4083e5da754SJohn Baldwin return(EINVAL); 4093e5da754SJohn Baldwin } else { 410b4151f71SJohn Baldwin error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL, 411b4151f71SJohn Baldwin "swi%d:", pri); 4128088699fSJohn Baldwin if (error) 413b4151f71SJohn Baldwin return (error); 414b4151f71SJohn Baldwin 4158088699fSJohn Baldwin if (ithdp != NULL) 4168088699fSJohn Baldwin *ithdp = ithd; 4178088699fSJohn Baldwin } 418d5a08a60SJake Burkholder return (ithread_add_handler(ithd, name, handler, arg, 419d5a08a60SJake Burkholder (pri * RQ_PPQ) + PI_SOFT, flags, cookiep)); 4208088699fSJohn Baldwin } 4218088699fSJohn Baldwin 4228088699fSJohn Baldwin 4231931cf94SJohn Baldwin /* 4248088699fSJohn Baldwin * Schedule a heavyweight software interrupt process. 4251931cf94SJohn Baldwin */ 4261931cf94SJohn Baldwin void 427b4151f71SJohn Baldwin swi_sched(void *cookie, int flags) 4281931cf94SJohn Baldwin { 429b4151f71SJohn Baldwin struct intrhand *ih = (struct intrhand *)cookie; 430b4151f71SJohn Baldwin struct ithd *it = ih->ih_ithread; 4313e5da754SJohn Baldwin int error; 4328088699fSJohn Baldwin 4331931cf94SJohn Baldwin atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */ 4341931cf94SJohn Baldwin 435b4151f71SJohn Baldwin CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d", 43660f2b032SJohn Baldwin it->it_proc->p_pid, it->it_proc->p_comm, it->it_need); 4371931cf94SJohn Baldwin 4381931cf94SJohn Baldwin /* 4393e5da754SJohn Baldwin * Set ih_need for this handler so that if the ithread is already 4403e5da754SJohn Baldwin * running it will execute this handler on the next pass. Otherwise, 4413e5da754SJohn Baldwin * it will execute it the next time it runs. 4421931cf94SJohn Baldwin */ 443b4151f71SJohn Baldwin atomic_store_rel_int(&ih->ih_need, 1); 444b4151f71SJohn Baldwin if (!(flags & SWI_DELAY)) { 4453e5da754SJohn Baldwin error = ithread_schedule(it, !cold && flags & SWI_SWITCH); 4463e5da754SJohn Baldwin KASSERT(error == 0, ("stray software interrupt")); 4478088699fSJohn Baldwin } 4488088699fSJohn Baldwin } 4498088699fSJohn Baldwin 4508088699fSJohn Baldwin /* 451b4151f71SJohn Baldwin * This is the main code for interrupt threads. 4528088699fSJohn Baldwin */ 4538088699fSJohn Baldwin void 454b4151f71SJohn Baldwin ithread_loop(void *arg) 4558088699fSJohn Baldwin { 456b4151f71SJohn Baldwin struct ithd *ithd; /* our thread context */ 4578088699fSJohn Baldwin struct intrhand *ih; /* and our interrupt handler chain */ 458b4151f71SJohn Baldwin struct proc *p; 4598088699fSJohn Baldwin 460b4151f71SJohn Baldwin p = curproc; 461b4151f71SJohn Baldwin ithd = (struct ithd *)arg; /* point to myself */ 462b4151f71SJohn Baldwin KASSERT(ithd->it_proc == p && p->p_ithd == ithd, 463b4151f71SJohn Baldwin (__func__ ": ithread and proc linkage out of sync")); 4648088699fSJohn Baldwin 4658088699fSJohn Baldwin /* 4668088699fSJohn Baldwin * As long as we have interrupts outstanding, go through the 4678088699fSJohn Baldwin * list of handlers, giving each one a go at it. 4688088699fSJohn Baldwin */ 4698088699fSJohn Baldwin for (;;) { 470b4151f71SJohn Baldwin /* 471b4151f71SJohn Baldwin * If we are an orphaned thread, then just die. 472b4151f71SJohn Baldwin */ 473b4151f71SJohn Baldwin if (ithd->it_flags & IT_DEAD) { 474b4151f71SJohn Baldwin CTR2(KTR_INTR, __func__ ": pid %d: (%s) exiting", 475b4151f71SJohn Baldwin p->p_pid, p->p_comm); 476b4151f71SJohn Baldwin p->p_ithd = NULL; 477b4151f71SJohn Baldwin mtx_lock(&Giant); 478b4151f71SJohn Baldwin free(ithd, M_ITHREAD); 479b4151f71SJohn Baldwin kthread_exit(0); 480b4151f71SJohn Baldwin } 481b4151f71SJohn Baldwin 482b4151f71SJohn Baldwin CTR3(KTR_INTR, __func__ ": pid %d: (%s) need=%d", 483b4151f71SJohn Baldwin p->p_pid, p->p_comm, ithd->it_need); 484b4151f71SJohn Baldwin while (ithd->it_need) { 4858088699fSJohn Baldwin /* 4868088699fSJohn Baldwin * Service interrupts. If another interrupt 4878088699fSJohn Baldwin * arrives while we are running, they will set 4888088699fSJohn Baldwin * it_need to denote that we should make 4898088699fSJohn Baldwin * another pass. 4908088699fSJohn Baldwin */ 491b4151f71SJohn Baldwin atomic_store_rel_int(&ithd->it_need, 0); 492de271f01SJohn Baldwin restart: 493b4151f71SJohn Baldwin TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 494b4151f71SJohn Baldwin if (ithd->it_flags & IT_SOFT && !ih->ih_need) 4958088699fSJohn Baldwin continue; 496b4151f71SJohn Baldwin atomic_store_rel_int(&ih->ih_need, 0); 4978088699fSJohn Baldwin CTR5(KTR_INTR, 498b4151f71SJohn Baldwin __func__ ": pid %d ih=%p: %p(%p) flg=%x", 4998088699fSJohn Baldwin p->p_pid, (void *)ih, 5008088699fSJohn Baldwin (void *)ih->ih_handler, ih->ih_argument, 5018088699fSJohn Baldwin ih->ih_flags); 5028088699fSJohn Baldwin 503b4151f71SJohn Baldwin if ((ih->ih_flags & IH_MPSAFE) == 0) 5049ed346baSBosko Milekic mtx_lock(&Giant); 505de271f01SJohn Baldwin if ((ih->ih_flags & IH_DEAD) != 0) { 506de271f01SJohn Baldwin mtx_lock_spin(&ithread_list_lock); 507de271f01SJohn Baldwin TAILQ_REMOVE(&ithd->it_handlers, ih, 508de271f01SJohn Baldwin ih_next); 509de271f01SJohn Baldwin ithread_update(ithd); 510de271f01SJohn Baldwin mtx_unlock_spin(&ithread_list_lock); 511de271f01SJohn Baldwin if (!mtx_owned(&Giant)) 512de271f01SJohn Baldwin mtx_lock(&Giant); 513de271f01SJohn Baldwin free(ih, M_ITHREAD); 514de271f01SJohn Baldwin mtx_unlock(&Giant); 515de271f01SJohn Baldwin goto restart; 516de271f01SJohn Baldwin } 5178088699fSJohn Baldwin ih->ih_handler(ih->ih_argument); 518b4151f71SJohn Baldwin if ((ih->ih_flags & IH_MPSAFE) == 0) 5199ed346baSBosko Milekic mtx_unlock(&Giant); 5208088699fSJohn Baldwin } 5218088699fSJohn Baldwin } 5228088699fSJohn Baldwin 5238088699fSJohn Baldwin /* 5248088699fSJohn Baldwin * Processed all our interrupts. Now get the sched 5258088699fSJohn Baldwin * lock. This may take a while and it_need may get 5268088699fSJohn Baldwin * set again, so we have to check it again. 5278088699fSJohn Baldwin */ 528896c2303SJohn Baldwin mtx_assert(&Giant, MA_NOTOWNED); 5299ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 530b4151f71SJohn Baldwin if (!ithd->it_need) { 531b4151f71SJohn Baldwin /* 532b4151f71SJohn Baldwin * Should we call this earlier in the loop above? 533b4151f71SJohn Baldwin */ 534b4151f71SJohn Baldwin if (ithd->it_enable != NULL) 535b4151f71SJohn Baldwin ithd->it_enable(ithd->it_vector); 5368088699fSJohn Baldwin p->p_stat = SWAIT; /* we're idle */ 537b4151f71SJohn Baldwin CTR1(KTR_INTR, __func__ ": pid %d: done", p->p_pid); 5388088699fSJohn Baldwin mi_switch(); 539b4151f71SJohn Baldwin CTR1(KTR_INTR, __func__ ": pid %d: resumed", p->p_pid); 5408088699fSJohn Baldwin } 5419ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 5428088699fSJohn Baldwin } 5431931cf94SJohn Baldwin } 5441931cf94SJohn Baldwin 545b4151f71SJohn Baldwin /* 546b4151f71SJohn Baldwin * Initialize mutex used to protect ithread handler lists. 547b4151f71SJohn Baldwin */ 548b4151f71SJohn Baldwin static void 549b4151f71SJohn Baldwin ithread_init(void *dummy) 550b4151f71SJohn Baldwin { 551b4151f71SJohn Baldwin 552b4151f71SJohn Baldwin mtx_init(&ithread_list_lock, "ithread list lock", MTX_SPIN); 553b4151f71SJohn Baldwin } 554b4151f71SJohn Baldwin SYSINIT(ithread_init, SI_SUB_INTR, SI_ORDER_FIRST, ithread_init, NULL); 5551931cf94SJohn Baldwin 5561931cf94SJohn Baldwin /* 5578088699fSJohn Baldwin * Start standard software interrupt threads 5581931cf94SJohn Baldwin */ 5591931cf94SJohn Baldwin static void 560b4151f71SJohn Baldwin start_softintr(void *dummy) 5611931cf94SJohn Baldwin { 562b4151f71SJohn Baldwin 563b4151f71SJohn Baldwin if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, 0, &net_ih) || 564b4151f71SJohn Baldwin swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK, 565b4151f71SJohn Baldwin INTR_MPSAFE, &softclock_ih) || 566b4151f71SJohn Baldwin swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, 0, &vm_ih)) 567b4151f71SJohn Baldwin panic("died while creating standard software ithreads"); 5683e5da754SJohn Baldwin 5693e5da754SJohn Baldwin PROC_LOCK(clk_ithd->it_proc); 5703e5da754SJohn Baldwin clk_ithd->it_proc->p_flag |= P_NOLOAD; 5713e5da754SJohn Baldwin PROC_UNLOCK(clk_ithd->it_proc); 5721931cf94SJohn Baldwin } 573b4151f71SJohn Baldwin SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL) 5741931cf94SJohn Baldwin 5751931cf94SJohn Baldwin void 576b4151f71SJohn Baldwin legacy_setsoftnet(void) 5771931cf94SJohn Baldwin { 578b4151f71SJohn Baldwin swi_sched(net_ih, SWI_NOSWITCH); 5791931cf94SJohn Baldwin } 5801931cf94SJohn Baldwin 5818088699fSJohn Baldwin /* 5828088699fSJohn Baldwin * XXX: This should really be in the network code somewhere and installed 5838088699fSJohn Baldwin * via a SI_SUB_SOFINTR, SI_ORDER_MIDDLE sysinit. 5848088699fSJohn Baldwin */ 5858088699fSJohn Baldwin void (*netisrs[32]) __P((void)); 5868088699fSJohn Baldwin u_int netisr; 5878088699fSJohn Baldwin 5881eb44f02SJake Burkholder int 5891eb44f02SJake Burkholder register_netisr(num, handler) 5901eb44f02SJake Burkholder int num; 5911eb44f02SJake Burkholder netisr_t *handler; 5921eb44f02SJake Burkholder { 5931eb44f02SJake Burkholder 5941eb44f02SJake Burkholder if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) { 5951eb44f02SJake Burkholder printf("register_netisr: bad isr number: %d\n", num); 5961eb44f02SJake Burkholder return (EINVAL); 5971eb44f02SJake Burkholder } 5981eb44f02SJake Burkholder netisrs[num] = handler; 5991eb44f02SJake Burkholder return (0); 6001eb44f02SJake Burkholder } 6011eb44f02SJake Burkholder 6021eb44f02SJake Burkholder int 6031eb44f02SJake Burkholder unregister_netisr(num) 6041eb44f02SJake Burkholder int num; 6051eb44f02SJake Burkholder { 6061eb44f02SJake Burkholder 6071eb44f02SJake Burkholder if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) { 6081eb44f02SJake Burkholder printf("unregister_netisr: bad isr number: %d\n", num); 6091eb44f02SJake Burkholder return (EINVAL); 6101eb44f02SJake Burkholder } 6111eb44f02SJake Burkholder netisrs[num] = NULL; 6121eb44f02SJake Burkholder return (0); 6131eb44f02SJake Burkholder } 6141eb44f02SJake Burkholder 6158088699fSJohn Baldwin static void 6168088699fSJohn Baldwin swi_net(void *dummy) 6171931cf94SJohn Baldwin { 6188088699fSJohn Baldwin u_int bits; 6198088699fSJohn Baldwin int i; 6208088699fSJohn Baldwin 6218088699fSJohn Baldwin bits = atomic_readandclear_int(&netisr); 6228088699fSJohn Baldwin while ((i = ffs(bits)) != 0) { 6238088699fSJohn Baldwin i--; 624338c0bc6SSeigo Tanimura if (netisrs[i] != NULL) 6258088699fSJohn Baldwin netisrs[i](); 626338c0bc6SSeigo Tanimura else 627338c0bc6SSeigo Tanimura printf("swi_net: unregistered isr number: %d.\n", i); 6288088699fSJohn Baldwin bits &= ~(1 << i); 6298088699fSJohn Baldwin } 6301931cf94SJohn Baldwin } 631