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