kern_intr.c revision 72839
11541Srgrimes/* 21541Srgrimes * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 31541Srgrimes * All rights reserved. 41541Srgrimes * 51541Srgrimes * Redistribution and use in source and binary forms, with or without 61541Srgrimes * modification, are permitted provided that the following conditions 71541Srgrimes * are met: 81541Srgrimes * 1. Redistributions of source code must retain the above copyright 91541Srgrimes * notice unmodified, this list of conditions, and the following 101541Srgrimes * disclaimer. 111541Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 121541Srgrimes * notice, this list of conditions and the following disclaimer in the 131541Srgrimes * documentation and/or other materials provided with the distribution. 141541Srgrimes * 151541Srgrimes * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 161541Srgrimes * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 171541Srgrimes * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 181541Srgrimes * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 191541Srgrimes * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 201541Srgrimes * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 211541Srgrimes * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 221541Srgrimes * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 231541Srgrimes * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 241541Srgrimes * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 251541Srgrimes * 261541Srgrimes * $FreeBSD: head/sys/kern/kern_intr.c 72839 2001-02-22 02:18:32Z jhb $ 271541Srgrimes * 281541Srgrimes */ 291541Srgrimes 301541Srgrimes 311541Srgrimes#include <sys/param.h> 321541Srgrimes#include <sys/bus.h> 331541Srgrimes#include <sys/rtprio.h> 341541Srgrimes#include <sys/systm.h> 351541Srgrimes#include <sys/ipl.h> 361541Srgrimes#include <sys/interrupt.h> 371541Srgrimes#include <sys/kernel.h> 381541Srgrimes#include <sys/kthread.h> 3915985Sdg#include <sys/ktr.h> 401541Srgrimes#include <sys/malloc.h> 411541Srgrimes#include <sys/mutex.h> 421541Srgrimes#include <sys/proc.h> 431541Srgrimes#include <sys/random.h> 441541Srgrimes#include <sys/resourcevar.h> 451541Srgrimes#include <sys/unistd.h> 461541Srgrimes#include <sys/vmmeter.h> 471541Srgrimes#include <machine/atomic.h> 481541Srgrimes#include <machine/cpu.h> 4912221Sbde#include <machine/md_var.h> 501541Srgrimes#include <machine/stdarg.h> 511541Srgrimes 521541Srgrimes#include <net/netisr.h> /* prototype for legacy_setsoftnet */ 531541Srgrimes 541541Srgrimesstruct int_entropy { 551541Srgrimes struct proc *proc; 5612221Sbde int vector; 5711332Sswallace}; 581541Srgrimes 591541Srgrimesvoid *net_ih; 6012221Sbdevoid *vm_ih; 611541Srgrimesvoid *softclock_ih; 621541Srgrimesstruct ithd *clk_ithd; 631549Srgrimesstruct ithd *tty_ithd; 641541Srgrimes 651541Srgrimesstatic struct mtx ithread_list_lock; 6611332Sswallace 671541Srgrimesstatic MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads"); 681541Srgrimes 691541Srgrimesstatic void ithread_update(struct ithd *); 701541Srgrimesstatic void ithread_loop(void *); 711541Srgrimesstatic void ithread_init(void *); 721541Srgrimesstatic void start_softintr(void *); 731541Srgrimesstatic void swi_net(void *); 741541Srgrimes 751541Srgrimesu_char 761541Srgrimesithread_priority(enum intr_type flags) 7712221Sbde{ 7811332Sswallace u_char pri; 7911332Sswallace 8011332Sswallace flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET | 8112221Sbde INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK); 821541Srgrimes switch (flags) { 831549Srgrimes case INTR_TYPE_TTY: 841541Srgrimes pri = PI_TTYLOW; 851541Srgrimes break; 8611332Sswallace case INTR_TYPE_BIO: 871541Srgrimes /* 881541Srgrimes * XXX We need to refine this. BSD/OS distinguishes 891541Srgrimes * between tape and disk priorities. 901541Srgrimes */ 911541Srgrimes pri = PI_DISK; 921541Srgrimes break; 931541Srgrimes case INTR_TYPE_NET: 941541Srgrimes pri = PI_NET; 9512221Sbde break; 9611332Sswallace case INTR_TYPE_CAM: 9711332Sswallace pri = PI_DISK; /* XXX or PI_CAM? */ 9811332Sswallace break; 9912221Sbde case INTR_TYPE_CLK: 10011332Sswallace pri = PI_REALTIME; 1011549Srgrimes break; 1021541Srgrimes case INTR_TYPE_MISC: 1031541Srgrimes pri = PI_DULL; /* don't care */ 10411332Sswallace break; 1051541Srgrimes default: 1061541Srgrimes /* We didn't specify an interrupt level. */ 1071541Srgrimes panic("ithread_priority: no interrupt type in flags"); 1081541Srgrimes } 1091541Srgrimes 1101541Srgrimes return pri; 1111541Srgrimes} 11212221Sbde 11311332Sswallace/* 11411332Sswallace * Regenerate the name (p_comm) and priority for a threaded interrupt thread. 11511332Sswallace */ 11612221Sbdestatic void 11711332Sswallaceithread_update(struct ithd *ithd) 1181541Srgrimes{ 1191549Srgrimes struct intrhand *ih; 1201541Srgrimes struct proc *p; 1211541Srgrimes int entropy; 12211332Sswallace 1231541Srgrimes p = ithd->it_proc; 1241541Srgrimes if (p == NULL) 1251541Srgrimes return; 1261541Srgrimes 1271541Srgrimes strncpy(p->p_comm, ithd->it_name, sizeof(ithd->it_name)); 1281541Srgrimes ih = TAILQ_FIRST(&ithd->it_handlers); 1291541Srgrimes if (ih == NULL) { 1301541Srgrimes p->p_pri.pri_level = PRI_MAX_ITHD; 1311541Srgrimes ithd->it_flags &= ~IT_ENTROPY; 1321541Srgrimes return; 13312221Sbde } 13411332Sswallace 13511332Sswallace entropy = 0; 13611332Sswallace p->p_pri.pri_level = ih->ih_pri; 13712221Sbde TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 13811332Sswallace if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 < 1391541Srgrimes sizeof(p->p_comm)) { 1401549Srgrimes strcat(p->p_comm, " "); 1411541Srgrimes strcat(p->p_comm, ih->ih_name); 1421541Srgrimes } else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) { 14311332Sswallace if (p->p_comm[sizeof(p->p_comm) - 2] == '+') 1441541Srgrimes p->p_comm[sizeof(p->p_comm) - 2] = '*'; 1451541Srgrimes else 1461541Srgrimes p->p_comm[sizeof(p->p_comm) - 2] = '+'; 1471541Srgrimes } else 1481541Srgrimes strcat(p->p_comm, "+"); 1491541Srgrimes if (ih->ih_flags & IH_ENTROPY) 1501541Srgrimes entropy++; 15112221Sbde } 15211332Sswallace 15311332Sswallace if (entropy) 15411332Sswallace ithd->it_flags |= IT_ENTROPY; 15512221Sbde else 15611332Sswallace ithd->it_flags &= ~IT_ENTROPY; 1571541Srgrimes 1581549Srgrimes CTR1(KTR_INTR, __func__ ": updated %s\n", p->p_comm); 1591541Srgrimes} 1601541Srgrimes 16111332Sswallaceint 1621541Srgrimesithread_create(struct ithd **ithread, int vector, int flags, 1631541Srgrimes void (*disable)(int), void (*enable)(int), const char *fmt, ...) 1641541Srgrimes{ 1651541Srgrimes struct ithd *ithd; 1661541Srgrimes struct proc *p; 1671541Srgrimes int error; 1681541Srgrimes va_list ap; 1691541Srgrimes 1701541Srgrimes /* The only valid flag during creation is IT_SOFT. */ 1711541Srgrimes if ((flags & ~IT_SOFT) != 0) 1721541Srgrimes return (EINVAL); 1731541Srgrimes 1741541Srgrimes ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO); 1751541Srgrimes ithd->it_vector = vector; 1761541Srgrimes ithd->it_disable = disable; 17712221Sbde ithd->it_enable = enable; 17811332Sswallace ithd->it_flags = flags; 17911332Sswallace TAILQ_INIT(&ithd->it_handlers); 18011332Sswallace 18112221Sbde va_start(ap, fmt); 18211332Sswallace vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap); 1831541Srgrimes va_end(ap); 1841549Srgrimes 1851541Srgrimes error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID, 1861541Srgrimes ithd->it_name); 18711332Sswallace if (error) { 1881541Srgrimes free(ithd, M_ITHREAD); 1891541Srgrimes return (error); 1901541Srgrimes } 1911541Srgrimes p->p_pri.pri_class = PRI_ITHD; 1921541Srgrimes p->p_pri.pri_level = PRI_MAX_ITHD; 1931541Srgrimes p->p_stat = SWAIT; 1941541Srgrimes ithd->it_proc = p; 19512221Sbde p->p_ithd = ithd; 1961541Srgrimes if (ithread != NULL) 1971541Srgrimes *ithread = ithd; 1981541Srgrimes 1991541Srgrimes CTR1(KTR_INTR, __func__ ": created %s", ithd->it_name); 20012221Sbde return (0); 2011549Srgrimes} 2021541Srgrimes 2031541Srgrimesint 2041541Srgrimesithread_destroy(struct ithd *ithread) 2051541Srgrimes{ 2061541Srgrimes 2071541Srgrimes if (ithread == NULL || !TAILQ_EMPTY(&ithread->it_handlers)) 2081541Srgrimes return (EINVAL); 2091541Srgrimes 2101541Srgrimes mtx_lock_spin(&sched_lock); 2111541Srgrimes ithread->it_flags |= IT_DEAD; 2121541Srgrimes if (ithread->it_proc->p_stat == SWAIT) { 2131541Srgrimes ithread->it_proc->p_stat = SRUN; 2141541Srgrimes setrunqueue(ithread->it_proc); 2151541Srgrimes } 2161541Srgrimes mtx_unlock_spin(&sched_lock); 2171541Srgrimes CTR1(KTR_INTR, __func__ ": killing %s", ithread->it_name); 2183098Sphk return (0); 2193098Sphk} 2201541Srgrimes 2211541Srgrimesint 2221541Srgrimesithread_add_handler(struct ithd* ithread, const char *name, 2231541Srgrimes driver_intr_t handler, void *arg, u_char pri, enum intr_type flags, 2241541Srgrimes void **cookiep) 22512221Sbde{ 22612207Sbde struct intrhand *ih, *temp_ih; 22711332Sswallace 22811332Sswallace if (ithread == NULL || name == NULL || handler == NULL) 22912221Sbde return (EINVAL); 23011332Sswallace if ((flags & INTR_FAST) !=0) 2311541Srgrimes flags |= INTR_EXCL; 2321549Srgrimes 2331541Srgrimes ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_WAITOK | M_ZERO); 2341541Srgrimes ih->ih_handler = handler; 23512207Sbde ih->ih_argument = arg; 2361541Srgrimes ih->ih_name = name; 2371541Srgrimes ih->ih_ithread = ithread; 2381541Srgrimes ih->ih_pri = pri; 2391541Srgrimes if (flags & INTR_FAST) 2401541Srgrimes ih->ih_flags = IH_FAST | IH_EXCLUSIVE; 2411541Srgrimes else if (flags & INTR_EXCL) 2421541Srgrimes ih->ih_flags = IH_EXCLUSIVE; 2431541Srgrimes if (flags & INTR_MPSAFE) 2441541Srgrimes ih->ih_flags |= IH_MPSAFE; 2451541Srgrimes if (flags & INTR_ENTROPY) 2461541Srgrimes ih->ih_flags |= IH_ENTROPY; 2471541Srgrimes 2481541Srgrimes mtx_lock_spin(&ithread_list_lock); 2491541Srgrimes if ((flags & INTR_EXCL) !=0 && !TAILQ_EMPTY(&ithread->it_handlers)) 2501541Srgrimes goto fail; 2511541Srgrimes if (!TAILQ_EMPTY(&ithread->it_handlers) && 2521541Srgrimes (TAILQ_FIRST(&ithread->it_handlers)->ih_flags & IH_EXCLUSIVE) != 0) 2531541Srgrimes goto fail; 2541541Srgrimes 2551541Srgrimes TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next) 2561541Srgrimes if (temp_ih->ih_pri > ih->ih_pri) 2571541Srgrimes break; 2581541Srgrimes if (temp_ih == NULL) 2591541Srgrimes TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next); 2601541Srgrimes else 26112221Sbde TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next); 2621541Srgrimes ithread_update(ithread); 2631541Srgrimes mtx_unlock_spin(&ithread_list_lock); 2641541Srgrimes 2651541Srgrimes if (cookiep != NULL) 26612221Sbde *cookiep = ih; 2671541Srgrimes CTR2(KTR_INTR, __func__ ": added %s to %s", ih->ih_name, 2681549Srgrimes ithread->it_name); 2691541Srgrimes return (0); 2701541Srgrimes 2711541Srgrimesfail: 2721541Srgrimes mtx_unlock_spin(&ithread_list_lock); 2731541Srgrimes free(ih, M_ITHREAD); 2741541Srgrimes return (EINVAL); 2751541Srgrimes} 2761541Srgrimes 2771541Srgrimesint 2781541Srgrimesithread_remove_handler(void *cookie) 2791541Srgrimes{ 28015985Sdg struct intrhand *handler = (struct intrhand *)cookie; 2811541Srgrimes struct ithd *ithread; 2821541Srgrimes#ifdef INVARIANTS 2831541Srgrimes struct intrhand *ih; 2841541Srgrimes#endif 2851541Srgrimes 2861541Srgrimes if (handler == NULL) 2871541Srgrimes return (EINVAL); 2881541Srgrimes ithread = handler->ih_ithread; 2891541Srgrimes KASSERT(ithread != NULL, 2901541Srgrimes ("interrupt handler \"%s\" has a NULL interrupt thread", 2911541Srgrimes handler->ih_name)); 2921541Srgrimes CTR2(KTR_INTR, __func__ ": removing %s from %s", handler->ih_name, 2931541Srgrimes ithread->it_name); 2941541Srgrimes mtx_lock_spin(&ithread_list_lock); 2951541Srgrimes#ifdef INVARIANTS 2961541Srgrimes TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next) 29712221Sbde if (ih == handler) 2981541Srgrimes goto ok; 2991541Srgrimes mtx_unlock_spin(&ithread_list_lock); 3001541Srgrimes panic("interrupt handler \"%s\" not found in interrupt thread \"%s\"", 30112221Sbde ih->ih_name, ithread->it_name); 3021541Srgrimesok: 3031549Srgrimes#endif 3041541Srgrimes /* 3051541Srgrimes * If the interrupt thread is already running, then just mark this 3061541Srgrimes * handler as being dead and let the ithread do the actual removal. 3071541Srgrimes */ 3081541Srgrimes mtx_lock_spin(&sched_lock); 3091541Srgrimes if (ithread->it_proc->p_stat != SWAIT) { 3101541Srgrimes handler->ih_flags |= IH_DEAD; 3111541Srgrimes 3121541Srgrimes /* 3131541Srgrimes * Ensure that the thread will process the handler list 3148162Sache * again and remove this handler if it has already passed 3158162Sache * it on the list. 3161541Srgrimes */ 3171541Srgrimes ithread->it_need = 1; 3181541Srgrimes } else { 3191541Srgrimes TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next); 3201541Srgrimes ithread_update(ithread); 3211541Srgrimes } 3228162Sache mtx_unlock_spin(&sched_lock); 3238141Sache mtx_unlock_spin(&ithread_list_lock); 3248141Sache 3258141Sache if ((handler->ih_flags & IH_DEAD) == 0) 3261541Srgrimes free(handler, M_ITHREAD); 3278162Sache return (0); 3288141Sache} 3298141Sache 3308141Sacheint 3318162Sacheithread_schedule(struct ithd *ithread, int do_switch) 3321541Srgrimes{ 3331541Srgrimes struct int_entropy entropy; 3341541Srgrimes struct proc *p; 3351541Srgrimes intrmask_t saveintr; 33612221Sbde 3371541Srgrimes /* 3381541Srgrimes * If no ithread or no handlers, then we have a stray interrupt. 3391541Srgrimes */ 34012221Sbde if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers)) 3411541Srgrimes return (EINVAL); 3421549Srgrimes 3431541Srgrimes /* 3441541Srgrimes * If any of the handlers for this ithread claim to be good 3451541Srgrimes * sources of entropy, then gather some. 3461541Srgrimes */ 3471541Srgrimes if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) { 3481541Srgrimes entropy.vector = ithread->it_vector; 3491541Srgrimes entropy.proc = CURPROC; 3501541Srgrimes random_harvest(&entropy, sizeof(entropy), 2, 0, 3511541Srgrimes RANDOM_INTERRUPT); 3521541Srgrimes } 3531541Srgrimes 3541541Srgrimes p = ithread->it_proc; 3551541Srgrimes CTR3(KTR_INTR, __func__ ": pid %d: (%s) need = %d", p->p_pid, p->p_comm, 3561541Srgrimes ithread->it_need); 3571541Srgrimes 3581541Srgrimes /* 3591541Srgrimes * Set it_need to tell the thread to keep running if it is already 3601541Srgrimes * running. Then, grab sched_lock and see if we actually need to 3611541Srgrimes * put this thread on the runqueue. If so and the do_switch flag is 3621541Srgrimes * true, then switch to the ithread immediately. Otherwise, use 3631541Srgrimes * need_resched() to guarantee that this ithread will run before any 3641541Srgrimes * userland processes. 3651541Srgrimes */ 36612221Sbde ithread->it_need = 1; 3671541Srgrimes mtx_lock_spin(&sched_lock); 3681541Srgrimes if (p->p_stat == SWAIT) { 3691541Srgrimes CTR1(KTR_INTR, __func__ ": setrunqueue %d", p->p_pid); 37012221Sbde p->p_stat = SRUN; 3711541Srgrimes setrunqueue(p); 3721549Srgrimes if (do_switch) { 3731541Srgrimes saveintr = sched_lock.mtx_saveintr; 3741541Srgrimes mtx_intr_enable(&sched_lock); 3751541Srgrimes if (curproc != PCPU_GET(idleproc)) 3761541Srgrimes setrunqueue(curproc); 3771541Srgrimes curproc->p_stats->p_ru.ru_nvcsw++; 3781541Srgrimes mi_switch(); 3791541Srgrimes sched_lock.mtx_saveintr = saveintr; 3801541Srgrimes } else 3811541Srgrimes need_resched(); 3821541Srgrimes } else { 3838162Sache CTR3(KTR_INTR, __func__ ": pid %d: it_need %d, state %d", 3848162Sache p->p_pid, ithread->it_need, p->p_stat); 3851541Srgrimes } 3861541Srgrimes mtx_unlock_spin(&sched_lock); 3871541Srgrimes 3888162Sache return (0); 3898141Sache} 3908141Sache 3918141Sacheint 3921541Srgrimesswi_add(struct ithd **ithdp, const char *name, driver_intr_t handler, 3931541Srgrimes void *arg, int pri, enum intr_type flags, void **cookiep) 3941541Srgrimes{ 3951541Srgrimes struct ithd *ithd; 39612221Sbde int error; 3971541Srgrimes 3981541Srgrimes if (flags & (INTR_FAST | INTR_ENTROPY)) 3991541Srgrimes return (EINVAL); 40012221Sbde 4011541Srgrimes ithd = (ithdp != NULL) ? *ithdp : NULL; 4021549Srgrimes 4031541Srgrimes if (ithd != NULL) { 4041541Srgrimes if ((ithd->it_flags & IT_SOFT) == 0) 4051541Srgrimes return(EINVAL); 4061541Srgrimes } else { 4071541Srgrimes error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL, 4081541Srgrimes "swi%d:", pri); 4091541Srgrimes if (error) 4101541Srgrimes return (error); 4111541Srgrimes 4121541Srgrimes if (ithdp != NULL) 4131541Srgrimes *ithdp = ithd; 4141541Srgrimes } 4151541Srgrimes return (ithread_add_handler(ithd, name, handler, arg, 4161541Srgrimes (pri * RQ_PPQ) + PI_SOFT, flags, cookiep)); 4171541Srgrimes} 4181541Srgrimes 4191541Srgrimes 4201541Srgrimes/* 4211541Srgrimes * Schedule a heavyweight software interrupt process. 42212221Sbde */ 4231541Srgrimesvoid 4241541Srgrimesswi_sched(void *cookie, int flags) 4251541Srgrimes{ 4261541Srgrimes struct intrhand *ih = (struct intrhand *)cookie; 42712221Sbde struct ithd *it = ih->ih_ithread; 4281541Srgrimes int error; 4291549Srgrimes 4301541Srgrimes atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */ 4311541Srgrimes 4321541Srgrimes CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d", 4331541Srgrimes it->it_proc->p_pid, it->it_proc->p_comm, it->it_need); 4341541Srgrimes 4351541Srgrimes /* 4361541Srgrimes * Set ih_need for this handler so that if the ithread is already 4371541Srgrimes * running it will execute this handler on the next pass. Otherwise, 4381541Srgrimes * it will execute it the next time it runs. 4393098Sphk */ 4401541Srgrimes atomic_store_rel_int(&ih->ih_need, 1); 44112063Sdg if (!(flags & SWI_DELAY)) { 44212063Sdg error = ithread_schedule(it, !cold && flags & SWI_SWITCH); 4431541Srgrimes KASSERT(error == 0, ("stray software interrupt")); 4441541Srgrimes } 4453098Sphk} 4463098Sphk 4471541Srgrimes/* 4481541Srgrimes * This is the main code for interrupt threads. 4491541Srgrimes */ 4501541Srgrimesvoid 4511541Srgrimesithread_loop(void *arg) 4521541Srgrimes{ 45312221Sbde struct ithd *ithd; /* our thread context */ 4541541Srgrimes struct intrhand *ih; /* and our interrupt handler chain */ 4559238Sache struct proc *p; 4569238Sache 4571541Srgrimes p = curproc; 45812221Sbde ithd = (struct ithd *)arg; /* point to myself */ 4591541Srgrimes KASSERT(ithd->it_proc == p && p->p_ithd == ithd, 4601549Srgrimes (__func__ ": ithread and proc linkage out of sync")); 4618019Sache 4621541Srgrimes /* 4631541Srgrimes * As long as we have interrupts outstanding, go through the 4641541Srgrimes * list of handlers, giving each one a go at it. 4651541Srgrimes */ 4661541Srgrimes for (;;) { 4679238Sache /* 4688135Sache * If we are an orphaned thread, then just die. 4691541Srgrimes */ 4709238Sache if (ithd->it_flags & IT_DEAD) { 4719238Sache CTR2(KTR_INTR, __func__ ": pid %d: (%s) exiting", 4729238Sache p->p_pid, p->p_comm); 4739238Sache p->p_ithd = NULL; 4748135Sache mtx_lock(&Giant); 4758135Sache free(ithd, M_ITHREAD); 4769238Sache kthread_exit(0); 4779238Sache } 4789238Sache 4799238Sache CTR3(KTR_INTR, __func__ ": pid %d: (%s) need=%d", 4809238Sache p->p_pid, p->p_comm, ithd->it_need); 4819238Sache while (ithd->it_need) { 4829238Sache /* 4839238Sache * Service interrupts. If another interrupt 4848135Sache * arrives while we are running, they will set 4859238Sache * it_need to denote that we should make 4868111Sache * another pass. 4879238Sache */ 4888135Sache atomic_store_rel_int(&ithd->it_need, 0); 4891541Srgrimesrestart: 4901541Srgrimes TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 49112221Sbde if (ithd->it_flags & IT_SOFT && !ih->ih_need) 4921541Srgrimes continue; 4939238Sache atomic_store_rel_int(&ih->ih_need, 0); 4949238Sache CTR5(KTR_INTR, 4951541Srgrimes __func__ ": pid %d ih=%p: %p(%p) flg=%x", 49612221Sbde p->p_pid, (void *)ih, 4971541Srgrimes (void *)ih->ih_handler, ih->ih_argument, 4981549Srgrimes ih->ih_flags); 4998019Sache 5001541Srgrimes if ((ih->ih_flags & IH_MPSAFE) == 0) 5011541Srgrimes mtx_lock(&Giant); 5021541Srgrimes if ((ih->ih_flags & IH_DEAD) != 0) { 5031541Srgrimes mtx_lock_spin(&ithread_list_lock); 5041541Srgrimes TAILQ_REMOVE(&ithd->it_handlers, ih, 5059238Sache ih_next); 5068135Sache ithread_update(ithd); 5071541Srgrimes mtx_unlock_spin(&ithread_list_lock); 5089238Sache if (!mtx_owned(&Giant)) 5099238Sache mtx_lock(&Giant); 5109238Sache free(ih, M_ITHREAD); 5119238Sache mtx_unlock(&Giant); 5128135Sache goto restart; 5138135Sache } 5149238Sache ih->ih_handler(ih->ih_argument); 5159238Sache if ((ih->ih_flags & IH_MPSAFE) == 0) 5169238Sache mtx_unlock(&Giant); 5179238Sache } 5189238Sache } 5199238Sache 5209238Sache /* 5218111Sache * Processed all our interrupts. Now get the sched 5229238Sache * lock. This may take a while and it_need may get 5238135Sache * set again, so we have to check it again. 5241541Srgrimes */ 5251541Srgrimes mtx_assert(&Giant, MA_NOTOWNED); 5261541Srgrimes mtx_lock_spin(&sched_lock); 5271541Srgrimes if (!ithd->it_need) { 5281541Srgrimes /* 5291549Srgrimes * Should we call this earlier in the loop above? 5301541Srgrimes */ 5311541Srgrimes if (ithd->it_enable != NULL) 5321541Srgrimes ithd->it_enable(ithd->it_vector); 5331541Srgrimes p->p_stat = SWAIT; /* we're idle */ 5341541Srgrimes CTR1(KTR_INTR, __func__ ": pid %d: done", p->p_pid); 5351541Srgrimes mi_switch(); 5361541Srgrimes CTR1(KTR_INTR, __func__ ": pid %d: resumed", p->p_pid); 5371541Srgrimes } 5381541Srgrimes mtx_unlock_spin(&sched_lock); 5391541Srgrimes } 5401541Srgrimes} 5411541Srgrimes 5421541Srgrimes/* 5431541Srgrimes * Initialize mutex used to protect ithread handler lists. 5441541Srgrimes */ 5451541Srgrimesstatic void 5461541Srgrimesithread_init(void *dummy) 5471541Srgrimes{ 5481541Srgrimes 5491541Srgrimes mtx_init(&ithread_list_lock, "ithread list lock", MTX_SPIN); 5501549Srgrimes} 5511541SrgrimesSYSINIT(ithread_init, SI_SUB_INTR, SI_ORDER_FIRST, ithread_init, NULL); 5521541Srgrimes 5538011Sbde/* 5541541Srgrimes * Start standard software interrupt threads 5551541Srgrimes */ 5561541Srgrimesstatic void 5571541Srgrimesstart_softintr(void *dummy) 5581541Srgrimes{ 5591541Srgrimes 5601541Srgrimes if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, 0, &net_ih) || 5611541Srgrimes swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK, 5621541Srgrimes INTR_MPSAFE, &softclock_ih) || 5631541Srgrimes swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, 0, &vm_ih)) 5641541Srgrimes panic("died while creating standard software ithreads"); 5651541Srgrimes 5661541Srgrimes PROC_LOCK(clk_ithd->it_proc); 5671541Srgrimes clk_ithd->it_proc->p_flag |= P_NOLOAD; 5681541Srgrimes PROC_UNLOCK(clk_ithd->it_proc); 5691541Srgrimes} 5701541SrgrimesSYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL) 5711541Srgrimes 5721541Srgrimesvoid 5731541Srgrimeslegacy_setsoftnet(void) 5741541Srgrimes{ 5751541Srgrimes swi_sched(net_ih, SWI_NOSWITCH); 5761541Srgrimes} 5771541Srgrimes 5781541Srgrimes/* 5791541Srgrimes * XXX: This should really be in the network code somewhere and installed 5801541Srgrimes * via a SI_SUB_SOFINTR, SI_ORDER_MIDDLE sysinit. 5811549Srgrimes */ 5821541Srgrimesvoid (*netisrs[32]) __P((void)); 5831541Srgrimesu_int netisr; 5841541Srgrimes 5851541Srgrimesint 5861541Srgrimesregister_netisr(num, handler) 5871541Srgrimes int num; 5881541Srgrimes netisr_t *handler; 5891541Srgrimes{ 5901541Srgrimes 5911541Srgrimes if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) { 5921541Srgrimes printf("register_netisr: bad isr number: %d\n", num); 5931541Srgrimes return (EINVAL); 5941541Srgrimes } 5951541Srgrimes netisrs[num] = handler; 5961541Srgrimes return (0); 5971541Srgrimes} 5981541Srgrimes 5991541Srgrimesint 6001541Srgrimesunregister_netisr(num) 6011541Srgrimes int num; 6021541Srgrimes{ 6031541Srgrimes 6041541Srgrimes if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) { 6051541Srgrimes printf("unregister_netisr: bad isr number: %d\n", num); 6061541Srgrimes return (EINVAL); 6071541Srgrimes } 6081541Srgrimes netisrs[num] = NULL; 6091541Srgrimes return (0); 6101541Srgrimes} 6111541Srgrimes 6121541Srgrimesstatic void 6131541Srgrimesswi_net(void *dummy) 6141541Srgrimes{ 6151541Srgrimes u_int bits; 6161541Srgrimes int i; 6171541Srgrimes 6181541Srgrimes bits = atomic_readandclear_int(&netisr); 6191541Srgrimes while ((i = ffs(bits)) != 0) { 6201541Srgrimes i--; 6211541Srgrimes if (netisrs[i] != NULL) 6221541Srgrimes netisrs[i](); 6231541Srgrimes else 6241541Srgrimes printf("swi_net: unregistered isr number: %d.\n", i); 6251541Srgrimes bits &= ~(1 << i); 6261541Srgrimes } 6271541Srgrimes} 6281541Srgrimes