kern_intr.c revision 74914
126156Sse/* 226156Sse * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 326156Sse * All rights reserved. 426156Sse * 526156Sse * Redistribution and use in source and binary forms, with or without 626156Sse * modification, are permitted provided that the following conditions 726156Sse * are met: 826156Sse * 1. Redistributions of source code must retain the above copyright 926156Sse * notice unmodified, this list of conditions, and the following 1026156Sse * disclaimer. 1126156Sse * 2. Redistributions in binary form must reproduce the above copyright 1226156Sse * notice, this list of conditions and the following disclaimer in the 1326156Sse * documentation and/or other materials provided with the distribution. 1426156Sse * 1526156Sse * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 1626156Sse * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 1726156Sse * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 1826156Sse * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 1926156Sse * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 2026156Sse * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 2126156Sse * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 2226156Sse * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 2326156Sse * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 2426156Sse * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 2526156Sse * 2650477Speter * $FreeBSD: head/sys/kern/kern_intr.c 74914 2001-03-28 09:17:56Z jhb $ 2726156Sse * 2826156Sse */ 2926156Sse 3036887Sdfr 3141059Speter#include <sys/param.h> 3265822Sjhb#include <sys/bus.h> 3365822Sjhb#include <sys/rtprio.h> 3441059Speter#include <sys/systm.h> 3566698Sjhb#include <sys/ipl.h> 3666698Sjhb#include <sys/interrupt.h> 3766698Sjhb#include <sys/kernel.h> 3866698Sjhb#include <sys/kthread.h> 3966698Sjhb#include <sys/ktr.h> 4074914Sjhb#include <sys/lock.h> 4126156Sse#include <sys/malloc.h> 4267365Sjhb#include <sys/mutex.h> 4366698Sjhb#include <sys/proc.h> 4472759Sjhb#include <sys/random.h> 4572237Sjhb#include <sys/resourcevar.h> 4666698Sjhb#include <sys/unistd.h> 4766698Sjhb#include <sys/vmmeter.h> 4866698Sjhb#include <machine/atomic.h> 4966698Sjhb#include <machine/cpu.h> 5067551Sjhb#include <machine/md_var.h> 5172237Sjhb#include <machine/stdarg.h> 5226156Sse 5367551Sjhb#include <net/netisr.h> /* prototype for legacy_setsoftnet */ 5438244Sbde 5572759Sjhbstruct int_entropy { 5672759Sjhb struct proc *proc; 5772759Sjhb int vector; 5872759Sjhb}; 5972759Sjhb 6072237Sjhbvoid *net_ih; 6172237Sjhbvoid *vm_ih; 6272237Sjhbvoid *softclock_ih; 6372237Sjhbstruct ithd *clk_ithd; 6472237Sjhbstruct ithd *tty_ithd; 6538244Sbde 6672237Sjhbstatic struct mtx ithread_list_lock; 6766698Sjhb 6872237Sjhbstatic MALLOC_DEFINE(M_ITHREAD, "ithread", "Interrupt Threads"); 6972237Sjhb 7072237Sjhbstatic void ithread_update(struct ithd *); 7172237Sjhbstatic void ithread_loop(void *); 7272237Sjhbstatic void ithread_init(void *); 7372237Sjhbstatic void start_softintr(void *); 7472237Sjhbstatic void swi_net(void *); 7572237Sjhb 7672237Sjhbu_char 7772237Sjhbithread_priority(enum intr_type flags) 7865822Sjhb{ 7972237Sjhb u_char pri; 8065822Sjhb 8172237Sjhb flags &= (INTR_TYPE_TTY | INTR_TYPE_BIO | INTR_TYPE_NET | 8272237Sjhb INTR_TYPE_CAM | INTR_TYPE_MISC | INTR_TYPE_CLK); 8365822Sjhb switch (flags) { 8472237Sjhb case INTR_TYPE_TTY: 8565822Sjhb pri = PI_TTYLOW; 8665822Sjhb break; 8765822Sjhb case INTR_TYPE_BIO: 8865822Sjhb /* 8965822Sjhb * XXX We need to refine this. BSD/OS distinguishes 9065822Sjhb * between tape and disk priorities. 9165822Sjhb */ 9265822Sjhb pri = PI_DISK; 9365822Sjhb break; 9465822Sjhb case INTR_TYPE_NET: 9565822Sjhb pri = PI_NET; 9665822Sjhb break; 9765822Sjhb case INTR_TYPE_CAM: 9865822Sjhb pri = PI_DISK; /* XXX or PI_CAM? */ 9965822Sjhb break; 10072237Sjhb case INTR_TYPE_CLK: 10172237Sjhb pri = PI_REALTIME; 10272237Sjhb break; 10365822Sjhb case INTR_TYPE_MISC: 10465822Sjhb pri = PI_DULL; /* don't care */ 10565822Sjhb break; 10665822Sjhb default: 10772237Sjhb /* We didn't specify an interrupt level. */ 10865822Sjhb panic("ithread_priority: no interrupt type in flags"); 10965822Sjhb } 11065822Sjhb 11165822Sjhb return pri; 11265822Sjhb} 11365822Sjhb 11472237Sjhb/* 11572237Sjhb * Regenerate the name (p_comm) and priority for a threaded interrupt thread. 11672237Sjhb */ 11772237Sjhbstatic void 11872237Sjhbithread_update(struct ithd *ithd) 11972237Sjhb{ 12072237Sjhb struct intrhand *ih; 12172237Sjhb struct proc *p; 12272237Sjhb int entropy; 12367551Sjhb 12472237Sjhb p = ithd->it_proc; 12572237Sjhb if (p == NULL) 12672237Sjhb return; 12772237Sjhb 12872237Sjhb strncpy(p->p_comm, ithd->it_name, sizeof(ithd->it_name)); 12972237Sjhb ih = TAILQ_FIRST(&ithd->it_handlers); 13072237Sjhb if (ih == NULL) { 13172376Sjake p->p_pri.pri_level = PRI_MAX_ITHD; 13272237Sjhb ithd->it_flags &= ~IT_ENTROPY; 13372237Sjhb return; 13472237Sjhb } 13572237Sjhb 13672237Sjhb entropy = 0; 13772376Sjake p->p_pri.pri_level = ih->ih_pri; 13873205Sjake p->p_pri.pri_native = ih->ih_pri; 13972237Sjhb TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 14072237Sjhb if (strlen(p->p_comm) + strlen(ih->ih_name) + 1 < 14172237Sjhb sizeof(p->p_comm)) { 14272237Sjhb strcat(p->p_comm, " "); 14372237Sjhb strcat(p->p_comm, ih->ih_name); 14472237Sjhb } else if (strlen(p->p_comm) + 1 == sizeof(p->p_comm)) { 14572237Sjhb if (p->p_comm[sizeof(p->p_comm) - 2] == '+') 14672237Sjhb p->p_comm[sizeof(p->p_comm) - 2] = '*'; 14772237Sjhb else 14872237Sjhb p->p_comm[sizeof(p->p_comm) - 2] = '+'; 14972237Sjhb } else 15072237Sjhb strcat(p->p_comm, "+"); 15172237Sjhb if (ih->ih_flags & IH_ENTROPY) 15272237Sjhb entropy++; 15372237Sjhb } 15472237Sjhb 15572759Sjhb if (entropy) 15672237Sjhb ithd->it_flags |= IT_ENTROPY; 15772237Sjhb else 15872237Sjhb ithd->it_flags &= ~IT_ENTROPY; 15972837Sjhb 16072837Sjhb CTR1(KTR_INTR, __func__ ": updated %s\n", p->p_comm); 16172237Sjhb} 16272237Sjhb 16372237Sjhbint 16472237Sjhbithread_create(struct ithd **ithread, int vector, int flags, 16572237Sjhb void (*disable)(int), void (*enable)(int), const char *fmt, ...) 16666698Sjhb{ 16772237Sjhb struct ithd *ithd; 16867551Sjhb struct proc *p; 16972237Sjhb int error; 17072237Sjhb va_list ap; 17172237Sjhb 17272759Sjhb /* The only valid flag during creation is IT_SOFT. */ 17372759Sjhb if ((flags & ~IT_SOFT) != 0) 17472759Sjhb return (EINVAL); 17572759Sjhb 17672237Sjhb ithd = malloc(sizeof(struct ithd), M_ITHREAD, M_WAITOK | M_ZERO); 17772237Sjhb ithd->it_vector = vector; 17872237Sjhb ithd->it_disable = disable; 17972237Sjhb ithd->it_enable = enable; 18072237Sjhb ithd->it_flags = flags; 18172237Sjhb TAILQ_INIT(&ithd->it_handlers); 18272237Sjhb 18372237Sjhb va_start(ap, fmt); 18472237Sjhb vsnprintf(ithd->it_name, sizeof(ithd->it_name), fmt, ap); 18572237Sjhb va_end(ap); 18672237Sjhb 18772237Sjhb error = kthread_create(ithread_loop, ithd, &p, RFSTOPPED | RFHIGHPID, 18874734Sjhb "%s", ithd->it_name); 18972237Sjhb if (error) { 19072237Sjhb free(ithd, M_ITHREAD); 19172237Sjhb return (error); 19272237Sjhb } 19372376Sjake p->p_pri.pri_class = PRI_ITHD; 19472376Sjake p->p_pri.pri_level = PRI_MAX_ITHD; 19572237Sjhb p->p_stat = SWAIT; 19672237Sjhb ithd->it_proc = p; 19772237Sjhb p->p_ithd = ithd; 19872237Sjhb if (ithread != NULL) 19972237Sjhb *ithread = ithd; 20072237Sjhb 20172837Sjhb CTR1(KTR_INTR, __func__ ": created %s", ithd->it_name); 20272237Sjhb return (0); 20372237Sjhb} 20472237Sjhb 20572237Sjhbint 20672237Sjhbithread_destroy(struct ithd *ithread) 20772237Sjhb{ 20872237Sjhb 20972237Sjhb if (ithread == NULL || !TAILQ_EMPTY(&ithread->it_handlers)) 21072237Sjhb return (EINVAL); 21172237Sjhb 21272237Sjhb mtx_lock_spin(&sched_lock); 21372237Sjhb ithread->it_flags |= IT_DEAD; 21472237Sjhb if (ithread->it_proc->p_stat == SWAIT) { 21572237Sjhb ithread->it_proc->p_stat = SRUN; 21672237Sjhb setrunqueue(ithread->it_proc); 21772237Sjhb } 21872237Sjhb mtx_unlock_spin(&sched_lock); 21972837Sjhb CTR1(KTR_INTR, __func__ ": killing %s", ithread->it_name); 22072237Sjhb return (0); 22172237Sjhb} 22272237Sjhb 22372237Sjhbint 22472237Sjhbithread_add_handler(struct ithd* ithread, const char *name, 22572237Sjhb driver_intr_t handler, void *arg, u_char pri, enum intr_type flags, 22672237Sjhb void **cookiep) 22772237Sjhb{ 22872237Sjhb struct intrhand *ih, *temp_ih; 22972237Sjhb 23072237Sjhb if (ithread == NULL || name == NULL || handler == NULL) 23172237Sjhb return (EINVAL); 23272237Sjhb if ((flags & INTR_FAST) !=0) 23372237Sjhb flags |= INTR_EXCL; 23472237Sjhb 23572237Sjhb ih = malloc(sizeof(struct intrhand), M_ITHREAD, M_WAITOK | M_ZERO); 23672237Sjhb ih->ih_handler = handler; 23772237Sjhb ih->ih_argument = arg; 23872237Sjhb ih->ih_name = name; 23972237Sjhb ih->ih_ithread = ithread; 24072237Sjhb ih->ih_pri = pri; 24172237Sjhb if (flags & INTR_FAST) 24272237Sjhb ih->ih_flags = IH_FAST | IH_EXCLUSIVE; 24372237Sjhb else if (flags & INTR_EXCL) 24472237Sjhb ih->ih_flags = IH_EXCLUSIVE; 24572237Sjhb if (flags & INTR_MPSAFE) 24672237Sjhb ih->ih_flags |= IH_MPSAFE; 24772237Sjhb if (flags & INTR_ENTROPY) 24872237Sjhb ih->ih_flags |= IH_ENTROPY; 24972237Sjhb 25072237Sjhb mtx_lock_spin(&ithread_list_lock); 25172237Sjhb if ((flags & INTR_EXCL) !=0 && !TAILQ_EMPTY(&ithread->it_handlers)) 25272237Sjhb goto fail; 25372237Sjhb if (!TAILQ_EMPTY(&ithread->it_handlers) && 25472237Sjhb (TAILQ_FIRST(&ithread->it_handlers)->ih_flags & IH_EXCLUSIVE) != 0) 25572237Sjhb goto fail; 25672237Sjhb 25772237Sjhb TAILQ_FOREACH(temp_ih, &ithread->it_handlers, ih_next) 25872237Sjhb if (temp_ih->ih_pri > ih->ih_pri) 25972237Sjhb break; 26072237Sjhb if (temp_ih == NULL) 26172237Sjhb TAILQ_INSERT_TAIL(&ithread->it_handlers, ih, ih_next); 26272237Sjhb else 26372237Sjhb TAILQ_INSERT_BEFORE(temp_ih, ih, ih_next); 26472237Sjhb ithread_update(ithread); 26572237Sjhb mtx_unlock_spin(&ithread_list_lock); 26672237Sjhb 26772237Sjhb if (cookiep != NULL) 26872237Sjhb *cookiep = ih; 26972837Sjhb CTR2(KTR_INTR, __func__ ": added %s to %s", ih->ih_name, 27072837Sjhb ithread->it_name); 27172237Sjhb return (0); 27272237Sjhb 27372237Sjhbfail: 27472237Sjhb mtx_unlock_spin(&ithread_list_lock); 27572237Sjhb free(ih, M_ITHREAD); 27672237Sjhb return (EINVAL); 27772237Sjhb} 27872237Sjhb 27972237Sjhbint 28072237Sjhbithread_remove_handler(void *cookie) 28172237Sjhb{ 28272237Sjhb struct intrhand *handler = (struct intrhand *)cookie; 28372237Sjhb struct ithd *ithread; 28472237Sjhb#ifdef INVARIANTS 28572237Sjhb struct intrhand *ih; 28672237Sjhb#endif 28772237Sjhb 28872759Sjhb if (handler == NULL) 28972237Sjhb return (EINVAL); 29072827Sjhb ithread = handler->ih_ithread; 29172827Sjhb KASSERT(ithread != NULL, 29272759Sjhb ("interrupt handler \"%s\" has a NULL interrupt thread", 29372759Sjhb handler->ih_name)); 29472837Sjhb CTR2(KTR_INTR, __func__ ": removing %s from %s", handler->ih_name, 29572837Sjhb ithread->it_name); 29672237Sjhb mtx_lock_spin(&ithread_list_lock); 29772237Sjhb#ifdef INVARIANTS 29872237Sjhb TAILQ_FOREACH(ih, &ithread->it_handlers, ih_next) 29972759Sjhb if (ih == handler) 30072759Sjhb goto ok; 30172759Sjhb mtx_unlock_spin(&ithread_list_lock); 30272759Sjhb panic("interrupt handler \"%s\" not found in interrupt thread \"%s\"", 30372759Sjhb ih->ih_name, ithread->it_name); 30472759Sjhbok: 30572237Sjhb#endif 30672839Sjhb /* 30772839Sjhb * If the interrupt thread is already running, then just mark this 30872839Sjhb * handler as being dead and let the ithread do the actual removal. 30972839Sjhb */ 31072839Sjhb mtx_lock_spin(&sched_lock); 31172839Sjhb if (ithread->it_proc->p_stat != SWAIT) { 31272839Sjhb handler->ih_flags |= IH_DEAD; 31372839Sjhb 31472839Sjhb /* 31572839Sjhb * Ensure that the thread will process the handler list 31672839Sjhb * again and remove this handler if it has already passed 31772839Sjhb * it on the list. 31872839Sjhb */ 31972839Sjhb ithread->it_need = 1; 32072839Sjhb } else { 32172839Sjhb TAILQ_REMOVE(&ithread->it_handlers, handler, ih_next); 32272839Sjhb ithread_update(ithread); 32372839Sjhb } 32472839Sjhb mtx_unlock_spin(&sched_lock); 32572237Sjhb mtx_unlock_spin(&ithread_list_lock); 32672237Sjhb 32772839Sjhb if ((handler->ih_flags & IH_DEAD) == 0) 32872839Sjhb free(handler, M_ITHREAD); 32972237Sjhb return (0); 33072237Sjhb} 33172237Sjhb 33272237Sjhbint 33372759Sjhbithread_schedule(struct ithd *ithread, int do_switch) 33472759Sjhb{ 33572759Sjhb struct int_entropy entropy; 33672759Sjhb struct proc *p; 33774902Sjhb critical_t savecrit; 33872759Sjhb 33972759Sjhb /* 34072759Sjhb * If no ithread or no handlers, then we have a stray interrupt. 34172759Sjhb */ 34272759Sjhb if ((ithread == NULL) || TAILQ_EMPTY(&ithread->it_handlers)) 34372759Sjhb return (EINVAL); 34472759Sjhb 34572759Sjhb /* 34672759Sjhb * If any of the handlers for this ithread claim to be good 34772759Sjhb * sources of entropy, then gather some. 34872759Sjhb */ 34972759Sjhb if (harvest.interrupt && ithread->it_flags & IT_ENTROPY) { 35072759Sjhb entropy.vector = ithread->it_vector; 35172759Sjhb entropy.proc = CURPROC; 35272759Sjhb random_harvest(&entropy, sizeof(entropy), 2, 0, 35372759Sjhb RANDOM_INTERRUPT); 35472759Sjhb } 35572759Sjhb 35672759Sjhb p = ithread->it_proc; 35773313Sjhb KASSERT(p != NULL, ("ithread %s has no process", ithread->it_name)); 35872759Sjhb CTR3(KTR_INTR, __func__ ": pid %d: (%s) need = %d", p->p_pid, p->p_comm, 35972759Sjhb ithread->it_need); 36072759Sjhb 36172759Sjhb /* 36272759Sjhb * Set it_need to tell the thread to keep running if it is already 36372759Sjhb * running. Then, grab sched_lock and see if we actually need to 36472759Sjhb * put this thread on the runqueue. If so and the do_switch flag is 36572759Sjhb * true, then switch to the ithread immediately. Otherwise, use 36672759Sjhb * need_resched() to guarantee that this ithread will run before any 36772759Sjhb * userland processes. 36872759Sjhb */ 36972759Sjhb ithread->it_need = 1; 37072759Sjhb mtx_lock_spin(&sched_lock); 37172759Sjhb if (p->p_stat == SWAIT) { 37272759Sjhb CTR1(KTR_INTR, __func__ ": setrunqueue %d", p->p_pid); 37372759Sjhb p->p_stat = SRUN; 37472759Sjhb setrunqueue(p); 37573313Sjhb if (do_switch && curproc->p_stat == SRUN) { 37674902Sjhb savecrit = sched_lock.mtx_savecrit; 37772759Sjhb mtx_intr_enable(&sched_lock); 37872759Sjhb if (curproc != PCPU_GET(idleproc)) 37972759Sjhb setrunqueue(curproc); 38072759Sjhb curproc->p_stats->p_ru.ru_nvcsw++; 38172759Sjhb mi_switch(); 38274902Sjhb sched_lock.mtx_savecrit = savecrit; 38372759Sjhb } else 38472759Sjhb need_resched(); 38572759Sjhb } else { 38672759Sjhb CTR3(KTR_INTR, __func__ ": pid %d: it_need %d, state %d", 38772759Sjhb p->p_pid, ithread->it_need, p->p_stat); 38872759Sjhb } 38972759Sjhb mtx_unlock_spin(&sched_lock); 39072759Sjhb 39172759Sjhb return (0); 39272759Sjhb} 39372759Sjhb 39472759Sjhbint 39572237Sjhbswi_add(struct ithd **ithdp, const char *name, driver_intr_t handler, 39672237Sjhb void *arg, int pri, enum intr_type flags, void **cookiep) 39772237Sjhb{ 39867551Sjhb struct ithd *ithd; 39972237Sjhb int error; 40066698Sjhb 40172759Sjhb if (flags & (INTR_FAST | INTR_ENTROPY)) 40272759Sjhb return (EINVAL); 40372759Sjhb 40467551Sjhb ithd = (ithdp != NULL) ? *ithdp : NULL; 40566698Sjhb 40672759Sjhb if (ithd != NULL) { 40772759Sjhb if ((ithd->it_flags & IT_SOFT) == 0) 40872759Sjhb return(EINVAL); 40972759Sjhb } else { 41072237Sjhb error = ithread_create(&ithd, pri, IT_SOFT, NULL, NULL, 41172237Sjhb "swi%d:", pri); 41267551Sjhb if (error) 41372237Sjhb return (error); 41472237Sjhb 41567551Sjhb if (ithdp != NULL) 41667551Sjhb *ithdp = ithd; 41766698Sjhb } 41872376Sjake return (ithread_add_handler(ithd, name, handler, arg, 41972376Sjake (pri * RQ_PPQ) + PI_SOFT, flags, cookiep)); 42066698Sjhb} 42166698Sjhb 42266698Sjhb 42366698Sjhb/* 42467551Sjhb * Schedule a heavyweight software interrupt process. 42566698Sjhb */ 42667551Sjhbvoid 42772237Sjhbswi_sched(void *cookie, int flags) 42866698Sjhb{ 42972237Sjhb struct intrhand *ih = (struct intrhand *)cookie; 43072237Sjhb struct ithd *it = ih->ih_ithread; 43172759Sjhb int error; 43266698Sjhb 43367551Sjhb atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */ 43467551Sjhb 43572237Sjhb CTR3(KTR_INTR, "swi_sched pid %d(%s) need=%d", 43672838Sjhb it->it_proc->p_pid, it->it_proc->p_comm, it->it_need); 43767551Sjhb 43867551Sjhb /* 43972759Sjhb * Set ih_need for this handler so that if the ithread is already 44072759Sjhb * running it will execute this handler on the next pass. Otherwise, 44172759Sjhb * it will execute it the next time it runs. 44267551Sjhb */ 44372237Sjhb atomic_store_rel_int(&ih->ih_need, 1); 44472237Sjhb if (!(flags & SWI_DELAY)) { 44572759Sjhb error = ithread_schedule(it, !cold && flags & SWI_SWITCH); 44672759Sjhb KASSERT(error == 0, ("stray software interrupt")); 44766698Sjhb } 44866698Sjhb} 44966698Sjhb 45066698Sjhb/* 45172237Sjhb * This is the main code for interrupt threads. 45266698Sjhb */ 45367551Sjhbvoid 45472237Sjhbithread_loop(void *arg) 45566698Sjhb{ 45672237Sjhb struct ithd *ithd; /* our thread context */ 45767551Sjhb struct intrhand *ih; /* and our interrupt handler chain */ 45872237Sjhb struct proc *p; 45967551Sjhb 46072237Sjhb p = curproc; 46172237Sjhb ithd = (struct ithd *)arg; /* point to myself */ 46272237Sjhb KASSERT(ithd->it_proc == p && p->p_ithd == ithd, 46372237Sjhb (__func__ ": ithread and proc linkage out of sync")); 46466698Sjhb 46567551Sjhb /* 46667551Sjhb * As long as we have interrupts outstanding, go through the 46767551Sjhb * list of handlers, giving each one a go at it. 46867551Sjhb */ 46966698Sjhb for (;;) { 47072237Sjhb /* 47172237Sjhb * If we are an orphaned thread, then just die. 47272237Sjhb */ 47372237Sjhb if (ithd->it_flags & IT_DEAD) { 47472237Sjhb CTR2(KTR_INTR, __func__ ": pid %d: (%s) exiting", 47572237Sjhb p->p_pid, p->p_comm); 47672237Sjhb p->p_ithd = NULL; 47772237Sjhb mtx_lock(&Giant); 47872237Sjhb free(ithd, M_ITHREAD); 47972237Sjhb kthread_exit(0); 48072237Sjhb } 48172237Sjhb 48272237Sjhb CTR3(KTR_INTR, __func__ ": pid %d: (%s) need=%d", 48372237Sjhb p->p_pid, p->p_comm, ithd->it_need); 48472237Sjhb while (ithd->it_need) { 48567551Sjhb /* 48667551Sjhb * Service interrupts. If another interrupt 48767551Sjhb * arrives while we are running, they will set 48867551Sjhb * it_need to denote that we should make 48967551Sjhb * another pass. 49067551Sjhb */ 49172237Sjhb atomic_store_rel_int(&ithd->it_need, 0); 49272839Sjhbrestart: 49372237Sjhb TAILQ_FOREACH(ih, &ithd->it_handlers, ih_next) { 49472237Sjhb if (ithd->it_flags & IT_SOFT && !ih->ih_need) 49567551Sjhb continue; 49672237Sjhb atomic_store_rel_int(&ih->ih_need, 0); 49767551Sjhb CTR5(KTR_INTR, 49872237Sjhb __func__ ": pid %d ih=%p: %p(%p) flg=%x", 49967551Sjhb p->p_pid, (void *)ih, 50067551Sjhb (void *)ih->ih_handler, ih->ih_argument, 50167551Sjhb ih->ih_flags); 50266698Sjhb 50372237Sjhb if ((ih->ih_flags & IH_MPSAFE) == 0) 50472200Sbmilekic mtx_lock(&Giant); 50572839Sjhb if ((ih->ih_flags & IH_DEAD) != 0) { 50672839Sjhb mtx_lock_spin(&ithread_list_lock); 50772839Sjhb TAILQ_REMOVE(&ithd->it_handlers, ih, 50872839Sjhb ih_next); 50972839Sjhb ithread_update(ithd); 51072839Sjhb mtx_unlock_spin(&ithread_list_lock); 51172839Sjhb if (!mtx_owned(&Giant)) 51272839Sjhb mtx_lock(&Giant); 51372839Sjhb free(ih, M_ITHREAD); 51472839Sjhb mtx_unlock(&Giant); 51572839Sjhb goto restart; 51672839Sjhb } 51767551Sjhb ih->ih_handler(ih->ih_argument); 51872237Sjhb if ((ih->ih_flags & IH_MPSAFE) == 0) 51972200Sbmilekic mtx_unlock(&Giant); 52067551Sjhb } 52166698Sjhb } 52267551Sjhb 52366698Sjhb /* 52466698Sjhb * Processed all our interrupts. Now get the sched 52567551Sjhb * lock. This may take a while and it_need may get 52666698Sjhb * set again, so we have to check it again. 52766698Sjhb */ 52868789Sjhb mtx_assert(&Giant, MA_NOTOWNED); 52972200Sbmilekic mtx_lock_spin(&sched_lock); 53072237Sjhb if (!ithd->it_need) { 53172237Sjhb /* 53272237Sjhb * Should we call this earlier in the loop above? 53372237Sjhb */ 53472237Sjhb if (ithd->it_enable != NULL) 53572237Sjhb ithd->it_enable(ithd->it_vector); 53667551Sjhb p->p_stat = SWAIT; /* we're idle */ 53772237Sjhb CTR1(KTR_INTR, __func__ ": pid %d: done", p->p_pid); 53866698Sjhb mi_switch(); 53972237Sjhb CTR1(KTR_INTR, __func__ ": pid %d: resumed", p->p_pid); 54066698Sjhb } 54172200Sbmilekic mtx_unlock_spin(&sched_lock); 54266698Sjhb } 54366698Sjhb} 54466698Sjhb 54572237Sjhb/* 54672237Sjhb * Initialize mutex used to protect ithread handler lists. 54772237Sjhb */ 54872237Sjhbstatic void 54972237Sjhbithread_init(void *dummy) 55072237Sjhb{ 55167551Sjhb 55272237Sjhb mtx_init(&ithread_list_lock, "ithread list lock", MTX_SPIN); 55372237Sjhb} 55472237SjhbSYSINIT(ithread_init, SI_SUB_INTR, SI_ORDER_FIRST, ithread_init, NULL); 55572237Sjhb 55666698Sjhb/* 55767551Sjhb * Start standard software interrupt threads 55866698Sjhb */ 55967551Sjhbstatic void 56072237Sjhbstart_softintr(void *dummy) 56167551Sjhb{ 56272237Sjhb 56372237Sjhb if (swi_add(NULL, "net", swi_net, NULL, SWI_NET, 0, &net_ih) || 56472237Sjhb swi_add(&clk_ithd, "clock", softclock, NULL, SWI_CLOCK, 56572237Sjhb INTR_MPSAFE, &softclock_ih) || 56672237Sjhb swi_add(NULL, "vm", swi_vm, NULL, SWI_VM, 0, &vm_ih)) 56772237Sjhb panic("died while creating standard software ithreads"); 56872759Sjhb 56972759Sjhb PROC_LOCK(clk_ithd->it_proc); 57072759Sjhb clk_ithd->it_proc->p_flag |= P_NOLOAD; 57172759Sjhb PROC_UNLOCK(clk_ithd->it_proc); 57266698Sjhb} 57372237SjhbSYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL) 57466698Sjhb 57567551Sjhbvoid 57672237Sjhblegacy_setsoftnet(void) 57767551Sjhb{ 57872237Sjhb swi_sched(net_ih, SWI_NOSWITCH); 57966698Sjhb} 58066698Sjhb 58167551Sjhb/* 58267551Sjhb * XXX: This should really be in the network code somewhere and installed 58367551Sjhb * via a SI_SUB_SOFINTR, SI_ORDER_MIDDLE sysinit. 58467551Sjhb */ 58567551Sjhbvoid (*netisrs[32]) __P((void)); 58667551Sjhbu_int netisr; 58766698Sjhb 58869586Sjakeint 58969586Sjakeregister_netisr(num, handler) 59069586Sjake int num; 59169586Sjake netisr_t *handler; 59269586Sjake{ 59369586Sjake 59469586Sjake if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) { 59569586Sjake printf("register_netisr: bad isr number: %d\n", num); 59669586Sjake return (EINVAL); 59769586Sjake } 59869586Sjake netisrs[num] = handler; 59969586Sjake return (0); 60069586Sjake} 60169586Sjake 60269586Sjakeint 60369586Sjakeunregister_netisr(num) 60469586Sjake int num; 60569586Sjake{ 60669586Sjake 60769586Sjake if (num < 0 || num >= (sizeof(netisrs)/sizeof(*netisrs)) ) { 60869586Sjake printf("unregister_netisr: bad isr number: %d\n", num); 60969586Sjake return (EINVAL); 61069586Sjake } 61169586Sjake netisrs[num] = NULL; 61269586Sjake return (0); 61369586Sjake} 61469586Sjake 61567551Sjhbstatic void 61667551Sjhbswi_net(void *dummy) 61766698Sjhb{ 61867551Sjhb u_int bits; 61967551Sjhb int i; 62066698Sjhb 62167551Sjhb bits = atomic_readandclear_int(&netisr); 62267551Sjhb while ((i = ffs(bits)) != 0) { 62367551Sjhb i--; 62470531Stanimura if (netisrs[i] != NULL) 62570531Stanimura netisrs[i](); 62670531Stanimura else 62770531Stanimura printf("swi_net: unregistered isr number: %d.\n", i); 62867551Sjhb bits &= ~(1 << i); 62966698Sjhb } 63066698Sjhb} 631