1 /* $OpenBSD: softintr.c,v 1.19 2015/09/02 13:53:55 deraadt Exp $ */ 2 /* $NetBSD: softintr.c,v 1.2 2003/07/15 00:24:39 lukem Exp $ */ 3 4 /* 5 * Copyright (c) 2001 Wasabi Systems, Inc. 6 * All rights reserved. 7 * 8 * Written by Jason R. Thorpe for Wasabi Systems, Inc. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. All advertising materials mentioning features or use of this software 19 * must display the following acknowledgement: 20 * This product includes software developed for the NetBSD Project by 21 * Wasabi Systems, Inc. 22 * 4. The name of Wasabi Systems, Inc. may not be used to endorse 23 * or promote products derived from this software without specific prior 24 * written permission. 25 * 26 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND 27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC 30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 36 * POSSIBILITY OF SUCH DAMAGE. 37 */ 38 39 #include <sys/param.h> 40 #include <sys/mutex.h> 41 #include <sys/malloc.h> 42 #include <sys/atomic.h> 43 44 #include <uvm/uvm_extern.h> 45 46 #include <machine/intr.h> 47 #ifdef MULTIPROCESSOR 48 #include <mips64/mips_cpu.h> 49 #endif 50 51 struct soft_intrq soft_intrq[SI_NQUEUES]; 52 53 void netintr(void); 54 55 /* 56 * Initialize the software interrupt system. 57 */ 58 void 59 softintr_init(void) 60 { 61 struct soft_intrq *siq; 62 int i; 63 64 for (i = 0; i < SI_NQUEUES; i++) { 65 siq = &soft_intrq[i]; 66 TAILQ_INIT(&siq->siq_list); 67 siq->siq_si = i; 68 mtx_init(&siq->siq_mtx, IPL_HIGH); 69 } 70 } 71 72 /* 73 * Process pending software interrupts on the specified queue. 74 * 75 * NOTE: We must already be at the correct interrupt priority level. 76 */ 77 void 78 softintr_dispatch(int si) 79 { 80 struct soft_intrq *siq = &soft_intrq[si]; 81 struct soft_intrhand *sih; 82 83 for (;;) { 84 mtx_enter(&siq->siq_mtx); 85 sih = TAILQ_FIRST(&siq->siq_list); 86 if (sih == NULL) { 87 mtx_leave(&siq->siq_mtx); 88 break; 89 } 90 91 TAILQ_REMOVE(&siq->siq_list, sih, sih_list); 92 sih->sih_pending = 0; 93 94 atomic_inc_int(&uvmexp.softs); 95 96 mtx_leave(&siq->siq_mtx); 97 98 (*sih->sih_func)(sih->sih_arg); 99 } 100 } 101 102 /* 103 * Register a software interrupt handler. 104 */ 105 void * 106 softintr_establish(int ipl, void (*func)(void *), void *arg) 107 { 108 struct soft_intrhand *sih; 109 int si; 110 111 switch (ipl) { 112 case IPL_SOFT: 113 si = SI_SOFT; 114 break; 115 case IPL_SOFTCLOCK: 116 si = SI_SOFTCLOCK; 117 break; 118 case IPL_SOFTNET: 119 si = SI_SOFTNET; 120 break; 121 case IPL_TTY: /* XXX until MI code is fixed */ 122 case IPL_SOFTTTY: 123 si = SI_SOFTTTY; 124 break; 125 default: 126 printf("softintr_establish: unknown soft IPL %d\n", ipl); 127 return NULL; 128 } 129 130 sih = malloc(sizeof(*sih), M_DEVBUF, M_NOWAIT); 131 if (__predict_true(sih != NULL)) { 132 sih->sih_func = func; 133 sih->sih_arg = arg; 134 sih->sih_siq = &soft_intrq[si]; 135 sih->sih_pending = 0; 136 } 137 return (sih); 138 } 139 140 /* 141 * Unregister a software interrupt handler. 142 */ 143 void 144 softintr_disestablish(void *arg) 145 { 146 struct soft_intrhand *sih = arg; 147 struct soft_intrq *siq = sih->sih_siq; 148 149 mtx_enter(&siq->siq_mtx); 150 if (sih->sih_pending) { 151 TAILQ_REMOVE(&siq->siq_list, sih, sih_list); 152 sih->sih_pending = 0; 153 } 154 mtx_leave(&siq->siq_mtx); 155 156 free(sih, M_DEVBUF, sizeof *sih); 157 } 158 159 /* 160 * Schedule a software interrupt. 161 */ 162 void 163 softintr_schedule(void *arg) 164 { 165 struct cpu_info *ci = curcpu(); 166 struct soft_intrhand *sih = (struct soft_intrhand *)arg; 167 struct soft_intrq *siq = sih->sih_siq; 168 169 mtx_enter(&siq->siq_mtx); 170 if (sih->sih_pending == 0) { 171 TAILQ_INSERT_TAIL(&siq->siq_list, sih, sih_list); 172 sih->sih_pending = 1; 173 atomic_setbits_int(&ci->ci_softpending, SINTMASK(siq->siq_si)); 174 } 175 mtx_leave(&siq->siq_mtx); 176 } 177 178 void 179 dosoftint() 180 { 181 struct cpu_info *ci = curcpu(); 182 int sir, q, mask; 183 #ifdef MULTIPROCESSOR 184 register_t sr; 185 186 /* Enable interrupts */ 187 sr = getsr(); 188 ENABLEIPI(); 189 __mp_lock(&kernel_lock); 190 #endif 191 192 while ((sir = ci->ci_softpending) != 0) { 193 atomic_clearbits_int(&ci->ci_softpending, sir); 194 195 for (q = SI_NQUEUES - 1; q >= 0; q--) { 196 mask = SINTMASK(q); 197 if (sir & mask) 198 softintr_dispatch(q); 199 } 200 } 201 202 #ifdef MULTIPROCESSOR 203 __mp_unlock(&kernel_lock); 204 setsr(sr); 205 #endif 206 } 207