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> 33c11110eaSAlfred Perlstein #include <sys/conf.h> 349a94c9c5SJohn Baldwin #include <sys/rtprio.h> 35425f9fdaSStefan Eßer #include <sys/systm.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> 46d279178dSThomas Moestl #include <sys/sysctl.h> 471931cf94SJohn Baldwin #include <sys/unistd.h> 481931cf94SJohn Baldwin #include <sys/vmmeter.h> 491931cf94SJohn Baldwin #include <machine/atomic.h> 501931cf94SJohn Baldwin #include <machine/cpu.h> 518088699fSJohn Baldwin #include <machine/md_var.h> 52b4151f71SJohn Baldwin #include <machine/stdarg.h> 53425f9fdaSStefan Eßer 543e5da754SJohn Baldwin struct int_entropy { 553e5da754SJohn Baldwin struct proc *proc; 563e5da754SJohn Baldwin int vector; 573e5da754SJohn Baldwin }; 583e5da754SJohn Baldwin 59b4151f71SJohn Baldwin void *vm_ih; 60b4151f71SJohn Baldwin void *softclock_ih; 618088699fSJohn Baldwin struct ithd *clk_ithd; 628088699fSJohn Baldwin struct ithd *tty_ithd; 631931cf94SJohn Baldwin 64b4151f71SJohn Baldwin static MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads"); 65b4151f71SJohn Baldwin 66b4151f71SJohn Baldwin static void ithread_update(struct ithd *); 67b4151f71SJohn Baldwin static void ithread_loop(void *); 681931cf94SJohn Baldwin static void start_softintr(void *); 6918c5a6c4SBruce Evans 70b4151f71SJohn Baldwin u_char 71b4151f71SJohn Baldwin ithread_priority(enum intr_type flags) 729a94c9c5SJohn Baldwin { 73b4151f71SJohn Baldwin u_char pri; 749a94c9c5SJohn Baldwin 75b4151f71SJohn Baldwin flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET | 765a280d9cSPeter Wemm INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK | INTR_TYPE_AV); 779a94c9c5SJohn Baldwin switch (flags) { 78b4151f71SJohn Baldwin case INTR_TYPE_TTY: 799a94c9c5SJohn Baldwin pri = PI_TTYLOW; 809a94c9c5SJohn Baldwin break; 819a94c9c5SJohn Baldwin case INTR_TYPE_BIO: 829a94c9c5SJohn Baldwin /* 839a94c9c5SJohn Baldwin * XXX We need to refine this. BSD/OS distinguishes 849a94c9c5SJohn Baldwin * between tape and disk priorities. 859a94c9c5SJohn Baldwin */ 869a94c9c5SJohn Baldwin pri = PI_DISK; 879a94c9c5SJohn Baldwin break; 889a94c9c5SJohn Baldwin case INTR_TYPE_NET: 899a94c9c5SJohn Baldwin pri = PI_NET; 909a94c9c5SJohn Baldwin break; 919a94c9c5SJohn Baldwin case INTR_TYPE_CAM: 929a94c9c5SJohn Baldwin pri = PI_DISK; /* XXX or PI_CAM? */ 939a94c9c5SJohn Baldwin break; 945a280d9cSPeter Wemm case INTR_TYPE_AV: /* Audio/video */ 955a280d9cSPeter Wemm pri = PI_AV; 965a280d9cSPeter Wemm break; 97b4151f71SJohn Baldwin case INTR_TYPE_CLK: 98b4151f71SJohn Baldwin pri = PI_REALTIME; 99b4151f71SJohn Baldwin break; 1009a94c9c5SJohn Baldwin case INTR_TYPE_MISC: 1019a94c9c5SJohn Baldwin pri = PI_DULL; /* don't care */ 1029a94c9c5SJohn Baldwin break; 1039a94c9c5SJohn Baldwin default: 104b4151f71SJohn Baldwin /* We didn't specify an interrupt level. */ 1059a94c9c5SJohn Baldwin panic("ithread_priority: no interrupt type in flags"); 1069a94c9c5SJohn Baldwin } 1079a94c9c5SJohn Baldwin 1089a94c9c5SJohn Baldwin return pri; 1099a94c9c5SJohn Baldwin } 1109a94c9c5SJohn Baldwin 111b4151f71SJohn Baldwin /* 112b4151f71SJohn Baldwin * Regenerate the name (p_comm) and priority for a threaded interrupt thread. 113b4151f71SJohn Baldwin */ 114b4151f71SJohn Baldwin static void 115b4151f71SJohn Baldwin ithread_update(struct ithd *ithd) 116b4151f71SJohn Baldwin { 117b4151f71SJohn Baldwin struct intrhand *ih; 118b40ce416SJulian Elischer struct thread *td; 119b4151f71SJohn Baldwin struct proc *p; 120b4151f71SJohn Baldwin int entropy; 1218088699fSJohn Baldwin 1224d29cb2dSJohn Baldwin mtx_assert(&ithd->it_lock, MA_OWNED); 123b40ce416SJulian Elischer td = ithd->it_td; 124b40ce416SJulian Elischer if (td == NULL) 125b4151f71SJohn Baldwin return; 126b40ce416SJulian Elischer p = td->td_proc; 127b4151f71SJohn Baldwin 128bb8992b3SRobert Drehmel strlcpy(p->p_comm, ithd->it_name, sizeof(p->p_comm)); 129e80fb434SRobert Drehmel 130b4151f71SJohn Baldwin ih = TAILQ_FIRST(&ithd->it_handlers); 131b4151f71SJohn Baldwin if (ih == NULL) { 132b106d2f5SJohn Baldwin mtx_lock_spin(&sched_lock); 1332c100766SJulian Elischer td->td_priority = PRI_MAX_ITHD; 134b106d2f5SJohn Baldwin td->td_base_pri = PRI_MAX_ITHD; 135b106d2f5SJohn Baldwin mtx_unlock_spin(&sched_lock); 136b4151f71SJohn Baldwin ithd->it_flags &= ~IT_ENTROPY; 137b4151f71SJohn Baldwin return; 138b4151f71SJohn Baldwin } 139b4151f71SJohn Baldwin entropy = 0; 140b106d2f5SJohn Baldwin mtx_lock_spin(&sched_lock); 1412c100766SJulian Elischer td->td_priority = ih->ih_pri; 1422c100766SJulian Elischer td->td_base_pri = ih->ih_pri; 143b106d2f5SJohn Baldwin mtx_unlock_spin(&sched_lock); 144b4151f71SJohn Baldwin TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 145b4151f71SJohn Baldwin if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 < 146b4151f71SJohn Baldwin sizeof(p->p_comm)) { 147b4151f71SJohn Baldwin strcat(p->p_comm, " "); 148b4151f71SJohn Baldwin strcat(p->p_comm, ih->ih_name); 149b4151f71SJohn Baldwin } else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) { 150b4151f71SJohn Baldwin if (p->p_comm[sizeof(p->p_comm) - 2] == '+') 151b4151f71SJohn Baldwin p->p_comm[sizeof(p->p_comm) - 2] = '*'; 152b4151f71SJohn Baldwin else 153b4151f71SJohn Baldwin p->p_comm[sizeof(p->p_comm) - 2] = '+'; 154b4151f71SJohn Baldwin } else 155b4151f71SJohn Baldwin strcat(p->p_comm, "+"); 156b4151f71SJohn Baldwin if (ih->ih_flags & IH_ENTROPY) 157b4151f71SJohn Baldwin entropy++; 158b4151f71SJohn Baldwin } 1593e5da754SJohn Baldwin if (entropy) 160b4151f71SJohn Baldwin ithd->it_flags |= IT_ENTROPY; 161b4151f71SJohn Baldwin else 162b4151f71SJohn Baldwin ithd->it_flags &= ~IT_ENTROPY; 16324fbeaf9SJake Burkholder CTR2(KTR_INTR, "%s: updated %s", __func__, p->p_comm); 164b4151f71SJohn Baldwin } 165b4151f71SJohn Baldwin 166b4151f71SJohn Baldwin int 167b4151f71SJohn Baldwin ithread_create(struct ithd **ithread, int vector, int flags, 168b4151f71SJohn Baldwin void (*disable)(int), void (*enable)(int), const char *fmt, ...) 169b4151f71SJohn Baldwin { 170b4151f71SJohn Baldwin struct ithd *ithd; 171b40ce416SJulian Elischer struct thread *td; 172b4151f71SJohn Baldwin struct proc *p; 173b4151f71SJohn Baldwin int error; 174b4151f71SJohn Baldwin va_list ap; 175b4151f71SJohn Baldwin 1763e5da754SJohn Baldwin /* The only valid flag during creation is IT_SOFT. */ 1773e5da754SJohn Baldwin if ((flags & ~IT_SOFT) != 0) 1783e5da754SJohn Baldwin return (EINVAL); 1793e5da754SJohn Baldwin 18044956c98SAlfred Perlstein ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_ZERO); 181b4151f71SJohn Baldwin ithd->it_vector = vector; 182b4151f71SJohn Baldwin ithd->it_disable = disable; 183b4151f71SJohn Baldwin ithd->it_enable = enable; 184b4151f71SJohn Baldwin ithd->it_flags = flags; 185b4151f71SJohn Baldwin TAILQ_INIT(&ithd->it_handlers); 1866008862bSJohn Baldwin mtx_init(&ithd->it_lock, "ithread", NULL, MTX_DEF); 187b4151f71SJohn Baldwin 188b4151f71SJohn Baldwin va_start(ap, fmt); 189b4151f71SJohn Baldwin vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap); 190b4151f71SJohn Baldwin va_end(ap); 191b4151f71SJohn Baldwin 192b4151f71SJohn Baldwin error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID, 193316ec49aSScott Long 0, "%s", ithd->it_name); 194b4151f71SJohn Baldwin if (error) { 1954d29cb2dSJohn Baldwin mtx_destroy(&ithd->it_lock); 196b4151f71SJohn Baldwin free(ithd, M_ITHREAD); 197b4151f71SJohn Baldwin return (error); 198b4151f71SJohn Baldwin } 199079b7badSJulian Elischer td = FIRST_THREAD_IN_PROC(p); /* XXXKSE */ 2002c100766SJulian Elischer td->td_ksegrp->kg_pri_class = PRI_ITHD; 2012c100766SJulian Elischer td->td_priority = PRI_MAX_ITHD; 20271fad9fdSJulian Elischer TD_SET_IWAIT(td); 203b40ce416SJulian Elischer ithd->it_td = td; 204b40ce416SJulian Elischer td->td_ithd = ithd; 205b4151f71SJohn Baldwin if (ithread != NULL) 206b4151f71SJohn Baldwin *ithread = ithd; 207b4151f71SJohn Baldwin 20891f91617SDavid E. O'Brien CTR2(KTR_INTR, "%s: created %s", __func__, ithd->it_name); 209b4151f71SJohn Baldwin return (0); 210b4151f71SJohn Baldwin } 211b4151f71SJohn Baldwin 212b4151f71SJohn Baldwin int 213b4151f71SJohn Baldwin ithread_destroy(struct ithd *ithread) 214b4151f71SJohn Baldwin { 215b4151f71SJohn Baldwin 216b40ce416SJulian Elischer struct thread *td; 217b40ce416SJulian Elischer struct proc *p; 2184d29cb2dSJohn Baldwin if (ithread == NULL) 219b4151f71SJohn Baldwin return (EINVAL); 220b4151f71SJohn Baldwin 221b40ce416SJulian Elischer td = ithread->it_td; 222b40ce416SJulian Elischer p = td->td_proc; 2234d29cb2dSJohn Baldwin mtx_lock(&ithread->it_lock); 2244d29cb2dSJohn Baldwin if (!TAILQ_EMPTY(&ithread->it_handlers)) { 2254d29cb2dSJohn Baldwin mtx_unlock(&ithread->it_lock); 2264d29cb2dSJohn Baldwin return (EINVAL); 2274d29cb2dSJohn Baldwin } 228b4151f71SJohn Baldwin ithread->it_flags |= IT_DEAD; 2294d29cb2dSJohn Baldwin mtx_lock_spin(&sched_lock); 23071fad9fdSJulian Elischer if (TD_AWAITING_INTR(td)) { 23171fad9fdSJulian Elischer TD_CLR_IWAIT(td); 232b40ce416SJulian Elischer setrunqueue(td); 233b4151f71SJohn Baldwin } 234b4151f71SJohn Baldwin mtx_unlock_spin(&sched_lock); 2354d29cb2dSJohn Baldwin mtx_unlock(&ithread->it_lock); 23691f91617SDavid E. O'Brien CTR2(KTR_INTR, "%s: killing %s", __func__, ithread->it_name); 237b4151f71SJohn Baldwin return (0); 238b4151f71SJohn Baldwin } 239b4151f71SJohn Baldwin 240b4151f71SJohn Baldwin int 241b4151f71SJohn Baldwin ithread_add_handler(struct ithd* ithread, const char *name, 242b4151f71SJohn Baldwin driver_intr_t handler, void *arg, u_char pri, enum intr_type flags, 243b4151f71SJohn Baldwin void **cookiep) 244b4151f71SJohn Baldwin { 245b4151f71SJohn Baldwin struct intrhand *ih, *temp_ih; 246b4151f71SJohn Baldwin 247b4151f71SJohn Baldwin if (ithread == NULL || name == NULL || handler == NULL) 248b4151f71SJohn Baldwin return (EINVAL); 249b4151f71SJohn Baldwin if ((flags & INTR_FAST) !=0) 250b4151f71SJohn Baldwin flags |= INTR_EXCL; 251b4151f71SJohn Baldwin 25244956c98SAlfred Perlstein ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_ZERO); 253b4151f71SJohn Baldwin ih->ih_handler = handler; 254b4151f71SJohn Baldwin ih->ih_argument = arg; 255b4151f71SJohn Baldwin ih->ih_name = name; 256b4151f71SJohn Baldwin ih->ih_ithread = ithread; 257b4151f71SJohn Baldwin ih->ih_pri = pri; 258b4151f71SJohn Baldwin if (flags & INTR_FAST) 259b4151f71SJohn Baldwin ih->ih_flags = IH_FAST | IH_EXCLUSIVE; 260b4151f71SJohn Baldwin else if (flags & INTR_EXCL) 261b4151f71SJohn Baldwin ih->ih_flags = IH_EXCLUSIVE; 262b4151f71SJohn Baldwin if (flags & INTR_MPSAFE) 263b4151f71SJohn Baldwin ih->ih_flags |= IH_MPSAFE; 264b4151f71SJohn Baldwin if (flags & INTR_ENTROPY) 265b4151f71SJohn Baldwin ih->ih_flags |= IH_ENTROPY; 266b4151f71SJohn Baldwin 2674d29cb2dSJohn Baldwin mtx_lock(&ithread->it_lock); 268b4151f71SJohn Baldwin if ((flags & INTR_EXCL) !=0 && !TAILQ_EMPTY(&ithread->it_handlers)) 269b4151f71SJohn Baldwin goto fail; 270b4151f71SJohn Baldwin if (!TAILQ_EMPTY(&ithread->it_handlers) && 271b4151f71SJohn Baldwin (TAILQ_FIRST(&ithread->it_handlers)->ih_flags & IH_EXCLUSIVE) != 0) 272b4151f71SJohn Baldwin goto fail; 273b4151f71SJohn Baldwin 274b4151f71SJohn Baldwin TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next) 275b4151f71SJohn Baldwin if (temp_ih->ih_pri > ih->ih_pri) 276b4151f71SJohn Baldwin break; 277b4151f71SJohn Baldwin if (temp_ih == NULL) 278b4151f71SJohn Baldwin TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next); 279b4151f71SJohn Baldwin else 280b4151f71SJohn Baldwin TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next); 281b4151f71SJohn Baldwin ithread_update(ithread); 2824d29cb2dSJohn Baldwin mtx_unlock(&ithread->it_lock); 283b4151f71SJohn Baldwin 284b4151f71SJohn Baldwin if (cookiep != NULL) 285b4151f71SJohn Baldwin *cookiep = ih; 28691f91617SDavid E. O'Brien CTR3(KTR_INTR, "%s: added %s to %s", __func__, ih->ih_name, 287addec20cSJohn Baldwin ithread->it_name); 288b4151f71SJohn Baldwin return (0); 289b4151f71SJohn Baldwin 290b4151f71SJohn Baldwin fail: 2914d29cb2dSJohn Baldwin mtx_unlock(&ithread->it_lock); 292b4151f71SJohn Baldwin free(ih, M_ITHREAD); 293b4151f71SJohn Baldwin return (EINVAL); 294b4151f71SJohn Baldwin } 295b4151f71SJohn Baldwin 296b4151f71SJohn Baldwin int 297b4151f71SJohn Baldwin ithread_remove_handler(void *cookie) 298b4151f71SJohn Baldwin { 299b4151f71SJohn Baldwin struct intrhand *handler = (struct intrhand *)cookie; 300b4151f71SJohn Baldwin struct ithd *ithread; 301b4151f71SJohn Baldwin #ifdef INVARIANTS 302b4151f71SJohn Baldwin struct intrhand *ih; 303b4151f71SJohn Baldwin #endif 304b4151f71SJohn Baldwin 3053e5da754SJohn Baldwin if (handler == NULL) 306b4151f71SJohn Baldwin return (EINVAL); 30776bd604eSJohn Baldwin ithread = handler->ih_ithread; 30876bd604eSJohn Baldwin KASSERT(ithread != NULL, 3093e5da754SJohn Baldwin ("interrupt handler \"%s\" has a NULL interrupt thread", 3103e5da754SJohn Baldwin handler->ih_name)); 31191f91617SDavid E. O'Brien CTR3(KTR_INTR, "%s: removing %s from %s", __func__, handler->ih_name, 312addec20cSJohn Baldwin ithread->it_name); 3134d29cb2dSJohn Baldwin mtx_lock(&ithread->it_lock); 314b4151f71SJohn Baldwin #ifdef INVARIANTS 315b4151f71SJohn Baldwin TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next) 3163e5da754SJohn Baldwin if (ih == handler) 3173e5da754SJohn Baldwin goto ok; 3184d29cb2dSJohn Baldwin mtx_unlock(&ithread->it_lock); 3193e5da754SJohn Baldwin panic("interrupt handler \"%s\" not found in interrupt thread \"%s\"", 3203e5da754SJohn Baldwin ih->ih_name, ithread->it_name); 3213e5da754SJohn Baldwin ok: 322b4151f71SJohn Baldwin #endif 323de271f01SJohn Baldwin /* 324de271f01SJohn Baldwin * If the interrupt thread is already running, then just mark this 325de271f01SJohn Baldwin * handler as being dead and let the ithread do the actual removal. 326de271f01SJohn Baldwin */ 327de271f01SJohn Baldwin mtx_lock_spin(&sched_lock); 32871fad9fdSJulian Elischer if (!TD_AWAITING_INTR(ithread->it_td)) { 329de271f01SJohn Baldwin handler->ih_flags |= IH_DEAD; 330de271f01SJohn Baldwin 331de271f01SJohn Baldwin /* 332de271f01SJohn Baldwin * Ensure that the thread will process the handler list 333de271f01SJohn Baldwin * again and remove this handler if it has already passed 334de271f01SJohn Baldwin * it on the list. 335de271f01SJohn Baldwin */ 336de271f01SJohn Baldwin ithread->it_need = 1; 3374d29cb2dSJohn Baldwin } else 338b4151f71SJohn Baldwin TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next); 339de271f01SJohn Baldwin mtx_unlock_spin(&sched_lock); 3404d29cb2dSJohn Baldwin if ((handler->ih_flags & IH_DEAD) != 0) 3414d29cb2dSJohn Baldwin msleep(handler, &ithread->it_lock, PUSER, "itrmh", 0); 3424d29cb2dSJohn Baldwin ithread_update(ithread); 3434d29cb2dSJohn Baldwin mtx_unlock(&ithread->it_lock); 344b4151f71SJohn Baldwin free(handler, M_ITHREAD); 345b4151f71SJohn Baldwin return (0); 346b4151f71SJohn Baldwin } 347b4151f71SJohn Baldwin 348b4151f71SJohn Baldwin int 3493e5da754SJohn Baldwin ithread_schedule(struct ithd *ithread, int do_switch) 3503e5da754SJohn Baldwin { 3513e5da754SJohn Baldwin struct int_entropy entropy; 352b40ce416SJulian Elischer struct thread *td; 35304774f23SJulian Elischer struct thread *ctd; 3543e5da754SJohn Baldwin struct proc *p; 3553e5da754SJohn Baldwin 3563e5da754SJohn Baldwin /* 3573e5da754SJohn Baldwin * If no ithread or no handlers, then we have a stray interrupt. 3583e5da754SJohn Baldwin */ 3593e5da754SJohn Baldwin if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers)) 3603e5da754SJohn Baldwin return (EINVAL); 3613e5da754SJohn Baldwin 36204774f23SJulian Elischer ctd = curthread; 3633e5da754SJohn Baldwin /* 3643e5da754SJohn Baldwin * If any of the handlers for this ithread claim to be good 3653e5da754SJohn Baldwin * sources of entropy, then gather some. 3663e5da754SJohn Baldwin */ 3673e5da754SJohn Baldwin if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) { 3683e5da754SJohn Baldwin entropy.vector = ithread->it_vector; 36965c17e74SDavid Xu entropy.proc = ctd->td_proc; 3703e5da754SJohn Baldwin random_harvest(&entropy, sizeof(entropy), 2, 0, 3713e5da754SJohn Baldwin RANDOM_INTERRUPT); 3723e5da754SJohn Baldwin } 3733e5da754SJohn Baldwin 374b40ce416SJulian Elischer td = ithread->it_td; 375b40ce416SJulian Elischer p = td->td_proc; 376653dd8c2SJohn Baldwin KASSERT(p != NULL, ("ithread %s has no process", ithread->it_name)); 377e602ba25SJulian Elischer CTR4(KTR_INTR, "%s: pid %d: (%s) need = %d", 378e602ba25SJulian Elischer __func__, p->p_pid, p->p_comm, ithread->it_need); 3793e5da754SJohn Baldwin 3803e5da754SJohn Baldwin /* 3813e5da754SJohn Baldwin * Set it_need to tell the thread to keep running if it is already 3823e5da754SJohn Baldwin * running. Then, grab sched_lock and see if we actually need to 3833e5da754SJohn Baldwin * put this thread on the runqueue. If so and the do_switch flag is 384c86b6ff5SJohn Baldwin * true and it is safe to switch, then switch to the ithread 385c86b6ff5SJohn Baldwin * immediately. Otherwise, set the needresched flag to guarantee 386c86b6ff5SJohn Baldwin * that this ithread will run before any userland processes. 3873e5da754SJohn Baldwin */ 3883e5da754SJohn Baldwin ithread->it_need = 1; 3893e5da754SJohn Baldwin mtx_lock_spin(&sched_lock); 39071fad9fdSJulian Elischer if (TD_AWAITING_INTR(td)) { 39191f91617SDavid E. O'Brien CTR2(KTR_INTR, "%s: setrunqueue %d", __func__, p->p_pid); 39271fad9fdSJulian Elischer TD_CLR_IWAIT(td); 393e602ba25SJulian Elischer setrunqueue(td); 394e602ba25SJulian Elischer if (do_switch && 39504774f23SJulian Elischer (ctd->td_critnest == 1) ) { 39671fad9fdSJulian Elischer KASSERT((TD_IS_RUNNING(ctd)), 39704774f23SJulian Elischer ("ithread_schedule: Bad state for curthread.")); 39804774f23SJulian Elischer ctd->td_proc->p_stats->p_ru.ru_nivcsw++; 39904774f23SJulian Elischer if (ctd->td_kse->ke_flags & KEF_IDLEKSE) 40071fad9fdSJulian Elischer ctd->td_state = TDS_CAN_RUN; /* XXXKSE */ 4013e5da754SJohn Baldwin mi_switch(); 4022d0231f5SJulian Elischer } else { 403b40ce416SJulian Elischer curthread->td_kse->ke_flags |= KEF_NEEDRESCHED; 4042d0231f5SJulian Elischer } 4053e5da754SJohn Baldwin } else { 40691f91617SDavid E. O'Brien CTR4(KTR_INTR, "%s: pid %d: it_need %d, state %d", 407e602ba25SJulian Elischer __func__, p->p_pid, ithread->it_need, p->p_state); 4083e5da754SJohn Baldwin } 4093e5da754SJohn Baldwin mtx_unlock_spin(&sched_lock); 4103e5da754SJohn Baldwin 4113e5da754SJohn Baldwin return (0); 4123e5da754SJohn Baldwin } 4133e5da754SJohn Baldwin 4143e5da754SJohn Baldwin int 415b4151f71SJohn Baldwin swi_add(struct ithd **ithdp, const char *name, driver_intr_t handler, 416b4151f71SJohn Baldwin void *arg, int pri, enum intr_type flags, void **cookiep) 4178088699fSJohn Baldwin { 4188088699fSJohn Baldwin struct ithd *ithd; 419b4151f71SJohn Baldwin int error; 4208088699fSJohn Baldwin 4213e5da754SJohn Baldwin if (flags & (INTR_FAST | INTR_ENTROPY)) 4223e5da754SJohn Baldwin return (EINVAL); 4233e5da754SJohn Baldwin 4248088699fSJohn Baldwin ithd = (ithdp != NULL) ? *ithdp : NULL; 4258088699fSJohn Baldwin 4263e5da754SJohn Baldwin if (ithd != NULL) { 4273e5da754SJohn Baldwin if ((ithd->it_flags & IT_SOFT) == 0) 4283e5da754SJohn Baldwin return(EINVAL); 4293e5da754SJohn Baldwin } else { 430b4151f71SJohn Baldwin error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL, 431b4151f71SJohn Baldwin "swi%d:", pri); 4328088699fSJohn Baldwin if (error) 433b4151f71SJohn Baldwin return (error); 434b4151f71SJohn Baldwin 4358088699fSJohn Baldwin if (ithdp != NULL) 4368088699fSJohn Baldwin *ithdp = ithd; 4378088699fSJohn Baldwin } 438d5a08a60SJake Burkholder return (ithread_add_handler(ithd, name, handler, arg, 439d5a08a60SJake Burkholder (pri * RQ_PPQ) + PI_SOFT, flags, cookiep)); 4408088699fSJohn Baldwin } 4418088699fSJohn Baldwin 4428088699fSJohn Baldwin 4431931cf94SJohn Baldwin /* 4448088699fSJohn Baldwin * Schedule a heavyweight software interrupt process. 4451931cf94SJohn Baldwin */ 4461931cf94SJohn Baldwin void 447b4151f71SJohn Baldwin swi_sched(void *cookie, int flags) 4481931cf94SJohn Baldwin { 449b4151f71SJohn Baldwin struct intrhand *ih = (struct intrhand *)cookie; 450b4151f71SJohn Baldwin struct ithd *it = ih->ih_ithread; 4513e5da754SJohn Baldwin int error; 4528088699fSJohn Baldwin 4531931cf94SJohn Baldwin atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */ 4541931cf94SJohn Baldwin 455b4151f71SJohn Baldwin CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d", 456b40ce416SJulian Elischer it->it_td->td_proc->p_pid, it->it_td->td_proc->p_comm, it->it_need); 4571931cf94SJohn Baldwin 4581931cf94SJohn Baldwin /* 4593e5da754SJohn Baldwin * Set ih_need for this handler so that if the ithread is already 4603e5da754SJohn Baldwin * running it will execute this handler on the next pass. Otherwise, 4613e5da754SJohn Baldwin * it will execute it the next time it runs. 4621931cf94SJohn Baldwin */ 463b4151f71SJohn Baldwin atomic_store_rel_int(&ih->ih_need, 1); 464b4151f71SJohn Baldwin if (!(flags & SWI_DELAY)) { 465c11110eaSAlfred Perlstein error = ithread_schedule(it, !cold && !dumping); 4663e5da754SJohn Baldwin KASSERT(error == 0, ("stray software interrupt")); 4678088699fSJohn Baldwin } 4688088699fSJohn Baldwin } 4698088699fSJohn Baldwin 4708088699fSJohn Baldwin /* 471b4151f71SJohn Baldwin * This is the main code for interrupt threads. 4728088699fSJohn Baldwin */ 47337c84183SPoul-Henning Kamp static void 474b4151f71SJohn Baldwin ithread_loop(void *arg) 4758088699fSJohn Baldwin { 476b4151f71SJohn Baldwin struct ithd *ithd; /* our thread context */ 4778088699fSJohn Baldwin struct intrhand *ih; /* and our interrupt handler chain */ 478b40ce416SJulian Elischer struct thread *td; 479b4151f71SJohn Baldwin struct proc *p; 4808088699fSJohn Baldwin 481b40ce416SJulian Elischer td = curthread; 482b40ce416SJulian Elischer p = td->td_proc; 483b4151f71SJohn Baldwin ithd = (struct ithd *)arg; /* point to myself */ 484b40ce416SJulian Elischer KASSERT(ithd->it_td == td && td->td_ithd == ithd, 48591f91617SDavid E. O'Brien ("%s: ithread and proc linkage out of sync", __func__)); 4868088699fSJohn Baldwin 4878088699fSJohn Baldwin /* 4888088699fSJohn Baldwin * As long as we have interrupts outstanding, go through the 4898088699fSJohn Baldwin * list of handlers, giving each one a go at it. 4908088699fSJohn Baldwin */ 4918088699fSJohn Baldwin for (;;) { 492b4151f71SJohn Baldwin /* 493b4151f71SJohn Baldwin * If we are an orphaned thread, then just die. 494b4151f71SJohn Baldwin */ 495b4151f71SJohn Baldwin if (ithd->it_flags & IT_DEAD) { 49691f91617SDavid E. O'Brien CTR3(KTR_INTR, "%s: pid %d: (%s) exiting", __func__, 497b4151f71SJohn Baldwin p->p_pid, p->p_comm); 498b40ce416SJulian Elischer td->td_ithd = NULL; 4994d29cb2dSJohn Baldwin mtx_destroy(&ithd->it_lock); 500b4151f71SJohn Baldwin mtx_lock(&Giant); 501b4151f71SJohn Baldwin free(ithd, M_ITHREAD); 502b4151f71SJohn Baldwin kthread_exit(0); 503b4151f71SJohn Baldwin } 504b4151f71SJohn Baldwin 50591f91617SDavid E. O'Brien CTR4(KTR_INTR, "%s: pid %d: (%s) need=%d", __func__, 506b4151f71SJohn Baldwin p->p_pid, p->p_comm, ithd->it_need); 507b4151f71SJohn Baldwin while (ithd->it_need) { 5088088699fSJohn Baldwin /* 5098088699fSJohn Baldwin * Service interrupts. If another interrupt 5108088699fSJohn Baldwin * arrives while we are running, they will set 5118088699fSJohn Baldwin * it_need to denote that we should make 5128088699fSJohn Baldwin * another pass. 5138088699fSJohn Baldwin */ 514b4151f71SJohn Baldwin atomic_store_rel_int(&ithd->it_need, 0); 515de271f01SJohn Baldwin restart: 516b4151f71SJohn Baldwin TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 517b4151f71SJohn Baldwin if (ithd->it_flags & IT_SOFT && !ih->ih_need) 5188088699fSJohn Baldwin continue; 519b4151f71SJohn Baldwin atomic_store_rel_int(&ih->ih_need, 0); 52091f91617SDavid E. O'Brien CTR6(KTR_INTR, 52191f91617SDavid E. O'Brien "%s: pid %d ih=%p: %p(%p) flg=%x", __func__, 5228088699fSJohn Baldwin p->p_pid, (void *)ih, 5238088699fSJohn Baldwin (void *)ih->ih_handler, ih->ih_argument, 5248088699fSJohn Baldwin ih->ih_flags); 5258088699fSJohn Baldwin 526de271f01SJohn Baldwin if ((ih->ih_flags & IH_DEAD) != 0) { 5274d29cb2dSJohn Baldwin mtx_lock(&ithd->it_lock); 528de271f01SJohn Baldwin TAILQ_REMOVE(&ithd->it_handlers, ih, 529de271f01SJohn Baldwin ih_next); 5304d29cb2dSJohn Baldwin wakeup(ih); 5314d29cb2dSJohn Baldwin mtx_unlock(&ithd->it_lock); 532de271f01SJohn Baldwin goto restart; 533de271f01SJohn Baldwin } 5344d29cb2dSJohn Baldwin if ((ih->ih_flags & IH_MPSAFE) == 0) 5354d29cb2dSJohn Baldwin mtx_lock(&Giant); 5368088699fSJohn Baldwin ih->ih_handler(ih->ih_argument); 537b4151f71SJohn Baldwin if ((ih->ih_flags & IH_MPSAFE) == 0) 5389ed346baSBosko Milekic mtx_unlock(&Giant); 5398088699fSJohn Baldwin } 5408088699fSJohn Baldwin } 5418088699fSJohn Baldwin 5428088699fSJohn Baldwin /* 5438088699fSJohn Baldwin * Processed all our interrupts. Now get the sched 5448088699fSJohn Baldwin * lock. This may take a while and it_need may get 5458088699fSJohn Baldwin * set again, so we have to check it again. 5468088699fSJohn Baldwin */ 547896c2303SJohn Baldwin mtx_assert(&Giant, MA_NOTOWNED); 5489ed346baSBosko Milekic mtx_lock_spin(&sched_lock); 549b4151f71SJohn Baldwin if (!ithd->it_need) { 550b4151f71SJohn Baldwin /* 551b4151f71SJohn Baldwin * Should we call this earlier in the loop above? 552b4151f71SJohn Baldwin */ 553b4151f71SJohn Baldwin if (ithd->it_enable != NULL) 554b4151f71SJohn Baldwin ithd->it_enable(ithd->it_vector); 55571fad9fdSJulian Elischer TD_SET_IWAIT(td); /* we're idle */ 55684bbc4dbSJohn Baldwin p->p_stats->p_ru.ru_nvcsw++; 55791f91617SDavid E. O'Brien CTR2(KTR_INTR, "%s: pid %d: done", __func__, p->p_pid); 5588088699fSJohn Baldwin mi_switch(); 55991f91617SDavid E. O'Brien CTR2(KTR_INTR, "%s: pid %d: resumed", __func__, p->p_pid); 5608088699fSJohn Baldwin } 5619ed346baSBosko Milekic mtx_unlock_spin(&sched_lock); 5628088699fSJohn Baldwin } 5631931cf94SJohn Baldwin } 5641931cf94SJohn Baldwin 565b4151f71SJohn Baldwin /* 5668088699fSJohn Baldwin * Start standard software interrupt threads 5671931cf94SJohn Baldwin */ 5681931cf94SJohn Baldwin static void 569b4151f71SJohn Baldwin start_softintr(void *dummy) 5701931cf94SJohn Baldwin { 571b4151f71SJohn Baldwin 572e3b6e33cSJake Burkholder if (swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK, 573b4151f71SJohn Baldwin INTR_MPSAFE, &softclock_ih) || 574b4151f71SJohn Baldwin swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, 0, &vm_ih)) 575b4151f71SJohn Baldwin panic("died while creating standard software ithreads"); 5763e5da754SJohn Baldwin 577b40ce416SJulian Elischer PROC_LOCK(clk_ithd->it_td->td_proc); 578b40ce416SJulian Elischer clk_ithd->it_td->td_proc->p_flag |= P_NOLOAD; 579b40ce416SJulian Elischer PROC_UNLOCK(clk_ithd->it_td->td_proc); 5801931cf94SJohn Baldwin } 581b4151f71SJohn Baldwin SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL) 5821931cf94SJohn Baldwin 583d279178dSThomas Moestl /* 584d279178dSThomas Moestl * Sysctls used by systat and others: hw.intrnames and hw.intrcnt. 585d279178dSThomas Moestl * The data for this machine dependent, and the declarations are in machine 586d279178dSThomas Moestl * dependent code. The layout of intrnames and intrcnt however is machine 587d279178dSThomas Moestl * independent. 588d279178dSThomas Moestl * 589d279178dSThomas Moestl * We do not know the length of intrcnt and intrnames at compile time, so 590d279178dSThomas Moestl * calculate things at run time. 591d279178dSThomas Moestl */ 592d279178dSThomas Moestl static int 593d279178dSThomas Moestl sysctl_intrnames(SYSCTL_HANDLER_ARGS) 594d279178dSThomas Moestl { 595d279178dSThomas Moestl return (sysctl_handle_opaque(oidp, intrnames, eintrnames - intrnames, 596d279178dSThomas Moestl req)); 597d279178dSThomas Moestl } 598d279178dSThomas Moestl 599d279178dSThomas Moestl SYSCTL_PROC(_hw, OID_AUTO, intrnames, CTLTYPE_OPAQUE | CTLFLAG_RD, 600d279178dSThomas Moestl NULL, 0, sysctl_intrnames, "", "Interrupt Names"); 601d279178dSThomas Moestl 602d279178dSThomas Moestl static int 603d279178dSThomas Moestl sysctl_intrcnt(SYSCTL_HANDLER_ARGS) 604d279178dSThomas Moestl { 605d279178dSThomas Moestl return (sysctl_handle_opaque(oidp, intrcnt, 606d279178dSThomas Moestl (char *)eintrcnt - (char *)intrcnt, req)); 607d279178dSThomas Moestl } 608d279178dSThomas Moestl 609d279178dSThomas Moestl SYSCTL_PROC(_hw, OID_AUTO, intrcnt, CTLTYPE_OPAQUE | CTLFLAG_RD, 610d279178dSThomas Moestl NULL, 0, sysctl_intrcnt, "", "Interrupt Counts"); 611