kern_intr.c revision 67365
1/* 2 * Copyright (c) 1997, Stefan Esser <se@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice unmodified, this list of conditions, and the following 10 * disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * 26 * $FreeBSD: head/sys/kern/kern_intr.c 67365 2000-10-20 07:58:15Z jhb $ 27 * 28 */ 29 30 31#include <sys/param.h> 32#include <sys/bus.h> 33#include <sys/rtprio.h> 34#include <sys/systm.h> 35#include <sys/ipl.h> 36#include <sys/interrupt.h> 37#include <sys/kernel.h> 38#include <sys/kthread.h> 39#include <sys/ktr.h> 40#include <sys/malloc.h> 41#include <sys/mutex.h> 42#include <sys/proc.h> 43#include <sys/unistd.h> 44#include <sys/vmmeter.h> 45#include <machine/atomic.h> 46#include <machine/cpu.h> 47 48struct swilist { 49 swihand_t *sl_handler; 50 struct swilist *sl_next; 51}; 52 53static struct swilist swilists[NSWI]; 54u_long softintr_count[NSWI]; 55static struct proc *softithd; 56volatile u_int sdelayed; 57volatile u_int spending; 58 59static void start_softintr(void *); 60static void intr_soft(void *); 61 62void 63register_swi(intr, handler) 64 int intr; 65 swihand_t *handler; 66{ 67 struct swilist *slp, *slq; 68 int s; 69 70 if (intr < 0 || intr >= NSWI) 71 panic("register_swi: bad intr %d", intr); 72 if (handler == swi_generic || handler == swi_null) 73 panic("register_swi: bad handler %p", (void *)handler); 74 slp = &swilists[intr]; 75 s = splhigh(); 76 if (shandlers[intr] == swi_null) 77 shandlers[intr] = handler; 78 else { 79 if (slp->sl_next == NULL) { 80 slp->sl_handler = shandlers[intr]; 81 shandlers[intr] = swi_generic; 82 } 83 slq = malloc(sizeof(*slq), M_DEVBUF, M_NOWAIT); 84 if (slq == NULL) 85 panic("register_swi: malloc failed"); 86 slq->sl_handler = handler; 87 slq->sl_next = NULL; 88 while (slp->sl_next != NULL) 89 slp = slp->sl_next; 90 slp->sl_next = slq; 91 } 92 splx(s); 93} 94 95void 96swi_dispatcher(intr) 97 int intr; 98{ 99 struct swilist *slp; 100 101 slp = &swilists[intr]; 102 do { 103 (*slp->sl_handler)(); 104 slp = slp->sl_next; 105 } while (slp != NULL); 106} 107 108void 109unregister_swi(intr, handler) 110 int intr; 111 swihand_t *handler; 112{ 113 struct swilist *slfoundpred, *slp, *slq; 114 int s; 115 116 if (intr < 0 || intr >= NSWI) 117 panic("unregister_swi: bad intr %d", intr); 118 if (handler == swi_generic || handler == swi_null) 119 panic("unregister_swi: bad handler %p", (void *)handler); 120 slp = &swilists[intr]; 121 s = splhigh(); 122 if (shandlers[intr] == handler) 123 shandlers[intr] = swi_null; 124 else if (slp->sl_next != NULL) { 125 slfoundpred = NULL; 126 for (slq = slp->sl_next; slq != NULL; 127 slp = slq, slq = slp->sl_next) 128 if (slq->sl_handler == handler) 129 slfoundpred = slp; 130 slp = &swilists[intr]; 131 if (slfoundpred != NULL) { 132 slq = slfoundpred->sl_next; 133 slfoundpred->sl_next = slq->sl_next; 134 free(slq, M_DEVBUF); 135 } else if (slp->sl_handler == handler) { 136 slq = slp->sl_next; 137 slp->sl_next = slq->sl_next; 138 slp->sl_handler = slq->sl_handler; 139 free(slq, M_DEVBUF); 140 } 141 if (slp->sl_next == NULL) 142 shandlers[intr] = slp->sl_handler; 143 } 144 splx(s); 145} 146 147int 148ithread_priority(flags) 149 int flags; 150{ 151 int pri; 152 153 switch (flags) { 154 case INTR_TYPE_TTY: /* keyboard or parallel port */ 155 pri = PI_TTYLOW; 156 break; 157 case (INTR_TYPE_TTY | INTR_FAST): /* sio */ 158 pri = PI_TTYHIGH; 159 break; 160 case INTR_TYPE_BIO: 161 /* 162 * XXX We need to refine this. BSD/OS distinguishes 163 * between tape and disk priorities. 164 */ 165 pri = PI_DISK; 166 break; 167 case INTR_TYPE_NET: 168 pri = PI_NET; 169 break; 170 case INTR_TYPE_CAM: 171 pri = PI_DISK; /* XXX or PI_CAM? */ 172 break; 173 case INTR_TYPE_MISC: 174 pri = PI_DULL; /* don't care */ 175 break; 176 /* We didn't specify an interrupt level. */ 177 default: 178 panic("ithread_priority: no interrupt type in flags"); 179 } 180 181 return pri; 182} 183 184/* 185 * Schedule the soft interrupt handler thread. 186 */ 187void 188sched_softintr(void) 189{ 190 atomic_add_int(&cnt.v_intr, 1); /* one more global interrupt */ 191 192 /* 193 * If we don't have an interrupt resource or an interrupt thread for 194 * this IRQ, log it as a stray interrupt. 195 */ 196 if (softithd == NULL) 197 panic("soft interrupt scheduled too early"); 198 199 CTR3(KTR_INTR, "sched_softintr pid %d(%s) spending=0x%x", 200 softithd->p_pid, softithd->p_comm, spending); 201 202 /* 203 * Get the sched lock and see if the thread is on whichkqs yet. 204 * If not, put it on there. In any case, kick everyone so that if 205 * the new thread is higher priority than their current thread, it 206 * gets run now. 207 */ 208 mtx_enter(&sched_lock, MTX_SPIN); 209 if (softithd->p_stat == SWAIT) { /* not on run queue */ 210 CTR1(KTR_INTR, "sched_softintr: setrunqueue %d", 211 softithd->p_pid); 212/* membar_lock(); */ 213 softithd->p_stat = SRUN; 214 setrunqueue(softithd); 215 aston(); 216 } 217 mtx_exit(&sched_lock, MTX_SPIN); 218#if 0 219 aston(); /* ??? check priorities first? */ 220#else 221 need_resched(); 222#endif 223} 224 225SYSINIT(start_softintr, SI_SUB_SOFTINTR, SI_ORDER_FIRST, start_softintr, NULL) 226 227/* 228 * Start soft interrupt thread. 229 */ 230static void 231start_softintr(dummy) 232 void *dummy; 233{ 234 int error; 235 236 if (softithd != NULL) { /* we already have a thread */ 237 printf("start_softintr: already running"); 238 return; 239 } 240 241 error = kthread_create(intr_soft, NULL, &softithd, 242 RFSTOPPED | RFHIGHPID, "softinterrupt"); 243 if (error) 244 panic("start_softintr: kthread_create error %d\n", error); 245 246 softithd->p_rtprio.type = RTP_PRIO_ITHREAD; 247 softithd->p_rtprio.prio = PI_SOFT; /* soft interrupt */ 248 softithd->p_stat = SWAIT; /* we're idle */ 249 softithd->p_flag |= P_NOLOAD; 250} 251 252/* 253 * Software interrupt process code. 254 */ 255static void 256intr_soft(dummy) 257 void *dummy; 258{ 259 int i; 260 u_int pend; 261 262 /* Main loop */ 263 for (;;) { 264 CTR3(KTR_INTR, "intr_soft pid %d(%s) spending=0x%x", 265 curproc->p_pid, curproc->p_comm, spending); 266 267 /* 268 * Service interrupts. If another interrupt arrives 269 * while we are running, they will set spending to 270 * denote that we should make another pass. 271 */ 272 pend = atomic_readandclear_int(&spending); 273 while ((i = ffs(pend))) { 274 i--; 275 atomic_add_long(&softintr_count[i], 1); 276 pend &= ~ (1 << i); 277 mtx_enter(&Giant, MTX_DEF); 278 if (shandlers[i] == swi_generic) 279 swi_dispatcher(i); 280 else 281 (shandlers[i])(); 282 mtx_exit(&Giant, MTX_DEF); 283 } 284 /* 285 * Processed all our interrupts. Now get the sched 286 * lock. This may take a while and spending may get 287 * set again, so we have to check it again. 288 */ 289 mtx_enter(&sched_lock, MTX_SPIN); 290 if (spending == 0) { 291 CTR1(KTR_INTR, "intr_soft pid %d: done", 292 curproc->p_pid); 293 curproc->p_stat = SWAIT; /* we're idle */ 294 mi_switch(); 295 CTR1(KTR_INTR, "intr_soft pid %d: resumed", 296 curproc->p_pid); 297 } 298 mtx_exit(&sched_lock, MTX_SPIN); 299 } 300} 301 302/* 303 * Bits in the spending bitmap variable must be set atomically because 304 * spending may be manipulated by interrupts or other cpu's without holding 305 * any locks. 306 * 307 * Note: setbits uses a locked or, making simple cases MP safe. 308 */ 309#define DO_SETBITS(name, var, bits) \ 310void name(void) \ 311{ \ 312 atomic_set_int(var, bits); \ 313 sched_softintr(); \ 314} 315 316#define DO_SETBITS_AND_NO_MORE(name, var, bits) \ 317void name(void) \ 318{ \ 319 atomic_set_int(var, bits); \ 320} 321 322DO_SETBITS(setsoftcamnet,&spending, SWI_CAMNET_PENDING) 323DO_SETBITS(setsoftcambio,&spending, SWI_CAMBIO_PENDING) 324DO_SETBITS(setsoftclock, &spending, SWI_CLOCK_PENDING) 325DO_SETBITS(setsoftnet, &spending, SWI_NET_PENDING) 326DO_SETBITS(setsofttty, &spending, SWI_TTY_PENDING) 327DO_SETBITS(setsoftvm, &spending, SWI_VM_PENDING) 328DO_SETBITS(setsofttq, &spending, SWI_TQ_PENDING) 329 330DO_SETBITS_AND_NO_MORE(schedsoftcamnet, &sdelayed, SWI_CAMNET_PENDING) 331DO_SETBITS_AND_NO_MORE(schedsoftcambio, &sdelayed, SWI_CAMBIO_PENDING) 332DO_SETBITS_AND_NO_MORE(schedsoftnet, &sdelayed, SWI_NET_PENDING) 333DO_SETBITS_AND_NO_MORE(schedsofttty, &sdelayed, SWI_TTY_PENDING) 334DO_SETBITS_AND_NO_MORE(schedsoftvm, &sdelayed, SWI_VM_PENDING) 335DO_SETBITS_AND_NO_MORE(schedsofttq, &sdelayed, SWI_TQ_PENDING) 336 337void 338setdelayed(void) 339{ 340 int pend; 341 342 pend = atomic_readandclear_int(&sdelayed); 343 if (pend != 0) { 344 atomic_set_int(&spending, pend); 345 sched_softintr(); 346 } 347} 348 349intrmask_t 350softclockpending(void) 351{ 352 return (spending & SWI_CLOCK_PENDING); 353} 354 355/* 356 * Dummy spl calls. The only reason for these is to not break 357 * all the code which expects to call them. 358 */ 359void spl0 (void) {} 360void splx (intrmask_t x) {} 361intrmask_t splq(intrmask_t mask) { return 0; } 362intrmask_t splbio(void) { return 0; } 363intrmask_t splcam(void) { return 0; } 364intrmask_t splclock(void) { return 0; } 365intrmask_t splhigh(void) { return 0; } 366intrmask_t splimp(void) { return 0; } 367intrmask_t splnet(void) { return 0; } 368intrmask_t splsoftcam(void) { return 0; } 369intrmask_t splsoftcambio(void) { return 0; } 370intrmask_t splsoftcamnet(void) { return 0; } 371intrmask_t splsoftclock(void) { return 0; } 372intrmask_t splsofttty(void) { return 0; } 373intrmask_t splsoftvm(void) { return 0; } 374intrmask_t splsofttq(void) { return 0; } 375intrmask_t splstatclock(void) { return 0; } 376intrmask_t spltty(void) { return 0; } 377intrmask_t splvm(void) { return 0; } 378