1 /* $NetBSD: isr.c,v 1.17 2002/09/27 15:36:32 provos Exp $ */ 2 3 /* 4 * This file was taken from mvme68k/mvme68k/isr.c 5 * should probably be re-synced when needed. 6 * Darrin B. Jewell <jewell@mit.edu> Tue Nov 10 05:07:16 1998 7 * original cvs id: NetBSD: isr.c,v 1.12 1998/07/05 06:49:07 jonathan Exp 8 */ 9 10 /*- 11 * Copyright (c) 1996 The NetBSD Foundation, Inc. 12 * All rights reserved. 13 * 14 * This code is derived from software contributed to The NetBSD Foundation 15 * by Adam Glass, Gordon W. Ross, and Jason R. Thorpe. 16 * 17 * Redistribution and use in source and binary forms, with or without 18 * modification, are permitted provided that the following conditions 19 * are met: 20 * 1. Redistributions of source code must retain the above copyright 21 * notice, this list of conditions and the following disclaimer. 22 * 2. Redistributions in binary form must reproduce the above copyright 23 * notice, this list of conditions and the following disclaimer in the 24 * documentation and/or other materials provided with the distribution. 25 * 3. All advertising materials mentioning features or use of this software 26 * must display the following acknowledgement: 27 * This product includes software developed by the NetBSD 28 * Foundation, Inc. and its contributors. 29 * 4. Neither the name of The NetBSD Foundation nor the names of its 30 * contributors may be used to endorse or promote products derived 31 * from this software without specific prior written permission. 32 * 33 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 34 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 35 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 36 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 37 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 38 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 39 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 40 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 41 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 42 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 43 * POSSIBILITY OF SUCH DAMAGE. 44 */ 45 46 /* 47 * Link and dispatch interrupts. 48 */ 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/malloc.h> 53 #include <sys/vmmeter.h> 54 55 #include <uvm/uvm_extern.h> 56 57 #include <net/netisr.h> 58 59 #include <machine/bus.h> 60 #include <machine/cpu.h> 61 62 #include <next68k/next68k/isr.h> 63 64 #include <next68k/dev/intiovar.h> 65 66 volatile unsigned int interrupt_depth; 67 isr_autovec_list_t isr_autovec[NISRAUTOVEC]; 68 struct isr_vectored isr_vectored[NISRVECTORED]; 69 static const char irqgroupname[] = "hard irqs"; 70 struct evcnt next68k_irq_evcnt[] = { 71 EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, irqgroupname, "spur"), 72 EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, irqgroupname, "lev1"), 73 EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, irqgroupname, "lev2"), 74 EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, irqgroupname, "lev3"), 75 EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, irqgroupname, "lev4"), 76 EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, irqgroupname, "lev5"), 77 EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, irqgroupname, "lev6"), 78 EVCNT_INITIALIZER(EVCNT_TYPE_INTR, NULL, irqgroupname, "nmi") 79 }; 80 81 extern int intrcnt[]; /* from locore.s. XXXSCW: will go away soon */ 82 extern void (*vectab[]) __P((void)); 83 extern void badtrap __P((void)); 84 extern void intrhand_vectored __P((void)); 85 86 #if 0 87 static int spurintr __P((void *)); 88 #endif 89 90 void 91 isrinit() 92 { 93 int i; 94 95 /* Initialize the autovector lists. */ 96 for (i = 0; i < NISRAUTOVEC; ++i) 97 LIST_INIT(&isr_autovec[i]); 98 99 /* Initialise the interrupt event counts */ 100 for (i = 0; i < (sizeof(next68k_irq_evcnt) / sizeof(struct evcnt)); i++) 101 evcnt_attach_static(&next68k_irq_evcnt[i]); 102 103 /* Arrange to trap Spurious and NMI auto-vectored Interrupts */ 104 /* isrlink_autovec(spurintr, NULL, 0, 0, NULL); */ 105 /* isrlink_autovec(nmihand, NULL, 7, 0, NULL); */ 106 } 107 108 /* 109 * Establish an autovectored interrupt handler. 110 * Called by driver attach functions. 111 */ 112 void 113 isrlink_autovec(func, arg, ipl, priority, evcnt) 114 int (*func) __P((void *)); 115 void *arg; 116 int ipl; 117 int priority; 118 struct evcnt *evcnt; 119 { 120 struct isr_autovec *newisr, *curisr; 121 isr_autovec_list_t *list; 122 123 #ifdef DIAGNOSTIC 124 if ((ipl < 0) || (ipl >= NISRAUTOVEC)) 125 panic("isrlink_autovec: bad ipl %d", ipl); 126 #endif 127 128 newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec), 129 M_DEVBUF, M_NOWAIT); 130 if (newisr == NULL) 131 panic("isrlink_autovec: can't allocate space for isr"); 132 133 /* Fill in the new entry. */ 134 newisr->isr_func = func; 135 newisr->isr_arg = arg; 136 newisr->isr_ipl = ipl; 137 newisr->isr_priority = priority; 138 newisr->isr_evcnt = evcnt; 139 140 /* 141 * Some devices are particularly sensitive to interrupt 142 * handling latency. The SCC, for example, can lose many 143 * characters if its interrupt isn't handled with reasonable 144 * speed. 145 * 146 * To work around this problem, each device can give itself a 147 * "priority". An unbuffered SCC would give itself a higher 148 * priority than a SCSI device, for example. 149 * 150 * This solution was originally developed for the hp300, which 151 * has a flat spl scheme (by necessity). Thankfully, the 152 * MVME systems don't have this problem, though this may serve 153 * a useful purpose in any case. 154 */ 155 156 /* 157 * Get the appropriate ISR list. If the list is empty, no 158 * additional work is necessary; we simply insert ourselves 159 * at the head of the list. 160 */ 161 list = &isr_autovec[ipl]; 162 if (list->lh_first == NULL) { 163 LIST_INSERT_HEAD(list, newisr, isr_link); 164 return; 165 } 166 167 /* 168 * A little extra work is required. We traverse the list 169 * and place ourselves after any ISRs with our current (or 170 * higher) priority. 171 */ 172 for (curisr = list->lh_first; curisr->isr_link.le_next != NULL; 173 curisr = curisr->isr_link.le_next) { 174 if (newisr->isr_priority > curisr->isr_priority) { 175 LIST_INSERT_BEFORE(curisr, newisr, isr_link); 176 return; 177 } 178 } 179 180 /* 181 * We're the least important entry, it seems. We just go 182 * on the end. 183 */ 184 LIST_INSERT_AFTER(curisr, newisr, isr_link); 185 } 186 187 /* 188 * Establish a vectored interrupt handler. 189 * Called by bus interrupt establish functions. 190 */ 191 void 192 isrlink_vectored(func, arg, ipl, vec, evcnt) 193 int (*func) __P((void *)); 194 void *arg; 195 int ipl, vec; 196 struct evcnt *evcnt; 197 { 198 struct isr_vectored *isr; 199 200 #ifdef DIAGNOSTIC 201 if ((ipl < 0) || (ipl >= NISRAUTOVEC)) 202 panic("isrlink_vectored: bad ipl %d", ipl); 203 if ((vec < ISRVECTORED) || (vec >= ISRVECTORED + NISRVECTORED)) 204 panic("isrlink_vectored: bad vec 0x%x", vec); 205 #endif 206 207 isr = &isr_vectored[vec - ISRVECTORED]; 208 209 #ifdef DIAGNOSTIC 210 if ((vectab[vec] != badtrap) || (isr->isr_func != NULL)) 211 panic("isrlink_vectored: vec 0x%x not available", vec); 212 #endif 213 214 /* Fill in the new entry. */ 215 isr->isr_func = func; 216 isr->isr_arg = arg; 217 isr->isr_ipl = ipl; 218 isr->isr_evcnt = evcnt; 219 220 /* Hook into the vector table. */ 221 vectab[vec] = intrhand_vectored; 222 } 223 224 /* 225 * Return a pointer to the evcnt structure for 226 * the specified ipl. 227 */ 228 struct evcnt * 229 isrlink_evcnt(ipl) 230 int ipl; 231 { 232 233 #ifdef DIAGNOSTIC 234 if (ipl < 0 || 235 ipl >= (sizeof(next68k_irq_evcnt) / sizeof(struct evcnt))) 236 panic("isrlink_evcnt: bad ipl %d", ipl); 237 #endif 238 239 return (&next68k_irq_evcnt[ipl]); 240 } 241 242 /* 243 * Unhook a vectored interrupt. 244 */ 245 void 246 isrunlink_vectored(vec) 247 int vec; 248 { 249 250 #ifdef DIAGNOSTIC 251 if ((vec < ISRVECTORED) || (vec >= ISRVECTORED + NISRVECTORED)) 252 panic("isrunlink_vectored: bad vec 0x%x", vec); 253 254 if (vectab[vec] != intrhand_vectored) 255 panic("isrunlink_vectored: not vectored interrupt"); 256 #endif 257 258 vectab[vec] = badtrap; 259 memset(&isr_vectored[vec - ISRVECTORED], 0, sizeof(struct isr_vectored)); 260 } 261 262 /* 263 * This is the dispatcher called by the low-level 264 * assembly language autovectored interrupt routine. 265 */ 266 void 267 isrdispatch_autovec(frame) 268 struct clockframe *frame; 269 { 270 struct isr_autovec *isr; 271 isr_autovec_list_t *list; 272 int handled, ipl; 273 void *arg; 274 static int straycount, unexpected; 275 276 ipl = (frame->vec >> 2) - ISRAUTOVEC; 277 278 #ifdef DIAGNOSTIC 279 if ((ipl < 0) || (ipl >= NISRAUTOVEC)) 280 panic("isrdispatch_autovec: bad vec 0x%x", frame->vec); 281 #endif 282 283 intrcnt[ipl]++; /* XXXSCW: Will go away soon */ 284 next68k_irq_evcnt[ipl].ev_count++; 285 uvmexp.intrs++; 286 287 list = &isr_autovec[ipl]; 288 if (list->lh_first == NULL) { 289 printf("isrdispatch_autovec: ipl %d unexpected\n", ipl); 290 if (++unexpected > 10) 291 panic("too many unexpected interrupts"); 292 return; 293 } 294 295 /* Give all the handlers a chance. */ 296 handled = 0; 297 for (isr = list->lh_first ; isr != NULL; isr = isr->isr_link.le_next) { 298 arg = isr->isr_arg ? isr->isr_arg : frame; 299 if ((*isr->isr_func)(arg) != 0) { 300 if (isr->isr_evcnt) 301 isr->isr_evcnt->ev_count++; 302 handled++; 303 } 304 } 305 306 if (handled) 307 straycount = 0; 308 else if (++straycount > 50) 309 panic("isr_dispatch_autovec: too many stray interrupts"); 310 else { 311 char sbuf[256]; 312 313 printf("isrdispatch_autovec: stray level %d interrupt\n", ipl); 314 315 bitmask_snprintf((*(volatile u_long *)IIOV(NEXT_P_INTRSTAT)), 316 NEXT_INTR_BITS, sbuf, sizeof(sbuf)); 317 printf(" *intrstat = 0x%s\n", sbuf); 318 319 bitmask_snprintf((*(volatile u_long *)IIOV(NEXT_P_INTRMASK)), 320 NEXT_INTR_BITS, sbuf, sizeof(sbuf)); 321 printf(" *intrmask = 0x%s\n", sbuf); 322 } 323 } 324 325 /* 326 * This is the dispatcher called by the low-level 327 * assembly language vectored interrupt routine. 328 */ 329 void 330 isrdispatch_vectored(ipl, frame) 331 int ipl; 332 struct clockframe *frame; 333 { 334 struct isr_vectored *isr; 335 int vec; 336 337 vec = (frame->vec >> 2) - ISRVECTORED; 338 339 #ifdef DIAGNOSTIC 340 if ((vec < 0) || (vec >= NISRVECTORED)) 341 panic("isrdispatch_vectored: bad vec 0x%x", frame->vec); 342 #endif 343 344 isr = &isr_vectored[vec]; 345 346 intrcnt[ipl]++; /* XXXSCW: Will go away soon */ 347 next68k_irq_evcnt[ipl].ev_count++; 348 uvmexp.intrs++; 349 350 if (isr->isr_func == NULL) { 351 printf("isrdispatch_vectored: no handler for vec 0x%x\n", 352 frame->vec); 353 vectab[vec + ISRVECTORED] = badtrap; 354 return; 355 } 356 357 /* 358 * Handler gets exception frame if argument is NULL. 359 */ 360 if ((*isr->isr_func)(isr->isr_arg ? isr->isr_arg : frame) == 0) 361 printf("isrdispatch_vectored: vec 0x%x not claimed\n", 362 frame->vec); 363 else 364 if (isr->isr_evcnt) 365 isr->isr_evcnt->ev_count++; 366 } 367 368 /* 369 * netisr junk... 370 * should use an array of chars instead of 371 * a bitmask to avoid atomicity locking issues. 372 */ 373 374 void 375 netintr() 376 { 377 int n, s; 378 379 s = splhigh(); 380 n = netisr; 381 netisr = 0; 382 splx(s); 383 384 #define DONETISR(bit, fn) do { \ 385 if (n & (1 << bit)) \ 386 fn(); \ 387 } while (0) 388 389 s = splsoftnet(); 390 391 #include <net/netisr_dispatch.h> 392 393 #undef DONETISR 394 395 splx(s); 396 } 397 398 #if 0 399 /* ARGSUSED */ 400 static int 401 spurintr(void *arg) 402 { 403 404 return (1); 405 } 406 #endif 407