1*d8788e7fSmartin /* $NetBSD: kern_softint.c,v 1.12 2008/03/10 22:20:14 martin Exp $ */ 2342d5fc9Sad 3342d5fc9Sad /*- 41b6e5c8bSad * Copyright (c) 2007, 2008 The NetBSD Foundation, Inc. 5342d5fc9Sad * All rights reserved. 6342d5fc9Sad * 7342d5fc9Sad * This code is derived from software contributed to The NetBSD Foundation 8342d5fc9Sad * by Andrew Doran. 9342d5fc9Sad * 10342d5fc9Sad * Redistribution and use in source and binary forms, with or without 11342d5fc9Sad * modification, are permitted provided that the following conditions 12342d5fc9Sad * are met: 13342d5fc9Sad * 1. Redistributions of source code must retain the above copyright 14342d5fc9Sad * notice, this list of conditions and the following disclaimer. 15342d5fc9Sad * 2. Redistributions in binary form must reproduce the above copyright 16342d5fc9Sad * notice, this list of conditions and the following disclaimer in the 17342d5fc9Sad * documentation and/or other materials provided with the distribution. 18342d5fc9Sad * 3. All advertising materials mentioning features or use of this software 19342d5fc9Sad * must display the following acknowledgement: 20342d5fc9Sad * This product includes software developed by the NetBSD 21342d5fc9Sad * Foundation, Inc. and its contributors. 22342d5fc9Sad * 4. Neither the name of The NetBSD Foundation nor the names of its 23342d5fc9Sad * contributors may be used to endorse or promote products derived 24342d5fc9Sad * from this software without specific prior written permission. 25342d5fc9Sad * 26342d5fc9Sad * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 27342d5fc9Sad * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28342d5fc9Sad * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29342d5fc9Sad * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 30342d5fc9Sad * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31342d5fc9Sad * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32342d5fc9Sad * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33342d5fc9Sad * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34342d5fc9Sad * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35342d5fc9Sad * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36342d5fc9Sad * POSSIBILITY OF SUCH DAMAGE. 37342d5fc9Sad */ 38342d5fc9Sad 39342d5fc9Sad /* 404b293a84Sad * Generic software interrupt framework. 414b293a84Sad * 424b293a84Sad * Overview 434b293a84Sad * 444b293a84Sad * The soft interrupt framework provides a mechanism to schedule a 454b293a84Sad * low priority callback that runs with thread context. It allows 464b293a84Sad * for dynamic registration of software interrupts, and for fair 474b293a84Sad * queueing and prioritization of those interrupts. The callbacks 484b293a84Sad * can be scheduled to run from nearly any point in the kernel: by 494b293a84Sad * code running with thread context, by code running from a 504b293a84Sad * hardware interrupt handler, and at any interrupt priority 514b293a84Sad * level. 524b293a84Sad * 534b293a84Sad * Priority levels 544b293a84Sad * 554b293a84Sad * Since soft interrupt dispatch can be tied to the underlying 564b293a84Sad * architecture's interrupt dispatch code, it can be limited 574b293a84Sad * both by the capabilities of the hardware and the capabilities 584b293a84Sad * of the interrupt dispatch code itself. The number of priority 594b293a84Sad * levels is restricted to four. In order of priority (lowest to 604b293a84Sad * highest) the levels are: clock, bio, net, serial. 614b293a84Sad * 624b293a84Sad * The names are symbolic and in isolation do not have any direct 634b293a84Sad * connection with a particular kind of device activity: they are 644b293a84Sad * only meant as a guide. 654b293a84Sad * 664b293a84Sad * The four priority levels map directly to scheduler priority 674b293a84Sad * levels, and where the architecture implements 'fast' software 684b293a84Sad * interrupts, they also map onto interrupt priorities. The 694b293a84Sad * interrupt priorities are intended to be hidden from machine 704b293a84Sad * independent code, which should use thread-safe mechanisms to 714b293a84Sad * synchronize with software interrupts (for example: mutexes). 724b293a84Sad * 734b293a84Sad * Capabilities 744b293a84Sad * 754b293a84Sad * Software interrupts run with limited machine context. In 764b293a84Sad * particular, they do not posess any address space context. They 774b293a84Sad * should not try to operate on user space addresses, or to use 784b293a84Sad * virtual memory facilities other than those noted as interrupt 794b293a84Sad * safe. 804b293a84Sad * 814b293a84Sad * Unlike hardware interrupts, software interrupts do have thread 824b293a84Sad * context. They may block on synchronization objects, sleep, and 834b293a84Sad * resume execution at a later time. 844b293a84Sad * 854b293a84Sad * Since software interrupts are a limited resource and run with 864b293a84Sad * higher priority than most other LWPs in the system, all 874b293a84Sad * block-and-resume activity by a software interrupt must be kept 884b293a84Sad * short to allow futher processing at that level to continue. By 894b293a84Sad * extension, code running with process context must take care to 904b293a84Sad * ensure that any lock that may be taken from a software interrupt 914b293a84Sad * can not be held for more than a short period of time. 924b293a84Sad * 934b293a84Sad * The kernel does not allow software interrupts to use facilities 944b293a84Sad * or perform actions that may block for a significant amount of 954b293a84Sad * time. This means that it's not valid for a software interrupt 961b6e5c8bSad * to sleep on condition variables or wait for resources to become 971b6e5c8bSad * available (for example, memory). 984b293a84Sad * 994b293a84Sad * Per-CPU operation 1004b293a84Sad * 1014b293a84Sad * If a soft interrupt is triggered on a CPU, it can only be 1024b293a84Sad * dispatched on the same CPU. Each LWP dedicated to handling a 1034b293a84Sad * soft interrupt is bound to its home CPU, so if the LWP blocks 1044b293a84Sad * and needs to run again, it can only run there. Nearly all data 1054b293a84Sad * structures used to manage software interrupts are per-CPU. 1064b293a84Sad * 1074b293a84Sad * The per-CPU requirement is intended to reduce "ping-pong" of 1084b293a84Sad * cache lines between CPUs: lines occupied by data structures 1094b293a84Sad * used to manage the soft interrupts, and lines occupied by data 1104b293a84Sad * items being passed down to the soft interrupt. As a positive 1114b293a84Sad * side effect, this also means that the soft interrupt dispatch 1124b293a84Sad * code does not need to to use spinlocks to synchronize. 1134b293a84Sad * 1144b293a84Sad * Generic implementation 1154b293a84Sad * 1164b293a84Sad * A generic, low performance implementation is provided that 1174b293a84Sad * works across all architectures, with no machine-dependent 1184b293a84Sad * modifications needed. This implementation uses the scheduler, 1194b293a84Sad * and so has a number of restrictions: 1204b293a84Sad * 1214b293a84Sad * 1) The software interrupts are not currently preemptive, so 1224b293a84Sad * must wait for the currently executing LWP to yield the CPU. 1234b293a84Sad * This can introduce latency. 1244b293a84Sad * 1254b293a84Sad * 2) An expensive context switch is required for a software 1264b293a84Sad * interrupt to be handled. 1274b293a84Sad * 1284b293a84Sad * 'Fast' software interrupts 1294b293a84Sad * 1304b293a84Sad * If an architectures defines __HAVE_FAST_SOFTINTS, it implements 1314b293a84Sad * the fast mechanism. Threads running either in the kernel or in 1324b293a84Sad * userspace will be interrupted, but will not be preempted. When 1334b293a84Sad * the soft interrupt completes execution, the interrupted LWP 1344b293a84Sad * is resumed. Interrupt dispatch code must provide the minimum 1354b293a84Sad * level of context necessary for the soft interrupt to block and 1364b293a84Sad * be resumed at a later time. The machine-dependent dispatch 1374b293a84Sad * path looks something like the following: 1384b293a84Sad * 1394b293a84Sad * softintr() 1404b293a84Sad * { 1414b293a84Sad * go to IPL_HIGH if necessary for switch; 1424b293a84Sad * save any necessary registers in a format that can be 1434b293a84Sad * restored by cpu_switchto if the softint blocks; 1444b293a84Sad * arrange for cpu_switchto() to restore into the 1454b293a84Sad * trampoline function; 1464b293a84Sad * identify LWP to handle this interrupt; 1474b293a84Sad * switch to the LWP's stack; 1484b293a84Sad * switch register stacks, if necessary; 1494b293a84Sad * assign new value of curlwp; 1504b293a84Sad * call MI softint_dispatch, passing old curlwp and IPL 1514b293a84Sad * to execute interrupt at; 1524b293a84Sad * switch back to old stack; 1534b293a84Sad * switch back to old register stack, if necessary; 1544b293a84Sad * restore curlwp; 1554b293a84Sad * return to interrupted LWP; 1564b293a84Sad * } 1574b293a84Sad * 1584b293a84Sad * If the soft interrupt blocks, a trampoline function is returned 1594b293a84Sad * to in the context of the interrupted LWP, as arranged for by 1604b293a84Sad * softint(): 1614b293a84Sad * 1624b293a84Sad * softint_ret() 1634b293a84Sad * { 1644b293a84Sad * unlock soft interrupt LWP; 1654b293a84Sad * resume interrupt processing, likely returning to 1664b293a84Sad * interrupted LWP or dispatching another, different 1674b293a84Sad * interrupt; 1684b293a84Sad * } 1694b293a84Sad * 1704b293a84Sad * Once the soft interrupt has fired (and even if it has blocked), 1714b293a84Sad * no further soft interrupts at that level will be triggered by 1724b293a84Sad * MI code until the soft interrupt handler has ceased execution. 1734b293a84Sad * If a soft interrupt handler blocks and is resumed, it resumes 1744b293a84Sad * execution as a normal LWP (kthread) and gains VM context. Only 1754b293a84Sad * when it has completed and is ready to fire again will it 1764b293a84Sad * interrupt other threads. 1774b293a84Sad * 1784b293a84Sad * Future directions 1794b293a84Sad * 1804b293a84Sad * Provide a cheap way to direct software interrupts to remote 1814b293a84Sad * CPUs. Provide a way to enqueue work items into the handler 1824b293a84Sad * record, removing additional spl calls (see subr_workqueue.c). 183342d5fc9Sad */ 184342d5fc9Sad 185342d5fc9Sad #include <sys/cdefs.h> 186*d8788e7fSmartin __KERNEL_RCSID(0, "$NetBSD: kern_softint.c,v 1.12 2008/03/10 22:20:14 martin Exp $"); 187342d5fc9Sad 188342d5fc9Sad #include <sys/param.h> 1894b293a84Sad #include <sys/malloc.h> 1904b293a84Sad #include <sys/proc.h> 191342d5fc9Sad #include <sys/intr.h> 1924b293a84Sad #include <sys/mutex.h> 1934b293a84Sad #include <sys/kthread.h> 1944b293a84Sad #include <sys/evcnt.h> 1954b293a84Sad #include <sys/cpu.h> 196342d5fc9Sad 1974b293a84Sad #include <net/netisr.h> 1984b293a84Sad 1994b293a84Sad #include <uvm/uvm_extern.h> 2004b293a84Sad 2014b293a84Sad /* This could overlap with signal info in struct lwp. */ 2024b293a84Sad typedef struct softint { 2034b293a84Sad SIMPLEQ_HEAD(, softhand) si_q; 2044b293a84Sad struct lwp *si_lwp; 2054b293a84Sad struct cpu_info *si_cpu; 2064b293a84Sad uintptr_t si_machdep; 2074b293a84Sad struct evcnt si_evcnt; 2084b293a84Sad struct evcnt si_evcnt_block; 2094b293a84Sad int si_active; 2104b293a84Sad char si_name[8]; 2114b293a84Sad char si_name_block[8+6]; 2124b293a84Sad } softint_t; 2134b293a84Sad 2144b293a84Sad typedef struct softhand { 2154b293a84Sad SIMPLEQ_ENTRY(softhand) sh_q; 2164b293a84Sad void (*sh_func)(void *); 2174b293a84Sad void *sh_arg; 2184b293a84Sad softint_t *sh_isr; 2194b293a84Sad u_int sh_pending; 2204b293a84Sad u_int sh_flags; 2214b293a84Sad } softhand_t; 2224b293a84Sad 2234b293a84Sad typedef struct softcpu { 2244b293a84Sad struct cpu_info *sc_cpu; 2254b293a84Sad softint_t sc_int[SOFTINT_COUNT]; 2264b293a84Sad softhand_t sc_hand[1]; 2274b293a84Sad } softcpu_t; 2284b293a84Sad 2294b293a84Sad static void softint_thread(void *); 2304b293a84Sad 2314b293a84Sad u_int softint_bytes = 8192; 23236a17127Sad u_int softint_timing; 2334b293a84Sad static u_int softint_max; 2344b293a84Sad static kmutex_t softint_lock; 2354b293a84Sad static void *softint_netisrs[32]; 23636a17127Sad 237342d5fc9Sad /* 2384b293a84Sad * softint_init_isr: 2394b293a84Sad * 2404b293a84Sad * Initialize a single interrupt level for a single CPU. 2414b293a84Sad */ 2424b293a84Sad static void 2434b293a84Sad softint_init_isr(softcpu_t *sc, const char *desc, pri_t pri, u_int level) 2444b293a84Sad { 2454b293a84Sad struct cpu_info *ci; 2464b293a84Sad softint_t *si; 2474b293a84Sad int error; 2484b293a84Sad 2494b293a84Sad si = &sc->sc_int[level]; 2504b293a84Sad ci = sc->sc_cpu; 2514b293a84Sad si->si_cpu = ci; 2524b293a84Sad 2534b293a84Sad SIMPLEQ_INIT(&si->si_q); 2544b293a84Sad 2554b293a84Sad error = kthread_create(pri, KTHREAD_MPSAFE | KTHREAD_INTR | 2564b293a84Sad KTHREAD_IDLE, ci, softint_thread, si, &si->si_lwp, 257*d8788e7fSmartin "soft%s/%u", desc, ci->ci_index); 2584b293a84Sad if (error != 0) 2594b293a84Sad panic("softint_init_isr: error %d", error); 2604b293a84Sad 261*d8788e7fSmartin snprintf(si->si_name, sizeof(si->si_name), "%s/%u", desc, 262*d8788e7fSmartin ci->ci_index); 2634b293a84Sad evcnt_attach_dynamic(&si->si_evcnt, EVCNT_TYPE_INTR, NULL, 2644b293a84Sad "softint", si->si_name); 265*d8788e7fSmartin snprintf(si->si_name_block, sizeof(si->si_name_block), "%s block/%u", 266*d8788e7fSmartin desc, ci->ci_index); 2674b293a84Sad evcnt_attach_dynamic(&si->si_evcnt_block, EVCNT_TYPE_INTR, NULL, 2684b293a84Sad "softint", si->si_name_block); 2694b293a84Sad 2704b293a84Sad si->si_lwp->l_private = si; 2714b293a84Sad softint_init_md(si->si_lwp, level, &si->si_machdep); 2724b293a84Sad } 2734b293a84Sad /* 274342d5fc9Sad * softint_init: 275342d5fc9Sad * 276342d5fc9Sad * Initialize per-CPU data structures. Called from mi_cpu_attach(). 277342d5fc9Sad */ 278342d5fc9Sad void 279342d5fc9Sad softint_init(struct cpu_info *ci) 280342d5fc9Sad { 2814b293a84Sad static struct cpu_info *first; 2824b293a84Sad softcpu_t *sc, *scfirst; 2834b293a84Sad softhand_t *sh, *shmax; 284342d5fc9Sad 2854b293a84Sad if (first == NULL) { 2864b293a84Sad /* Boot CPU. */ 2874b293a84Sad first = ci; 2884b293a84Sad mutex_init(&softint_lock, MUTEX_DEFAULT, IPL_NONE); 2894b293a84Sad softint_bytes = round_page(softint_bytes); 2904b293a84Sad softint_max = (softint_bytes - sizeof(softcpu_t)) / 2914b293a84Sad sizeof(softhand_t); 2924b293a84Sad } 2934b293a84Sad 2944b293a84Sad sc = (softcpu_t *)uvm_km_alloc(kernel_map, softint_bytes, 0, 2954b293a84Sad UVM_KMF_WIRED | UVM_KMF_ZERO); 2964b293a84Sad if (sc == NULL) 2974b293a84Sad panic("softint_init_cpu: cannot allocate memory"); 2984b293a84Sad 2994b293a84Sad ci->ci_data.cpu_softcpu = sc; 3004b293a84Sad ci->ci_data.cpu_softints = 0; 3014b293a84Sad sc->sc_cpu = ci; 3024b293a84Sad 3034b293a84Sad softint_init_isr(sc, "net", PRI_SOFTNET, SOFTINT_NET); 3044b293a84Sad softint_init_isr(sc, "bio", PRI_SOFTBIO, SOFTINT_BIO); 3054b293a84Sad softint_init_isr(sc, "clk", PRI_SOFTCLOCK, SOFTINT_CLOCK); 3064b293a84Sad softint_init_isr(sc, "ser", PRI_SOFTSERIAL, SOFTINT_SERIAL); 3074b293a84Sad 3084b293a84Sad if (first != ci) { 3094b293a84Sad mutex_enter(&softint_lock); 3104b293a84Sad scfirst = first->ci_data.cpu_softcpu; 3114b293a84Sad sh = sc->sc_hand; 3124b293a84Sad memcpy(sh, scfirst->sc_hand, sizeof(*sh) * softint_max); 3134b293a84Sad /* Update pointers for this CPU. */ 3144b293a84Sad for (shmax = sh + softint_max; sh < shmax; sh++) { 3154b293a84Sad if (sh->sh_func == NULL) 3164b293a84Sad continue; 3174b293a84Sad sh->sh_isr = 3184b293a84Sad &sc->sc_int[sh->sh_flags & SOFTINT_LVLMASK]; 3194b293a84Sad } 3204b293a84Sad mutex_exit(&softint_lock); 3214b293a84Sad } else { 3224b293a84Sad /* 3234b293a84Sad * Establish handlers for legacy net interrupts. 3244b293a84Sad * XXX Needs to go away. 3254b293a84Sad */ 3264b293a84Sad #define DONETISR(n, f) \ 3274b293a84Sad softint_netisrs[(n)] = \ 3284b293a84Sad softint_establish(SOFTINT_NET, (void (*)(void *))(f), NULL) 3294b293a84Sad #include <net/netisr_dispatch.h> 3304b293a84Sad } 331342d5fc9Sad } 332342d5fc9Sad 333342d5fc9Sad /* 334342d5fc9Sad * softint_establish: 335342d5fc9Sad * 336342d5fc9Sad * Register a software interrupt handler. 337342d5fc9Sad */ 338342d5fc9Sad void * 339342d5fc9Sad softint_establish(u_int flags, void (*func)(void *), void *arg) 340342d5fc9Sad { 3414b293a84Sad CPU_INFO_ITERATOR cii; 3424b293a84Sad struct cpu_info *ci; 3434b293a84Sad softcpu_t *sc; 3444b293a84Sad softhand_t *sh; 3454b293a84Sad u_int level, index; 346342d5fc9Sad 347342d5fc9Sad level = (flags & SOFTINT_LVLMASK); 348342d5fc9Sad KASSERT(level < SOFTINT_COUNT); 349342d5fc9Sad 3504b293a84Sad mutex_enter(&softint_lock); 3514b293a84Sad 3524b293a84Sad /* Find a free slot. */ 3534b293a84Sad sc = curcpu()->ci_data.cpu_softcpu; 3544b293a84Sad for (index = 1; index < softint_max; index++) 3554b293a84Sad if (sc->sc_hand[index].sh_func == NULL) 356342d5fc9Sad break; 3574b293a84Sad if (index == softint_max) { 3584b293a84Sad mutex_exit(&softint_lock); 3594b293a84Sad printf("WARNING: softint_establish: table full, " 3604b293a84Sad "increase softint_bytes\n"); 3614b293a84Sad return NULL; 362342d5fc9Sad } 363342d5fc9Sad 3644b293a84Sad /* Set up the handler on each CPU. */ 3657b8aa25aSad if (ncpu < 2) { 366eb83663dSad /* XXX hack for machines with no CPU_INFO_FOREACH() early on */ 367eb83663dSad sc = curcpu()->ci_data.cpu_softcpu; 368eb83663dSad sh = &sc->sc_hand[index]; 369eb83663dSad sh->sh_isr = &sc->sc_int[level]; 370eb83663dSad sh->sh_func = func; 371eb83663dSad sh->sh_arg = arg; 372eb83663dSad sh->sh_flags = flags; 373eb83663dSad sh->sh_pending = 0; 374eb83663dSad } else for (CPU_INFO_FOREACH(cii, ci)) { 3754b293a84Sad sc = ci->ci_data.cpu_softcpu; 3764b293a84Sad sh = &sc->sc_hand[index]; 3774b293a84Sad sh->sh_isr = &sc->sc_int[level]; 3784b293a84Sad sh->sh_func = func; 3794b293a84Sad sh->sh_arg = arg; 3804b293a84Sad sh->sh_flags = flags; 3814b293a84Sad sh->sh_pending = 0; 3824b293a84Sad } 3834b293a84Sad 3844b293a84Sad mutex_exit(&softint_lock); 3854b293a84Sad 3864b293a84Sad return (void *)((uint8_t *)&sc->sc_hand[index] - (uint8_t *)sc); 387342d5fc9Sad } 388342d5fc9Sad 389342d5fc9Sad /* 390342d5fc9Sad * softint_disestablish: 391342d5fc9Sad * 392342d5fc9Sad * Unregister a software interrupt handler. 393342d5fc9Sad */ 394342d5fc9Sad void 395342d5fc9Sad softint_disestablish(void *arg) 396342d5fc9Sad { 3974b293a84Sad CPU_INFO_ITERATOR cii; 3984b293a84Sad struct cpu_info *ci; 3994b293a84Sad softcpu_t *sc; 4004b293a84Sad softhand_t *sh; 4014b293a84Sad uintptr_t offset; 402342d5fc9Sad 4034b293a84Sad offset = (uintptr_t)arg; 4044b293a84Sad KASSERT(offset != 0 && offset < softint_bytes); 4054b293a84Sad 4064b293a84Sad mutex_enter(&softint_lock); 4074b293a84Sad 4084b293a84Sad /* Clear the handler on each CPU. */ 4094b293a84Sad for (CPU_INFO_FOREACH(cii, ci)) { 4104b293a84Sad sc = ci->ci_data.cpu_softcpu; 4114b293a84Sad sh = (softhand_t *)((uint8_t *)sc + offset); 4124b293a84Sad KASSERT(sh->sh_func != NULL); 4134b293a84Sad KASSERT(sh->sh_pending == 0); 4144b293a84Sad sh->sh_func = NULL; 4154b293a84Sad } 4164b293a84Sad 4174b293a84Sad mutex_exit(&softint_lock); 418342d5fc9Sad } 419342d5fc9Sad 420342d5fc9Sad /* 421342d5fc9Sad * softint_schedule: 422342d5fc9Sad * 423342d5fc9Sad * Trigger a software interrupt. Must be called from a hardware 424342d5fc9Sad * interrupt handler, or with preemption disabled (since we are 425342d5fc9Sad * using the value of curcpu()). 426342d5fc9Sad */ 427342d5fc9Sad void 428342d5fc9Sad softint_schedule(void *arg) 429342d5fc9Sad { 4304b293a84Sad softhand_t *sh; 4314b293a84Sad softint_t *si; 4324b293a84Sad uintptr_t offset; 4334b293a84Sad int s; 434342d5fc9Sad 4354b293a84Sad /* Find the handler record for this CPU. */ 4364b293a84Sad offset = (uintptr_t)arg; 4374b293a84Sad KASSERT(offset != 0 && offset < softint_bytes); 4384b293a84Sad sh = (softhand_t *)((uint8_t *)curcpu()->ci_data.cpu_softcpu + offset); 4394b293a84Sad 4404b293a84Sad /* If it's already pending there's nothing to do. */ 4414b293a84Sad if (sh->sh_pending) 4424b293a84Sad return; 4434b293a84Sad 4444b293a84Sad /* 4454b293a84Sad * Enqueue the handler into the LWP's pending list. 4464b293a84Sad * If the LWP is completely idle, then make it run. 4474b293a84Sad */ 4484b293a84Sad s = splhigh(); 4494b293a84Sad if (!sh->sh_pending) { 4504b293a84Sad si = sh->sh_isr; 4514b293a84Sad sh->sh_pending = 1; 4524b293a84Sad SIMPLEQ_INSERT_TAIL(&si->si_q, sh, sh_q); 4534b293a84Sad if (si->si_active == 0) { 4544b293a84Sad si->si_active = 1; 4554b293a84Sad softint_trigger(si->si_machdep); 4564b293a84Sad } 4574b293a84Sad } 4584b293a84Sad splx(s); 4594b293a84Sad } 4604b293a84Sad 4614b293a84Sad /* 4624b293a84Sad * softint_execute: 4634b293a84Sad * 4644b293a84Sad * Invoke handlers for the specified soft interrupt. 4654b293a84Sad * Must be entered at splhigh. Will drop the priority 4664b293a84Sad * to the level specified, but returns back at splhigh. 4674b293a84Sad */ 4684b293a84Sad static inline void 4694b293a84Sad softint_execute(softint_t *si, lwp_t *l, int s) 4704b293a84Sad { 4714b293a84Sad softhand_t *sh; 4724b293a84Sad bool havelock; 4734b293a84Sad 4744b293a84Sad #ifdef __HAVE_FAST_SOFTINTS 4754b293a84Sad KASSERT(si->si_lwp == curlwp); 4764b293a84Sad #else 4774b293a84Sad /* May be running in user context. */ 4784b293a84Sad #endif 4794b293a84Sad KASSERT(si->si_cpu == curcpu()); 4804b293a84Sad KASSERT(si->si_lwp->l_wchan == NULL); 4814b293a84Sad KASSERT(si->si_active); 4824b293a84Sad 4834b293a84Sad havelock = false; 4844b293a84Sad 4854b293a84Sad /* 4864b293a84Sad * Note: due to priority inheritance we may have interrupted a 4874b293a84Sad * higher priority LWP. Since the soft interrupt must be quick 4884b293a84Sad * and is non-preemptable, we don't bother yielding. 4894b293a84Sad */ 4904b293a84Sad 4914b293a84Sad while (!SIMPLEQ_EMPTY(&si->si_q)) { 4924b293a84Sad /* 4934b293a84Sad * Pick the longest waiting handler to run. We block 4944b293a84Sad * interrupts but do not lock in order to do this, as 4954b293a84Sad * we are protecting against the local CPU only. 4964b293a84Sad */ 4974b293a84Sad sh = SIMPLEQ_FIRST(&si->si_q); 4984b293a84Sad SIMPLEQ_REMOVE_HEAD(&si->si_q, sh_q); 4994b293a84Sad sh->sh_pending = 0; 5004b293a84Sad splx(s); 5014b293a84Sad 5024b293a84Sad /* Run the handler. */ 5034b293a84Sad if ((sh->sh_flags & SOFTINT_MPSAFE) == 0 && !havelock) { 5044b293a84Sad KERNEL_LOCK(1, l); 5054b293a84Sad havelock = true; 5064b293a84Sad } 5074b293a84Sad (*sh->sh_func)(sh->sh_arg); 5084b293a84Sad 5094b293a84Sad (void)splhigh(); 5104b293a84Sad } 5114b293a84Sad 5124b293a84Sad if (havelock) { 5134b293a84Sad KERNEL_UNLOCK_ONE(l); 5144b293a84Sad } 5154b293a84Sad 5164b293a84Sad /* 5174b293a84Sad * Unlocked, but only for statistics. 5184b293a84Sad * Should be per-CPU to prevent cache ping-pong. 5194b293a84Sad */ 5204b293a84Sad uvmexp.softs++; 5214b293a84Sad 5224b293a84Sad si->si_evcnt.ev_count++; 5234b293a84Sad si->si_active = 0; 524342d5fc9Sad } 525342d5fc9Sad 526342d5fc9Sad /* 527342d5fc9Sad * softint_block: 528342d5fc9Sad * 529342d5fc9Sad * Update statistics when the soft interrupt blocks. 530342d5fc9Sad */ 531342d5fc9Sad void 532342d5fc9Sad softint_block(lwp_t *l) 533342d5fc9Sad { 5344b293a84Sad softint_t *si = l->l_private; 535342d5fc9Sad 5364b293a84Sad KASSERT((l->l_pflag & LP_INTR) != 0); 5374b293a84Sad si->si_evcnt_block.ev_count++; 5384b293a84Sad } 5394b293a84Sad 5404b293a84Sad /* 5414b293a84Sad * schednetisr: 5424b293a84Sad * 5434b293a84Sad * Trigger a legacy network interrupt. XXX Needs to go away. 5444b293a84Sad */ 5454b293a84Sad void 5464b293a84Sad schednetisr(int isr) 5474b293a84Sad { 5484b293a84Sad 5494b293a84Sad softint_schedule(softint_netisrs[isr]); 5504b293a84Sad } 5514b293a84Sad 5524b293a84Sad #ifndef __HAVE_FAST_SOFTINTS 5534b293a84Sad 5544b293a84Sad /* 5554b293a84Sad * softint_init_md: 5564b293a84Sad * 5574b293a84Sad * Slow path: perform machine-dependent initialization. 5584b293a84Sad */ 5594b293a84Sad void 5604b293a84Sad softint_init_md(lwp_t *l, u_int level, uintptr_t *machdep) 5614b293a84Sad { 5624b293a84Sad softint_t *si; 5634b293a84Sad 5644b293a84Sad *machdep = (1 << level); 5654b293a84Sad si = l->l_private; 5664b293a84Sad 5674b293a84Sad lwp_lock(l); 5684b293a84Sad lwp_unlock_to(l, l->l_cpu->ci_schedstate.spc_mutex); 5694b293a84Sad lwp_lock(l); 5704b293a84Sad /* Cheat and make the KASSERT in softint_thread() happy. */ 5714b293a84Sad si->si_active = 1; 5724b293a84Sad l->l_stat = LSRUN; 5734b293a84Sad sched_enqueue(l, false); 5744b293a84Sad lwp_unlock(l); 5754b293a84Sad } 5764b293a84Sad 5774b293a84Sad /* 5784b293a84Sad * softint_trigger: 5794b293a84Sad * 5804b293a84Sad * Slow path: cause a soft interrupt handler to begin executing. 5814b293a84Sad * Called at IPL_HIGH. 5824b293a84Sad */ 5834b293a84Sad void 5844b293a84Sad softint_trigger(uintptr_t machdep) 5854b293a84Sad { 5864b293a84Sad struct cpu_info *ci; 5874b293a84Sad lwp_t *l; 5884b293a84Sad 5894b293a84Sad l = curlwp; 5904b293a84Sad ci = l->l_cpu; 5914b293a84Sad ci->ci_data.cpu_softints |= machdep; 5924b293a84Sad if (l == ci->ci_data.cpu_idlelwp) { 5934b293a84Sad cpu_need_resched(ci, 0); 5944b293a84Sad } else { 5954b293a84Sad /* MI equivalent of aston() */ 5964b293a84Sad cpu_signotify(l); 5974b293a84Sad } 5984b293a84Sad } 5994b293a84Sad 6004b293a84Sad /* 6014b293a84Sad * softint_thread: 6024b293a84Sad * 6034b293a84Sad * Slow path: MI software interrupt dispatch. 6044b293a84Sad */ 6054b293a84Sad void 6064b293a84Sad softint_thread(void *cookie) 6074b293a84Sad { 6084b293a84Sad softint_t *si; 6094b293a84Sad lwp_t *l; 6104b293a84Sad int s; 6114b293a84Sad 6124b293a84Sad l = curlwp; 6134b293a84Sad si = l->l_private; 6144b293a84Sad 6154b293a84Sad for (;;) { 6164b293a84Sad /* 6174b293a84Sad * Clear pending status and run it. We must drop the 6184b293a84Sad * spl before mi_switch(), since IPL_HIGH may be higher 6194b293a84Sad * than IPL_SCHED (and it is not safe to switch at a 6204b293a84Sad * higher level). 6214b293a84Sad */ 6224b293a84Sad s = splhigh(); 6234b293a84Sad l->l_cpu->ci_data.cpu_softints &= ~si->si_machdep; 6244b293a84Sad softint_execute(si, l, s); 6254b293a84Sad splx(s); 6264b293a84Sad 6274b293a84Sad lwp_lock(l); 6284b293a84Sad l->l_stat = LSIDL; 6294b293a84Sad mi_switch(l); 6304b293a84Sad } 631342d5fc9Sad } 632d831186dSad 633d831186dSad /* 634d831186dSad * softint_picklwp: 635d831186dSad * 636d831186dSad * Slow path: called from mi_switch() to pick the highest priority 637d831186dSad * soft interrupt LWP that needs to run. 638d831186dSad */ 639d831186dSad lwp_t * 640d831186dSad softint_picklwp(void) 641d831186dSad { 6424b293a84Sad struct cpu_info *ci; 6434b293a84Sad u_int mask; 6444b293a84Sad softint_t *si; 6454b293a84Sad lwp_t *l; 646d831186dSad 6474b293a84Sad ci = curcpu(); 6484b293a84Sad si = ((softcpu_t *)ci->ci_data.cpu_softcpu)->sc_int; 6494b293a84Sad mask = ci->ci_data.cpu_softints; 6504b293a84Sad 6514b293a84Sad if ((mask & (1 << SOFTINT_SERIAL)) != 0) { 6524b293a84Sad l = si[SOFTINT_SERIAL].si_lwp; 6534b293a84Sad } else if ((mask & (1 << SOFTINT_NET)) != 0) { 6544b293a84Sad l = si[SOFTINT_NET].si_lwp; 6554b293a84Sad } else if ((mask & (1 << SOFTINT_BIO)) != 0) { 6564b293a84Sad l = si[SOFTINT_BIO].si_lwp; 6574b293a84Sad } else if ((mask & (1 << SOFTINT_CLOCK)) != 0) { 6584b293a84Sad l = si[SOFTINT_CLOCK].si_lwp; 6594b293a84Sad } else { 660d831186dSad panic("softint_picklwp"); 661d831186dSad } 662d831186dSad 6634b293a84Sad return l; 6644b293a84Sad } 6654b293a84Sad 666d831186dSad /* 667d831186dSad * softint_overlay: 668d831186dSad * 669d831186dSad * Slow path: called from lwp_userret() to run a soft interrupt 6709027344dSad * within the context of a user thread. 671d831186dSad */ 672d831186dSad void 673d831186dSad softint_overlay(void) 674d831186dSad { 6754b293a84Sad struct cpu_info *ci; 6764b293a84Sad u_int softints; 6774b293a84Sad softint_t *si; 6789027344dSad pri_t obase; 6794b293a84Sad lwp_t *l; 6804b293a84Sad int s; 681d831186dSad 6824b293a84Sad l = curlwp; 6834b293a84Sad ci = l->l_cpu; 6844b293a84Sad si = ((softcpu_t *)ci->ci_data.cpu_softcpu)->sc_int; 6854b293a84Sad 6864b293a84Sad KASSERT((l->l_pflag & LP_INTR) == 0); 6874b293a84Sad 6889027344dSad /* Arrange to elevate priority if the LWP blocks. */ 6899027344dSad obase = l->l_kpribase; 6909027344dSad l->l_kpribase = PRI_KERNEL_RT; 6914b293a84Sad l->l_pflag |= LP_INTR; 6924b293a84Sad s = splhigh(); 6934b293a84Sad while ((softints = ci->ci_data.cpu_softints) != 0) { 6944b293a84Sad if ((softints & (1 << SOFTINT_SERIAL)) != 0) { 6954b293a84Sad ci->ci_data.cpu_softints &= ~(1 << SOFTINT_SERIAL); 6964b293a84Sad softint_execute(&si[SOFTINT_SERIAL], l, s); 6974b293a84Sad continue; 6984b293a84Sad } 6994b293a84Sad if ((softints & (1 << SOFTINT_NET)) != 0) { 7004b293a84Sad ci->ci_data.cpu_softints &= ~(1 << SOFTINT_NET); 7014b293a84Sad softint_execute(&si[SOFTINT_NET], l, s); 7024b293a84Sad continue; 7034b293a84Sad } 7044b293a84Sad if ((softints & (1 << SOFTINT_BIO)) != 0) { 7054b293a84Sad ci->ci_data.cpu_softints &= ~(1 << SOFTINT_BIO); 7064b293a84Sad softint_execute(&si[SOFTINT_BIO], l, s); 7074b293a84Sad continue; 7084b293a84Sad } 7094b293a84Sad if ((softints & (1 << SOFTINT_CLOCK)) != 0) { 7104b293a84Sad ci->ci_data.cpu_softints &= ~(1 << SOFTINT_CLOCK); 7114b293a84Sad softint_execute(&si[SOFTINT_CLOCK], l, s); 7124b293a84Sad continue; 7134b293a84Sad } 7144b293a84Sad } 7154b293a84Sad splx(s); 7164b293a84Sad l->l_pflag &= ~LP_INTR; 7179027344dSad l->l_kpribase = obase; 718d831186dSad } 7194b293a84Sad 7204b293a84Sad #else /* !__HAVE_FAST_SOFTINTS */ 7214b293a84Sad 7224b293a84Sad /* 7234b293a84Sad * softint_thread: 7244b293a84Sad * 7254b293a84Sad * Fast path: the LWP is switched to without restoring any state, 7264b293a84Sad * so we should not arrive here - there is a direct handoff between 7274b293a84Sad * the interrupt stub and softint_dispatch(). 7284b293a84Sad */ 7294b293a84Sad void 7304b293a84Sad softint_thread(void *cookie) 7314b293a84Sad { 7324b293a84Sad 7334b293a84Sad panic("softint_thread"); 7344b293a84Sad } 7354b293a84Sad 7364b293a84Sad /* 7374b293a84Sad * softint_dispatch: 7384b293a84Sad * 7394b293a84Sad * Fast path: entry point from machine-dependent code. 7404b293a84Sad */ 7414b293a84Sad void 7424b293a84Sad softint_dispatch(lwp_t *pinned, int s) 7434b293a84Sad { 744949e16d9Syamt struct bintime now; 7454b293a84Sad softint_t *si; 7464b293a84Sad u_int timing; 7474b293a84Sad lwp_t *l; 7484b293a84Sad 7494b293a84Sad l = curlwp; 7504b293a84Sad si = l->l_private; 7514b293a84Sad 7524b293a84Sad /* 7534b293a84Sad * Note the interrupted LWP, and mark the current LWP as running 7544b293a84Sad * before proceeding. Although this must as a rule be done with 7554b293a84Sad * the LWP locked, at this point no external agents will want to 7564b293a84Sad * modify the interrupt LWP's state. 7574b293a84Sad */ 7584b293a84Sad timing = (softint_timing ? LW_TIMEINTR : 0); 7594b293a84Sad l->l_switchto = pinned; 7604b293a84Sad l->l_stat = LSONPROC; 7614b293a84Sad l->l_flag |= (LW_RUNNING | timing); 7624b293a84Sad 7634b293a84Sad /* 7644b293a84Sad * Dispatch the interrupt. If softints are being timed, charge 7654b293a84Sad * for it. 7664b293a84Sad */ 7674b293a84Sad if (timing) 768caca6daaSyamt binuptime(&l->l_stime); 7694b293a84Sad softint_execute(si, l, s); 7704b293a84Sad if (timing) { 771caca6daaSyamt binuptime(&now); 7724b293a84Sad updatertime(l, &now); 7734b293a84Sad l->l_flag &= ~LW_TIMEINTR; 7744b293a84Sad } 7754b293a84Sad 7764b293a84Sad /* 7774b293a84Sad * If we blocked while handling the interrupt, the pinned LWP is 7784b293a84Sad * gone so switch to the idle LWP. It will select a new LWP to 7794b293a84Sad * run. 7804b293a84Sad * 7814b293a84Sad * We must drop the priority level as switching at IPL_HIGH could 7824b293a84Sad * deadlock the system. We have already set si->si_active = 0, 7834b293a84Sad * which means another interrupt at this level can be triggered. 7844b293a84Sad * That's not be a problem: we are lowering to level 's' which will 7854b293a84Sad * prevent softint_dispatch() from being reentered at level 's', 7864b293a84Sad * until the priority is finally dropped to IPL_NONE on entry to 7874b293a84Sad * the idle loop. 7884b293a84Sad */ 7894b293a84Sad l->l_stat = LSIDL; 7904b293a84Sad if (l->l_switchto == NULL) { 7914b293a84Sad splx(s); 7924b293a84Sad pmap_deactivate(l); 7934b293a84Sad lwp_exit_switchaway(l); 7944b293a84Sad /* NOTREACHED */ 7954b293a84Sad } 7964b293a84Sad l->l_switchto = NULL; 7974b293a84Sad l->l_flag &= ~LW_RUNNING; 7984b293a84Sad } 7994b293a84Sad 8004b293a84Sad #endif /* !__HAVE_FAST_SOFTINTS */ 801