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> 431931cf94SJohn Baldwin #include <sys/unistd.h> 441931cf94SJohn Baldwin #include <sys/vmmeter.h> 451931cf94SJohn Baldwin #include <machine/atomic.h> 461931cf94SJohn Baldwin #include <machine/cpu.h> 478088699fSJohn Baldwin #include <machine/md_var.h> 48425f9fdaSStefan Eßer 498088699fSJohn Baldwin #include <net/netisr.h> /* prototype for legacy_setsoftnet */ 5018c5a6c4SBruce Evans 518088699fSJohn Baldwin struct intrhand *net_ih; 528088699fSJohn Baldwin struct intrhand *vm_ih; 538088699fSJohn Baldwin struct intrhand *softclock_ih; 548088699fSJohn Baldwin struct ithd *clk_ithd; 558088699fSJohn Baldwin struct ithd *tty_ithd; 561931cf94SJohn Baldwin 571931cf94SJohn Baldwin static void start_softintr(void *); 588088699fSJohn Baldwin static void swi_net(void *); 5918c5a6c4SBruce Evans 609a94c9c5SJohn Baldwin int 619a94c9c5SJohn Baldwin ithread_priority(flags) 629a94c9c5SJohn Baldwin int flags; 639a94c9c5SJohn Baldwin { 649a94c9c5SJohn Baldwin int pri; 659a94c9c5SJohn Baldwin 669a94c9c5SJohn Baldwin switch (flags) { 679a94c9c5SJohn Baldwin case INTR_TYPE_TTY: /* keyboard or parallel port */ 689a94c9c5SJohn Baldwin pri = PI_TTYLOW; 699a94c9c5SJohn Baldwin break; 709a94c9c5SJohn Baldwin case (INTR_TYPE_TTY | INTR_FAST): /* sio */ 719a94c9c5SJohn Baldwin pri = PI_TTYHIGH; 729a94c9c5SJohn Baldwin break; 739a94c9c5SJohn Baldwin case INTR_TYPE_BIO: 749a94c9c5SJohn Baldwin /* 759a94c9c5SJohn Baldwin * XXX We need to refine this. BSD/OS distinguishes 769a94c9c5SJohn Baldwin * between tape and disk priorities. 779a94c9c5SJohn Baldwin */ 789a94c9c5SJohn Baldwin pri = PI_DISK; 799a94c9c5SJohn Baldwin break; 809a94c9c5SJohn Baldwin case INTR_TYPE_NET: 819a94c9c5SJohn Baldwin pri = PI_NET; 829a94c9c5SJohn Baldwin break; 839a94c9c5SJohn Baldwin case INTR_TYPE_CAM: 849a94c9c5SJohn Baldwin pri = PI_DISK; /* XXX or PI_CAM? */ 859a94c9c5SJohn Baldwin break; 869a94c9c5SJohn Baldwin case INTR_TYPE_MISC: 879a94c9c5SJohn Baldwin pri = PI_DULL; /* don't care */ 889a94c9c5SJohn Baldwin break; 899a94c9c5SJohn Baldwin /* We didn't specify an interrupt level. */ 909a94c9c5SJohn Baldwin default: 919a94c9c5SJohn Baldwin panic("ithread_priority: no interrupt type in flags"); 929a94c9c5SJohn Baldwin } 939a94c9c5SJohn Baldwin 949a94c9c5SJohn Baldwin return pri; 959a94c9c5SJohn Baldwin } 969a94c9c5SJohn Baldwin 978088699fSJohn Baldwin void sithd_loop(void *); 988088699fSJohn Baldwin 998088699fSJohn Baldwin struct intrhand * 1008088699fSJohn Baldwin sinthand_add(const char *name, struct ithd **ithdp, driver_intr_t handler, 1018088699fSJohn Baldwin void *arg, int pri, int flags) 1028088699fSJohn Baldwin { 1038088699fSJohn Baldwin struct proc *p; 1048088699fSJohn Baldwin struct ithd *ithd; 1058088699fSJohn Baldwin struct intrhand *ih; 1068088699fSJohn Baldwin struct intrhand *this_ih; 1078088699fSJohn Baldwin 1088088699fSJohn Baldwin ithd = (ithdp != NULL) ? *ithdp : NULL; 1098088699fSJohn Baldwin 1108088699fSJohn Baldwin 1118088699fSJohn Baldwin if (ithd == NULL) { 1128088699fSJohn Baldwin int error; 1138088699fSJohn Baldwin ithd = malloc(sizeof (struct ithd), M_DEVBUF, M_WAITOK | M_ZERO); 1148088699fSJohn Baldwin error = kthread_create(sithd_loop, NULL, &p, 1158088699fSJohn Baldwin RFSTOPPED | RFHIGHPID, "swi%d: %s", pri, name); 1168088699fSJohn Baldwin if (error) 1178088699fSJohn Baldwin panic("inthand_add: Can't create interrupt thread"); 1188088699fSJohn Baldwin ithd->it_proc = p; 1198088699fSJohn Baldwin p->p_ithd = ithd; 1208088699fSJohn Baldwin p->p_rtprio.type = RTP_PRIO_ITHREAD; 1218088699fSJohn Baldwin p->p_rtprio.prio = pri + PI_SOFT; /* soft interrupt */ 1228088699fSJohn Baldwin p->p_stat = SWAIT; /* we're idle */ 1238088699fSJohn Baldwin /* XXX - some hacks are _really_ gross */ 1248088699fSJohn Baldwin if (pri == SWI_CLOCK) 1258088699fSJohn Baldwin p->p_flag |= P_NOLOAD; 1268088699fSJohn Baldwin if (ithdp != NULL) 1278088699fSJohn Baldwin *ithdp = ithd; 1288088699fSJohn Baldwin } 1298088699fSJohn Baldwin this_ih = malloc(sizeof (struct intrhand), M_DEVBUF, M_WAITOK | M_ZERO); 1308088699fSJohn Baldwin this_ih->ih_handler = handler; 1318088699fSJohn Baldwin this_ih->ih_argument = arg; 1328088699fSJohn Baldwin this_ih->ih_flags = flags; 1338088699fSJohn Baldwin this_ih->ih_ithd = ithd; 1348088699fSJohn Baldwin this_ih->ih_name = malloc(strlen(name) + 1, M_DEVBUF, M_WAITOK); 1358088699fSJohn Baldwin if ((ih = ithd->it_ih)) { 1368088699fSJohn Baldwin while (ih->ih_next != NULL) 1378088699fSJohn Baldwin ih = ih->ih_next; 1388088699fSJohn Baldwin ih->ih_next = this_ih; 1398088699fSJohn Baldwin } else 1408088699fSJohn Baldwin ithd->it_ih = this_ih; 1418088699fSJohn Baldwin strcpy(this_ih->ih_name, name); 1428088699fSJohn Baldwin return (this_ih); 1438088699fSJohn Baldwin } 1448088699fSJohn Baldwin 1458088699fSJohn Baldwin 1461931cf94SJohn Baldwin /* 1478088699fSJohn Baldwin * Schedule a heavyweight software interrupt process. 1481931cf94SJohn Baldwin */ 1491931cf94SJohn Baldwin void 1508088699fSJohn Baldwin sched_swi(struct intrhand *ih, int flag) 1511931cf94SJohn Baldwin { 1528088699fSJohn Baldwin struct ithd *it = ih->ih_ithd; /* and the process that does it */ 1538088699fSJohn Baldwin struct proc *p = it->it_proc; 1548088699fSJohn Baldwin 1551931cf94SJohn Baldwin atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */ 1561931cf94SJohn Baldwin 1578088699fSJohn Baldwin CTR3(KTR_INTR, "sched_sihand pid %d(%s) need=%d", 1588088699fSJohn Baldwin p->p_pid, p->p_comm, it->it_need); 1591931cf94SJohn Baldwin 1601931cf94SJohn Baldwin /* 1618088699fSJohn Baldwin * Set it_need so that if the thread is already running but close 1628088699fSJohn Baldwin * to done, it will do another go-round. Then get the sched lock 1638088699fSJohn Baldwin * and see if the thread is on whichkqs yet. If not, put it on 1648088699fSJohn Baldwin * there. In any case, kick everyone so that if the new thread 1658088699fSJohn Baldwin * is higher priority than their current thread, it gets run now. 1661931cf94SJohn Baldwin */ 1678088699fSJohn Baldwin ih->ih_need = 1; 1688088699fSJohn Baldwin if (!(flag & SWI_DELAY)) { 1698088699fSJohn Baldwin it->it_need = 1; 1701931cf94SJohn Baldwin mtx_enter(&sched_lock, MTX_SPIN); 1718088699fSJohn Baldwin if (p->p_stat == SWAIT) { /* not on run queue */ 1728088699fSJohn Baldwin CTR1(KTR_INTR, "sched_ithd: setrunqueue %d", p->p_pid); 1731931cf94SJohn Baldwin /* membar_lock(); */ 1748088699fSJohn Baldwin p->p_stat = SRUN; 1758088699fSJohn Baldwin setrunqueue(p); 1761931cf94SJohn Baldwin aston(); 1771931cf94SJohn Baldwin } 1788088699fSJohn Baldwin else { 1798088699fSJohn Baldwin CTR3(KTR_INTR, "sched_ithd %d: it_need %d, state %d", 1808088699fSJohn Baldwin p->p_pid, it->it_need, p->p_stat ); 1818088699fSJohn Baldwin } 1821931cf94SJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 1831931cf94SJohn Baldwin need_resched(); 1848088699fSJohn Baldwin } 1858088699fSJohn Baldwin } 1868088699fSJohn Baldwin 1878088699fSJohn Baldwin /* 1888088699fSJohn Baldwin * This is the main code for soft interrupt threads. 1898088699fSJohn Baldwin */ 1908088699fSJohn Baldwin void 1918088699fSJohn Baldwin sithd_loop(void *dummy) 1928088699fSJohn Baldwin { 1938088699fSJohn Baldwin struct ithd *it; /* our thread context */ 1948088699fSJohn Baldwin struct intrhand *ih; /* and our interrupt handler chain */ 1958088699fSJohn Baldwin 1968088699fSJohn Baldwin struct proc *p = curproc; 1978088699fSJohn Baldwin it = p->p_ithd; /* point to myself */ 1988088699fSJohn Baldwin 1998088699fSJohn Baldwin /* 2008088699fSJohn Baldwin * As long as we have interrupts outstanding, go through the 2018088699fSJohn Baldwin * list of handlers, giving each one a go at it. 2028088699fSJohn Baldwin */ 2038088699fSJohn Baldwin for (;;) { 2048088699fSJohn Baldwin CTR3(KTR_INTR, "sithd_loop pid %d(%s) need=%d", 2058088699fSJohn Baldwin p->p_pid, p->p_comm, it->it_need); 2068088699fSJohn Baldwin while (it->it_need) { 2078088699fSJohn Baldwin /* 2088088699fSJohn Baldwin * Service interrupts. If another interrupt 2098088699fSJohn Baldwin * arrives while we are running, they will set 2108088699fSJohn Baldwin * it_need to denote that we should make 2118088699fSJohn Baldwin * another pass. 2128088699fSJohn Baldwin */ 2138088699fSJohn Baldwin it->it_need = 0; 2148088699fSJohn Baldwin for (ih = it->it_ih; ih != NULL; ih = ih->ih_next) { 2158088699fSJohn Baldwin if (!ih->ih_need) 2168088699fSJohn Baldwin continue; 2178088699fSJohn Baldwin ih->ih_need = 0; 2188088699fSJohn Baldwin CTR5(KTR_INTR, 2198088699fSJohn Baldwin "ithd_loop pid %d ih=%p: %p(%p) flg=%x", 2208088699fSJohn Baldwin p->p_pid, (void *)ih, 2218088699fSJohn Baldwin (void *)ih->ih_handler, ih->ih_argument, 2228088699fSJohn Baldwin ih->ih_flags); 2238088699fSJohn Baldwin 2248088699fSJohn Baldwin if ((ih->ih_flags & INTR_MPSAFE) == 0) 2258088699fSJohn Baldwin mtx_enter(&Giant, MTX_DEF); 2268088699fSJohn Baldwin ih->ih_handler(ih->ih_argument); 2278088699fSJohn Baldwin if ((ih->ih_flags & INTR_MPSAFE) == 0) 2288088699fSJohn Baldwin mtx_exit(&Giant, MTX_DEF); 2298088699fSJohn Baldwin } 2308088699fSJohn Baldwin } 2318088699fSJohn Baldwin 2328088699fSJohn Baldwin /* 2338088699fSJohn Baldwin * Processed all our interrupts. Now get the sched 2348088699fSJohn Baldwin * lock. This may take a while and it_need may get 2358088699fSJohn Baldwin * set again, so we have to check it again. 2368088699fSJohn Baldwin */ 2378088699fSJohn Baldwin mtx_enter(&sched_lock, MTX_SPIN); 2388088699fSJohn Baldwin if (!it->it_need) { 2398088699fSJohn Baldwin p->p_stat = SWAIT; /* we're idle */ 2408088699fSJohn Baldwin CTR1(KTR_INTR, "sithd_loop pid %d: done", p->p_pid); 2418088699fSJohn Baldwin mi_switch(); 2428088699fSJohn Baldwin CTR1(KTR_INTR, "sithd_loop pid %d: resumed", p->p_pid); 2438088699fSJohn Baldwin } 2448088699fSJohn Baldwin mtx_exit(&sched_lock, MTX_SPIN); 2458088699fSJohn Baldwin } 2461931cf94SJohn Baldwin } 2471931cf94SJohn Baldwin 2481931cf94SJohn Baldwin SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL) 2491931cf94SJohn Baldwin 2501931cf94SJohn Baldwin /* 2518088699fSJohn Baldwin * Start standard software interrupt threads 2521931cf94SJohn Baldwin */ 2531931cf94SJohn Baldwin static void 2541931cf94SJohn Baldwin start_softintr(dummy) 2551931cf94SJohn Baldwin void *dummy; 2561931cf94SJohn Baldwin { 2578088699fSJohn Baldwin net_ih = sinthand_add("net", NULL, swi_net, NULL, SWI_NET, 0); 2588088699fSJohn Baldwin softclock_ih = 2598088699fSJohn Baldwin sinthand_add("clock", &clk_ithd, softclock, NULL, SWI_CLOCK, 0); 2608088699fSJohn Baldwin vm_ih = sinthand_add("vm", NULL, swi_vm, NULL, SWI_VM, 0); 2611931cf94SJohn Baldwin } 2621931cf94SJohn Baldwin 2631931cf94SJohn Baldwin void 2648088699fSJohn Baldwin legacy_setsoftnet() 2651931cf94SJohn Baldwin { 2668088699fSJohn Baldwin sched_swi(net_ih, SWI_NOSWITCH); 2671931cf94SJohn Baldwin } 2681931cf94SJohn Baldwin 2698088699fSJohn Baldwin /* 2708088699fSJohn Baldwin * XXX: This should really be in the network code somewhere and installed 2718088699fSJohn Baldwin * via a SI_SUB_SOFINTR, SI_ORDER_MIDDLE sysinit. 2728088699fSJohn Baldwin */ 2738088699fSJohn Baldwin void (*netisrs[32]) __P((void)); 2748088699fSJohn Baldwin u_int netisr; 2758088699fSJohn Baldwin 2768088699fSJohn Baldwin static void 2778088699fSJohn Baldwin swi_net(void *dummy) 2781931cf94SJohn Baldwin { 2798088699fSJohn Baldwin u_int bits; 2808088699fSJohn Baldwin int i; 2818088699fSJohn Baldwin 2828088699fSJohn Baldwin bits = atomic_readandclear_int(&netisr); 2838088699fSJohn Baldwin while ((i = ffs(bits)) != 0) { 2848088699fSJohn Baldwin i--; 2858088699fSJohn Baldwin netisrs[i](); 2868088699fSJohn Baldwin bits &= ~(1 << i); 2878088699fSJohn Baldwin } 2881931cf94SJohn Baldwin } 2891931cf94SJohn Baldwin 2901931cf94SJohn Baldwin /* 2911931cf94SJohn Baldwin * Dummy spl calls. The only reason for these is to not break 2921931cf94SJohn Baldwin * all the code which expects to call them. 2931931cf94SJohn Baldwin */ 2941931cf94SJohn Baldwin void spl0 (void) {} 2951931cf94SJohn Baldwin void splx (intrmask_t x) {} 2961931cf94SJohn Baldwin intrmask_t splq(intrmask_t mask) { return 0; } 2971931cf94SJohn Baldwin intrmask_t splbio(void) { return 0; } 2981931cf94SJohn Baldwin intrmask_t splcam(void) { return 0; } 2991931cf94SJohn Baldwin intrmask_t splclock(void) { return 0; } 3001931cf94SJohn Baldwin intrmask_t splhigh(void) { return 0; } 3011931cf94SJohn Baldwin intrmask_t splimp(void) { return 0; } 3021931cf94SJohn Baldwin intrmask_t splnet(void) { return 0; } 3031931cf94SJohn Baldwin intrmask_t splsoftcam(void) { return 0; } 3041931cf94SJohn Baldwin intrmask_t splsoftcambio(void) { return 0; } 3051931cf94SJohn Baldwin intrmask_t splsoftcamnet(void) { return 0; } 3061931cf94SJohn Baldwin intrmask_t splsoftclock(void) { return 0; } 3071931cf94SJohn Baldwin intrmask_t splsofttty(void) { return 0; } 3081931cf94SJohn Baldwin intrmask_t splsoftvm(void) { return 0; } 3091931cf94SJohn Baldwin intrmask_t splsofttq(void) { return 0; } 3101931cf94SJohn Baldwin intrmask_t splstatclock(void) { return 0; } 3111931cf94SJohn Baldwin intrmask_t spltty(void) { return 0; } 3121931cf94SJohn Baldwin intrmask_t splvm(void) { return 0; } 313