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> 401931cf94SJohn Baldwin #include <sys/malloc.h> 4135e0e5b3SJohn Baldwin #include <sys/mutex.h> 421931cf94SJohn Baldwin #include <sys/proc.h> 43b4151f71SJohn Baldwin #include <sys/resourcevar.h> 441931cf94SJohn Baldwin #include <sys/unistd.h> 451931cf94SJohn Baldwin #include <sys/vmmeter.h> 461931cf94SJohn Baldwin #include <machine/atomic.h> 471931cf94SJohn Baldwin #include <machine/cpu.h> 488088699fSJohn Baldwin #include <machine/md_var.h> 49b4151f71SJohn Baldwin #include <machine/stdarg.h> 50425f9fdaSStefan Eßer 518088699fSJohn Baldwin #include <net/netisr.h> /* prototype for legacy_setsoftnet */ 5218c5a6c4SBruce Evans 53b4151f71SJohn Baldwin void *net_ih; 54b4151f71SJohn Baldwin void *vm_ih; 55b4151f71SJohn Baldwin void *softclock_ih; 568088699fSJohn Baldwin struct ithd *clk_ithd; 578088699fSJohn Baldwin struct ithd *tty_ithd; 581931cf94SJohn Baldwin 59b4151f71SJohn Baldwin static struct mtx ithread_list_lock; 60b4151f71SJohn Baldwin 61b4151f71SJohn Baldwin static MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads"); 62b4151f71SJohn Baldwin 63b4151f71SJohn Baldwin static void ithread_update(struct ithd *); 64b4151f71SJohn Baldwin static void ithread_loop(void *); 65b4151f71SJohn Baldwin static void ithread_init(void *); 661931cf94SJohn Baldwin static void start_softintr(void *); 678088699fSJohn Baldwin static void swi_net(void *); 6818c5a6c4SBruce Evans 69b4151f71SJohn Baldwin u_char 70b4151f71SJohn Baldwin ithread_priority(enum intr_type flags) 719a94c9c5SJohn Baldwin { 72b4151f71SJohn Baldwin u_char pri; 739a94c9c5SJohn Baldwin 74b4151f71SJohn Baldwin flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET | 75b4151f71SJohn Baldwin INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK); 769a94c9c5SJohn Baldwin switch (flags) { 77b4151f71SJohn Baldwin case INTR_TYPE_TTY: 789a94c9c5SJohn Baldwin pri = PI_TTYLOW; 799a94c9c5SJohn Baldwin break; 809a94c9c5SJohn Baldwin case INTR_TYPE_BIO: 819a94c9c5SJohn Baldwin /* 829a94c9c5SJohn Baldwin * XXX We need to refine this. BSD/OS distinguishes 839a94c9c5SJohn Baldwin * between tape and disk priorities. 849a94c9c5SJohn Baldwin */ 859a94c9c5SJohn Baldwin pri = PI_DISK; 869a94c9c5SJohn Baldwin break; 879a94c9c5SJohn Baldwin case INTR_TYPE_NET: 889a94c9c5SJohn Baldwin pri = PI_NET; 899a94c9c5SJohn Baldwin break; 909a94c9c5SJohn Baldwin case INTR_TYPE_CAM: 919a94c9c5SJohn Baldwin pri = PI_DISK; /* XXX or PI_CAM? */ 929a94c9c5SJohn Baldwin break; 93b4151f71SJohn Baldwin case INTR_TYPE_CLK: 94b4151f71SJohn Baldwin pri = PI_REALTIME; 95b4151f71SJohn Baldwin break; 969a94c9c5SJohn Baldwin case INTR_TYPE_MISC: 979a94c9c5SJohn Baldwin pri = PI_DULL; /* don't care */ 989a94c9c5SJohn Baldwin break; 999a94c9c5SJohn Baldwin default: 100b4151f71SJohn Baldwin /* We didn't specify an interrupt level. */ 1019a94c9c5SJohn Baldwin panic("ithread_priority: no interrupt type in flags"); 1029a94c9c5SJohn Baldwin } 1039a94c9c5SJohn Baldwin 1049a94c9c5SJohn Baldwin return pri; 1059a94c9c5SJohn Baldwin } 1069a94c9c5SJohn Baldwin 107b4151f71SJohn Baldwin /* 108b4151f71SJohn Baldwin * Regenerate the name (p_comm) and priority for a threaded interrupt thread. 109b4151f71SJohn Baldwin */ 110b4151f71SJohn Baldwin static void 111b4151f71SJohn Baldwin ithread_update(struct ithd *ithd) 112b4151f71SJohn Baldwin { 113b4151f71SJohn Baldwin struct intrhand *ih; 114b4151f71SJohn Baldwin struct proc *p; 115b4151f71SJohn Baldwin int entropy; 1168088699fSJohn Baldwin 117b4151f71SJohn Baldwin p = ithd->it_proc; 118b4151f71SJohn Baldwin if (p == NULL) 119b4151f71SJohn Baldwin return; 120b4151f71SJohn Baldwin 121b4151f71SJohn Baldwin strncpy(p->p_comm, ithd->it_name, sizeof(ithd->it_name)); 122b4151f71SJohn Baldwin ih = TAILQ_FIRST(&ithd->it_handlers); 123b4151f71SJohn Baldwin if (ih == NULL) { 124b4151f71SJohn Baldwin p->p_rtprio.prio = RTP_PRIO_MAX; 125b4151f71SJohn Baldwin ithd->it_flags &= ~IT_ENTROPY; 126b4151f71SJohn Baldwin return; 127b4151f71SJohn Baldwin } 128b4151f71SJohn Baldwin 129b4151f71SJohn Baldwin entropy = 0; 130b4151f71SJohn Baldwin p->p_rtprio.prio = ih->ih_pri; 131b4151f71SJohn Baldwin TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 132b4151f71SJohn Baldwin if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 < 133b4151f71SJohn Baldwin sizeof(p->p_comm)) { 134b4151f71SJohn Baldwin strcat(p->p_comm, " "); 135b4151f71SJohn Baldwin strcat(p->p_comm, ih->ih_name); 136b4151f71SJohn Baldwin } else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) { 137b4151f71SJohn Baldwin if (p->p_comm[sizeof(p->p_comm) - 2] == '+') 138b4151f71SJohn Baldwin p->p_comm[sizeof(p->p_comm) - 2] = '*'; 139b4151f71SJohn Baldwin else 140b4151f71SJohn Baldwin p->p_comm[sizeof(p->p_comm) - 2] = '+'; 141b4151f71SJohn Baldwin } else 142b4151f71SJohn Baldwin strcat(p->p_comm, "+"); 143b4151f71SJohn Baldwin if (ih->ih_flags & IH_ENTROPY) 144b4151f71SJohn Baldwin entropy++; 145b4151f71SJohn Baldwin } 146b4151f71SJohn Baldwin 147b4151f71SJohn Baldwin if (entropy) { 148b4151f71SJohn Baldwin printf("Warning, ithread (%d, %s) is an entropy source.\n", 149b4151f71SJohn Baldwin p->p_pid, p->p_comm); 150b4151f71SJohn Baldwin ithd->it_flags |= IT_ENTROPY; 151b4151f71SJohn Baldwin } 152b4151f71SJohn Baldwin else 153b4151f71SJohn Baldwin ithd->it_flags &= ~IT_ENTROPY; 154b4151f71SJohn Baldwin } 155b4151f71SJohn Baldwin 156b4151f71SJohn Baldwin int 157b4151f71SJohn Baldwin ithread_create(struct ithd **ithread, int vector, int flags, 158b4151f71SJohn Baldwin void (*disable)(int), void (*enable)(int), const char *fmt, ...) 159b4151f71SJohn Baldwin { 160b4151f71SJohn Baldwin struct ithd *ithd; 161b4151f71SJohn Baldwin struct proc *p; 162b4151f71SJohn Baldwin int error; 163b4151f71SJohn Baldwin va_list ap; 164b4151f71SJohn Baldwin 165b4151f71SJohn Baldwin ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO); 166b4151f71SJohn Baldwin ithd->it_vector = vector; 167b4151f71SJohn Baldwin ithd->it_disable = disable; 168b4151f71SJohn Baldwin ithd->it_enable = enable; 169b4151f71SJohn Baldwin ithd->it_flags = flags; 170b4151f71SJohn Baldwin TAILQ_INIT(&ithd->it_handlers); 171b4151f71SJohn Baldwin 172b4151f71SJohn Baldwin va_start(ap, fmt); 173b4151f71SJohn Baldwin vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap); 174b4151f71SJohn Baldwin va_end(ap); 175b4151f71SJohn Baldwin 176b4151f71SJohn Baldwin error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID, 177b4151f71SJohn Baldwin ithd->it_name); 178b4151f71SJohn Baldwin if (error) { 179b4151f71SJohn Baldwin free(ithd, M_ITHREAD); 180b4151f71SJohn Baldwin return (error); 181b4151f71SJohn Baldwin } 182b4151f71SJohn Baldwin p->p_rtprio.type = RTP_PRIO_ITHREAD; 183b4151f71SJohn Baldwin p->p_rtprio.prio = RTP_PRIO_MAX; 184b4151f71SJohn Baldwin p->p_stat = SWAIT; 185b4151f71SJohn Baldwin ithd->it_proc = p; 186b4151f71SJohn Baldwin p->p_ithd = ithd; 187b4151f71SJohn Baldwin if (ithread != NULL) 188b4151f71SJohn Baldwin *ithread = ithd; 189b4151f71SJohn Baldwin 190b4151f71SJohn Baldwin return (0); 191b4151f71SJohn Baldwin } 192b4151f71SJohn Baldwin 193b4151f71SJohn Baldwin int 194b4151f71SJohn Baldwin ithread_destroy(struct ithd *ithread) 195b4151f71SJohn Baldwin { 196b4151f71SJohn Baldwin 197b4151f71SJohn Baldwin if (ithread == NULL || !TAILQ_EMPTY(&ithread->it_handlers)) 198b4151f71SJohn Baldwin return (EINVAL); 199b4151f71SJohn Baldwin 200b4151f71SJohn Baldwin mtx_lock_spin(&sched_lock); 201b4151f71SJohn Baldwin ithread->it_flags |= IT_DEAD; 202b4151f71SJohn Baldwin if (ithread->it_proc->p_stat == SWAIT) { 203b4151f71SJohn Baldwin ithread->it_proc->p_stat = SRUN; 204b4151f71SJohn Baldwin setrunqueue(ithread->it_proc); 205b4151f71SJohn Baldwin } 206b4151f71SJohn Baldwin mtx_unlock_spin(&sched_lock); 207b4151f71SJohn Baldwin return (0); 208b4151f71SJohn Baldwin } 209b4151f71SJohn Baldwin 210b4151f71SJohn Baldwin int 211b4151f71SJohn Baldwin ithread_add_handler(struct ithd* ithread, const char *name, 212b4151f71SJohn Baldwin driver_intr_t handler, void *arg, u_char pri, enum intr_type flags, 213b4151f71SJohn Baldwin void **cookiep) 214b4151f71SJohn Baldwin { 215b4151f71SJohn Baldwin struct intrhand *ih, *temp_ih; 216b4151f71SJohn Baldwin 217b4151f71SJohn Baldwin if (ithread == NULL || name == NULL || handler == NULL) 218b4151f71SJohn Baldwin return (EINVAL); 219b4151f71SJohn Baldwin if ((flags & INTR_FAST) !=0) 220b4151f71SJohn Baldwin flags |= INTR_EXCL; 221b4151f71SJohn Baldwin 222b4151f71SJohn Baldwin ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_WAITOK | M_ZERO); 223b4151f71SJohn Baldwin ih->ih_handler = handler; 224b4151f71SJohn Baldwin ih->ih_argument = arg; 225b4151f71SJohn Baldwin ih->ih_name = name; 226b4151f71SJohn Baldwin ih->ih_ithread = ithread; 227b4151f71SJohn Baldwin ih->ih_pri = pri; 228b4151f71SJohn Baldwin if (flags & INTR_FAST) 229b4151f71SJohn Baldwin ih->ih_flags = IH_FAST | IH_EXCLUSIVE; 230b4151f71SJohn Baldwin else if (flags & INTR_EXCL) 231b4151f71SJohn Baldwin ih->ih_flags = IH_EXCLUSIVE; 232b4151f71SJohn Baldwin if (flags & INTR_MPSAFE) 233b4151f71SJohn Baldwin ih->ih_flags |= IH_MPSAFE; 234b4151f71SJohn Baldwin if (flags & INTR_ENTROPY) 235b4151f71SJohn Baldwin ih->ih_flags |= IH_ENTROPY; 236b4151f71SJohn Baldwin 237b4151f71SJohn Baldwin mtx_lock_spin(&ithread_list_lock); 238b4151f71SJohn Baldwin if ((flags & INTR_EXCL) !=0 && !TAILQ_EMPTY(&ithread->it_handlers)) 239b4151f71SJohn Baldwin goto fail; 240b4151f71SJohn Baldwin if (!TAILQ_EMPTY(&ithread->it_handlers) && 241b4151f71SJohn Baldwin (TAILQ_FIRST(&ithread->it_handlers)->ih_flags & IH_EXCLUSIVE) != 0) 242b4151f71SJohn Baldwin goto fail; 243b4151f71SJohn Baldwin 244b4151f71SJohn Baldwin TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next) 245b4151f71SJohn Baldwin if (temp_ih->ih_pri > ih->ih_pri) 246b4151f71SJohn Baldwin break; 247b4151f71SJohn Baldwin if (temp_ih == NULL) 248b4151f71SJohn Baldwin TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next); 249b4151f71SJohn Baldwin else 250b4151f71SJohn Baldwin TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next); 251b4151f71SJohn Baldwin ithread_update(ithread); 252b4151f71SJohn Baldwin mtx_unlock_spin(&ithread_list_lock); 253b4151f71SJohn Baldwin 254b4151f71SJohn Baldwin if (cookiep != NULL) 255b4151f71SJohn Baldwin *cookiep = ih; 256b4151f71SJohn Baldwin return (0); 257b4151f71SJohn Baldwin 258b4151f71SJohn Baldwin fail: 259b4151f71SJohn Baldwin mtx_unlock_spin(&ithread_list_lock); 260b4151f71SJohn Baldwin free(ih, M_ITHREAD); 261b4151f71SJohn Baldwin return (EINVAL); 262b4151f71SJohn Baldwin } 263b4151f71SJohn Baldwin 264b4151f71SJohn Baldwin int 265b4151f71SJohn Baldwin ithread_remove_handler(void *cookie) 266b4151f71SJohn Baldwin { 267b4151f71SJohn Baldwin struct intrhand *handler = (struct intrhand *)cookie; 268b4151f71SJohn Baldwin struct ithd *ithread; 269b4151f71SJohn Baldwin #ifdef INVARIANTS 270b4151f71SJohn Baldwin struct intrhand *ih; 271b4151f71SJohn Baldwin int found; 272b4151f71SJohn Baldwin #endif 273b4151f71SJohn Baldwin 274b4151f71SJohn Baldwin if (handler == NULL || (ithread = handler->ih_ithread) == NULL) 275b4151f71SJohn Baldwin return (EINVAL); 276b4151f71SJohn Baldwin 277b4151f71SJohn Baldwin mtx_lock_spin(&ithread_list_lock); 278b4151f71SJohn Baldwin #ifdef INVARIANTS 279b4151f71SJohn Baldwin found = 0; 280b4151f71SJohn Baldwin TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next) 281b4151f71SJohn Baldwin if (ih == handler) { 282b4151f71SJohn Baldwin found++; 283b4151f71SJohn Baldwin break; 284b4151f71SJohn Baldwin } 285b4151f71SJohn Baldwin if (found == 0) { 286b4151f71SJohn Baldwin mtx_unlock_spin(&ithread_list_lock); 287b4151f71SJohn Baldwin return (EINVAL); 288b4151f71SJohn Baldwin } 289b4151f71SJohn Baldwin #endif 290b4151f71SJohn Baldwin TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next); 291b4151f71SJohn Baldwin ithread_update(ithread); 292b4151f71SJohn Baldwin mtx_unlock_spin(&ithread_list_lock); 293b4151f71SJohn Baldwin 294b4151f71SJohn Baldwin free(handler, M_ITHREAD); 295b4151f71SJohn Baldwin return (0); 296b4151f71SJohn Baldwin } 297b4151f71SJohn Baldwin 298b4151f71SJohn Baldwin int 299b4151f71SJohn Baldwin swi_add(struct ithd **ithdp, const char *name, driver_intr_t handler, 300b4151f71SJohn Baldwin void *arg, int pri, enum intr_type flags, void **cookiep) 3018088699fSJohn Baldwin { 3028088699fSJohn Baldwin struct proc *p; 3038088699fSJohn Baldwin struct ithd *ithd; 304b4151f71SJohn Baldwin int error; 3058088699fSJohn Baldwin 3068088699fSJohn Baldwin ithd = (ithdp != NULL) ? *ithdp : NULL; 3078088699fSJohn Baldwin 3088088699fSJohn Baldwin if (ithd == NULL) { 309b4151f71SJohn Baldwin error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL, 310b4151f71SJohn Baldwin "swi%d:", pri); 3118088699fSJohn Baldwin if (error) 312b4151f71SJohn Baldwin return (error); 313b4151f71SJohn Baldwin 3148088699fSJohn Baldwin /* XXX - some hacks are _really_ gross */ 315b4151f71SJohn Baldwin p = ithd->it_proc; 316b4151f71SJohn Baldwin PROC_LOCK(p); 3178088699fSJohn Baldwin if (pri == SWI_CLOCK) 3188088699fSJohn Baldwin p->p_flag |= P_NOLOAD; 319b4151f71SJohn Baldwin PROC_UNLOCK(p); 3208088699fSJohn Baldwin if (ithdp != NULL) 3218088699fSJohn Baldwin *ithdp = ithd; 3228088699fSJohn Baldwin } 323b4151f71SJohn Baldwin return (ithread_add_handler(ithd, name, handler, arg, pri + PI_SOFT, 324b4151f71SJohn Baldwin flags, cookiep)); 3258088699fSJohn Baldwin } 3268088699fSJohn Baldwin 3278088699fSJohn Baldwin 3281931cf94SJohn Baldwin /* 3298088699fSJohn Baldwin * Schedule a heavyweight software interrupt process. 3301931cf94SJohn Baldwin */ 3311931cf94SJohn Baldwin void 332b4151f71SJohn Baldwin swi_sched(void *cookie, int flags) 3331931cf94SJohn Baldwin { 334b4151f71SJohn Baldwin struct intrhand *ih = (struct intrhand *)cookie; 335b4151f71SJohn Baldwin struct ithd *it = ih->ih_ithread; 3368088699fSJohn Baldwin struct proc *p = it->it_proc; 3378088699fSJohn Baldwin 3381931cf94SJohn Baldwin atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */ 3391931cf94SJohn Baldwin 340b4151f71SJohn Baldwin CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d", 3418088699fSJohn Baldwin p->p_pid, p->p_comm, it->it_need); 3421931cf94SJohn Baldwin 3431931cf94SJohn Baldwin /* 3448088699fSJohn Baldwin * Set it_need so that if the thread is already running but close 3458088699fSJohn Baldwin * to done, it will do another go-round. Then get the sched lock 3468088699fSJohn Baldwin * and see if the thread is on whichkqs yet. If not, put it on 3478088699fSJohn Baldwin * there. In any case, kick everyone so that if the new thread 3488088699fSJohn Baldwin * is higher priority than their current thread, it gets run now. 3491931cf94SJohn Baldwin */ 350b4151f71SJohn Baldwin atomic_store_rel_int(&ih->ih_need, 1); 351b4151f71SJohn Baldwin if (!(flags & SWI_DELAY)) { 3528088699fSJohn Baldwin it->it_need = 1; 3539ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 3548088699fSJohn Baldwin if (p->p_stat == SWAIT) { /* not on run queue */ 355b4151f71SJohn Baldwin CTR1(KTR_INTR, "swi_sched: setrunqueue %d", p->p_pid); 3568088699fSJohn Baldwin p->p_stat = SRUN; 3578088699fSJohn Baldwin setrunqueue(p); 358b4151f71SJohn Baldwin if (!cold && flags & SWI_SWITCH) { 359b4151f71SJohn Baldwin if (curproc != PCPU_GET(idleproc)) 360b4151f71SJohn Baldwin setrunqueue(curproc); 361b4151f71SJohn Baldwin curproc->p_stats->p_ru.ru_nvcsw++; 362b4151f71SJohn Baldwin mi_switch(); 363b4151f71SJohn Baldwin } else 364b4151f71SJohn Baldwin need_resched(); 3651931cf94SJohn Baldwin } 3668088699fSJohn Baldwin else { 367b4151f71SJohn Baldwin CTR3(KTR_INTR, "swi_sched %d: it_need %d, state %d", 3688088699fSJohn Baldwin p->p_pid, it->it_need, p->p_stat ); 3698088699fSJohn Baldwin } 3709ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 3718088699fSJohn Baldwin } 3728088699fSJohn Baldwin } 3738088699fSJohn Baldwin 3748088699fSJohn Baldwin /* 375b4151f71SJohn Baldwin * This is the main code for interrupt threads. 3768088699fSJohn Baldwin */ 3778088699fSJohn Baldwin void 378b4151f71SJohn Baldwin ithread_loop(void *arg) 3798088699fSJohn Baldwin { 380b4151f71SJohn Baldwin struct ithd *ithd; /* our thread context */ 3818088699fSJohn Baldwin struct intrhand *ih; /* and our interrupt handler chain */ 382b4151f71SJohn Baldwin struct proc *p; 3838088699fSJohn Baldwin 384b4151f71SJohn Baldwin p = curproc; 385b4151f71SJohn Baldwin ithd = (struct ithd *)arg; /* point to myself */ 386b4151f71SJohn Baldwin KASSERT(ithd->it_proc == p && p->p_ithd == ithd, 387b4151f71SJohn Baldwin (__func__ ": ithread and proc linkage out of sync")); 3888088699fSJohn Baldwin 3898088699fSJohn Baldwin /* 3908088699fSJohn Baldwin * As long as we have interrupts outstanding, go through the 3918088699fSJohn Baldwin * list of handlers, giving each one a go at it. 3928088699fSJohn Baldwin */ 3938088699fSJohn Baldwin for (;;) { 394b4151f71SJohn Baldwin /* 395b4151f71SJohn Baldwin * If we are an orphaned thread, then just die. 396b4151f71SJohn Baldwin */ 397b4151f71SJohn Baldwin if (ithd->it_flags & IT_DEAD) { 398b4151f71SJohn Baldwin CTR2(KTR_INTR, __func__ ": pid %d: (%s) exiting", 399b4151f71SJohn Baldwin p->p_pid, p->p_comm); 400b4151f71SJohn Baldwin p->p_ithd = NULL; 401b4151f71SJohn Baldwin mtx_lock(&Giant); 402b4151f71SJohn Baldwin free(ithd, M_ITHREAD); 403b4151f71SJohn Baldwin kthread_exit(0); 404b4151f71SJohn Baldwin } 405b4151f71SJohn Baldwin 406b4151f71SJohn Baldwin CTR3(KTR_INTR, __func__ ": pid %d: (%s) need=%d", 407b4151f71SJohn Baldwin p->p_pid, p->p_comm, ithd->it_need); 408b4151f71SJohn Baldwin while (ithd->it_need) { 4098088699fSJohn Baldwin /* 4108088699fSJohn Baldwin * Service interrupts. If another interrupt 4118088699fSJohn Baldwin * arrives while we are running, they will set 4128088699fSJohn Baldwin * it_need to denote that we should make 4138088699fSJohn Baldwin * another pass. 4148088699fSJohn Baldwin */ 415b4151f71SJohn Baldwin atomic_store_rel_int(&ithd->it_need, 0); 416b4151f71SJohn Baldwin TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 417b4151f71SJohn Baldwin if (ithd->it_flags & IT_SOFT && !ih->ih_need) 4188088699fSJohn Baldwin continue; 419b4151f71SJohn Baldwin atomic_store_rel_int(&ih->ih_need, 0); 4208088699fSJohn Baldwin CTR5(KTR_INTR, 421b4151f71SJohn Baldwin __func__ ": pid %d ih=%p: %p(%p) flg=%x", 4228088699fSJohn Baldwin p->p_pid, (void *)ih, 4238088699fSJohn Baldwin (void *)ih->ih_handler, ih->ih_argument, 4248088699fSJohn Baldwin ih->ih_flags); 4258088699fSJohn Baldwin 426b4151f71SJohn Baldwin if ((ih->ih_flags & IH_MPSAFE) == 0) 4279ed346baSBosko Milekic mtx_lock(&Giant); 4288088699fSJohn Baldwin ih->ih_handler(ih->ih_argument); 429b4151f71SJohn Baldwin if ((ih->ih_flags & IH_MPSAFE) == 0) 4309ed346baSBosko Milekic mtx_unlock(&Giant); 4318088699fSJohn Baldwin } 4328088699fSJohn Baldwin } 4338088699fSJohn Baldwin 4348088699fSJohn Baldwin /* 4358088699fSJohn Baldwin * Processed all our interrupts. Now get the sched 4368088699fSJohn Baldwin * lock. This may take a while and it_need may get 4378088699fSJohn Baldwin * set again, so we have to check it again. 4388088699fSJohn Baldwin */ 439896c2303SJohn Baldwin mtx_assert(&Giant, MA_NOTOWNED); 4409ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 441b4151f71SJohn Baldwin if (!ithd->it_need) { 442b4151f71SJohn Baldwin /* 443b4151f71SJohn Baldwin * Should we call this earlier in the loop above? 444b4151f71SJohn Baldwin */ 445b4151f71SJohn Baldwin if (ithd->it_enable != NULL) 446b4151f71SJohn Baldwin ithd->it_enable(ithd->it_vector); 4478088699fSJohn Baldwin p->p_stat = SWAIT; /* we're idle */ 448b4151f71SJohn Baldwin CTR1(KTR_INTR, __func__ ": pid %d: done", p->p_pid); 4498088699fSJohn Baldwin mi_switch(); 450b4151f71SJohn Baldwin CTR1(KTR_INTR, __func__ ": pid %d: resumed", p->p_pid); 4518088699fSJohn Baldwin } 4529ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 4538088699fSJohn Baldwin } 4541931cf94SJohn Baldwin } 4551931cf94SJohn Baldwin 456b4151f71SJohn Baldwin /* 457b4151f71SJohn Baldwin * Initialize mutex used to protect ithread handler lists. 458b4151f71SJohn Baldwin */ 459b4151f71SJohn Baldwin static void 460b4151f71SJohn Baldwin ithread_init(void *dummy) 461b4151f71SJohn Baldwin { 462b4151f71SJohn Baldwin 463b4151f71SJohn Baldwin mtx_init(&ithread_list_lock, "ithread list lock", MTX_SPIN); 464b4151f71SJohn Baldwin } 465b4151f71SJohn Baldwin SYSINIT(ithread_init, SI_SUB_INTR, SI_ORDER_FIRST, ithread_init, NULL); 4661931cf94SJohn Baldwin 4671931cf94SJohn Baldwin /* 4688088699fSJohn Baldwin * Start standard software interrupt threads 4691931cf94SJohn Baldwin */ 4701931cf94SJohn Baldwin static void 471b4151f71SJohn Baldwin start_softintr(void *dummy) 4721931cf94SJohn Baldwin { 473b4151f71SJohn Baldwin 474b4151f71SJohn Baldwin if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, 0, &net_ih) || 475b4151f71SJohn Baldwin swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK, 476b4151f71SJohn Baldwin INTR_MPSAFE, &softclock_ih) || 477b4151f71SJohn Baldwin swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, 0, &vm_ih)) 478b4151f71SJohn Baldwin panic("died while creating standard software ithreads"); 4791931cf94SJohn Baldwin } 480b4151f71SJohn Baldwin SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL) 4811931cf94SJohn Baldwin 4821931cf94SJohn Baldwin void 483b4151f71SJohn Baldwin legacy_setsoftnet(void) 4841931cf94SJohn Baldwin { 485b4151f71SJohn Baldwin swi_sched(net_ih, SWI_NOSWITCH); 4861931cf94SJohn Baldwin } 4871931cf94SJohn Baldwin 4888088699fSJohn Baldwin /* 4898088699fSJohn Baldwin * XXX: This should really be in the network code somewhere and installed 4908088699fSJohn Baldwin * via a SI_SUB_SOFINTR, SI_ORDER_MIDDLE sysinit. 4918088699fSJohn Baldwin */ 4928088699fSJohn Baldwin void (*netisrs[32]) __P((void)); 4938088699fSJohn Baldwin u_int netisr; 4948088699fSJohn Baldwin 4951eb44f02SJake Burkholder int 4961eb44f02SJake Burkholder register_netisr(num, handler) 4971eb44f02SJake Burkholder int num; 4981eb44f02SJake Burkholder netisr_t *handler; 4991eb44f02SJake Burkholder { 5001eb44f02SJake Burkholder 5011eb44f02SJake Burkholder if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) { 5021eb44f02SJake Burkholder printf("register_netisr: bad isr number: %d\n", num); 5031eb44f02SJake Burkholder return (EINVAL); 5041eb44f02SJake Burkholder } 5051eb44f02SJake Burkholder netisrs[num] = handler; 5061eb44f02SJake Burkholder return (0); 5071eb44f02SJake Burkholder } 5081eb44f02SJake Burkholder 5091eb44f02SJake Burkholder int 5101eb44f02SJake Burkholder unregister_netisr(num) 5111eb44f02SJake Burkholder int num; 5121eb44f02SJake Burkholder { 5131eb44f02SJake Burkholder 5141eb44f02SJake Burkholder if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) { 5151eb44f02SJake Burkholder printf("unregister_netisr: bad isr number: %d\n", num); 5161eb44f02SJake Burkholder return (EINVAL); 5171eb44f02SJake Burkholder } 5181eb44f02SJake Burkholder netisrs[num] = NULL; 5191eb44f02SJake Burkholder return (0); 5201eb44f02SJake Burkholder } 5211eb44f02SJake Burkholder 5228088699fSJohn Baldwin static void 5238088699fSJohn Baldwin swi_net(void *dummy) 5241931cf94SJohn Baldwin { 5258088699fSJohn Baldwin u_int bits; 5268088699fSJohn Baldwin int i; 5278088699fSJohn Baldwin 5288088699fSJohn Baldwin bits = atomic_readandclear_int(&netisr); 5298088699fSJohn Baldwin while ((i = ffs(bits)) != 0) { 5308088699fSJohn Baldwin i--; 531338c0bc6SSeigo Tanimura if (netisrs[i] != NULL) 5328088699fSJohn Baldwin netisrs[i](); 533338c0bc6SSeigo Tanimura else 534338c0bc6SSeigo Tanimura printf("swi_net: unregistered isr number: %d.\n", i); 5358088699fSJohn Baldwin bits &= ~(1 << i); 5368088699fSJohn Baldwin } 5371931cf94SJohn Baldwin } 538