1 /* $NetBSD: isr.c,v 1.20 2010/12/20 00:25:36 matt 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 * 19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 29 * POSSIBILITY OF SUCH DAMAGE. 30 */ 31 32 #include <sys/cdefs.h> /* RCS ID & Copyright macro defns */ 33 34 __KERNEL_RCSID(0, "$NetBSD: isr.c,v 1.20 2010/12/20 00:25:36 matt Exp $"); 35 36 /* 37 * Link and dispatch interrupts. 38 */ 39 40 #include <sys/param.h> 41 #include <sys/systm.h> 42 #include <sys/malloc.h> 43 #include <sys/vmmeter.h> 44 #include <sys/cpu.h> 45 46 #include <uvm/uvm_extern.h> 47 48 #include <luna68k/luna68k/isr.h> 49 50 isr_autovec_list_t isr_autovec[NISRAUTOVEC]; 51 struct isr_vectored isr_vectored[NISRVECTORED]; 52 int idepth; 53 volatile int ssir; 54 55 extern int intrcnt[]; /* from locore.s */ 56 extern void (*vectab[])(void); 57 extern void badtrap(void); 58 extern void intrhand_vectored(void); 59 60 extern int getsr(void); /* in locore.s */ 61 62 void 63 isrinit(void) 64 { 65 int i; 66 67 /* Initialize the autovector lists. */ 68 for (i = 0; i < NISRAUTOVEC; ++i) { 69 LIST_INIT(&isr_autovec[i]); 70 } 71 } 72 73 /* 74 * Establish an autovectored interrupt handler. 75 * Called by driver attach functions. 76 */ 77 void 78 isrlink_autovec(int (*func)(void *), void *arg, int ipl, int priority) 79 { 80 struct isr_autovec *newisr, *curisr; 81 isr_autovec_list_t *list; 82 83 if ((ipl < 0) || (ipl >= NISRAUTOVEC)) 84 panic("isrlink_autovec: bad ipl %d", ipl); 85 86 newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec), 87 M_DEVBUF, M_NOWAIT); 88 if (newisr == NULL) 89 panic("isrlink_autovec: can't allocate space for isr"); 90 91 /* Fill in the new entry. */ 92 newisr->isr_func = func; 93 newisr->isr_arg = arg; 94 newisr->isr_ipl = ipl; 95 newisr->isr_priority = priority; 96 97 /* 98 * Some devices are particularly sensitive to interrupt 99 * handling latency. The SCC, for example, can lose many 100 * characters if its interrupt isn't handled with reasonable 101 * speed. 102 * 103 * To work around this problem, each device can give itself a 104 * "priority". An unbuffered SCC would give itself a higher 105 * priority than a SCSI device, for example. 106 * 107 * This solution was originally developed for the hp300, which 108 * has a flat spl scheme (by necessity). Thankfully, the 109 * MVME systems don't have this problem, though this may serve 110 * a useful purpose in any case. 111 */ 112 113 /* 114 * Get the appropriate ISR list. If the list is empty, no 115 * additional work is necessary; we simply insert ourselves 116 * at the head of the list. 117 */ 118 list = &isr_autovec[ipl]; 119 if (list->lh_first == NULL) { 120 LIST_INSERT_HEAD(list, newisr, isr_link); 121 return; 122 } 123 124 /* 125 * A little extra work is required. We traverse the list 126 * and place ourselves after any ISRs with our current (or 127 * higher) priority. 128 */ 129 for (curisr = list->lh_first; curisr->isr_link.le_next != NULL; 130 curisr = curisr->isr_link.le_next) { 131 if (newisr->isr_priority > curisr->isr_priority) { 132 LIST_INSERT_BEFORE(curisr, newisr, isr_link); 133 return; 134 } 135 } 136 137 /* 138 * We're the least important entry, it seems. We just go 139 * on the end. 140 */ 141 LIST_INSERT_AFTER(curisr, newisr, isr_link); 142 } 143 144 /* 145 * Establish a vectored interrupt handler. 146 * Called by bus interrupt establish functions. 147 */ 148 void 149 isrlink_vectored(int (*func)(void *), void *arg, int ipl, int vec) 150 { 151 struct isr_vectored *isr; 152 153 if ((ipl < 0) || (ipl >= NISRAUTOVEC)) 154 panic("isrlink_vectored: bad ipl %d", ipl); 155 if ((vec < ISRVECTORED) || (vec >= ISRVECTORED + NISRVECTORED)) 156 panic("isrlink_vectored: bad vec 0x%x", vec); 157 158 isr = &isr_vectored[vec - ISRVECTORED]; 159 160 if ((vectab[vec] != badtrap) || (isr->isr_func != NULL)) 161 panic("isrlink_vectored: vec 0x%x not available", vec); 162 163 /* Fill in the new entry. */ 164 isr->isr_func = func; 165 isr->isr_arg = arg; 166 isr->isr_ipl = ipl; 167 168 /* Hook into the vector table. */ 169 vectab[vec] = intrhand_vectored; 170 } 171 172 /* 173 * Unhook a vectored interrupt. 174 */ 175 void 176 isrunlink_vectored(int vec) 177 { 178 179 if ((vec < ISRVECTORED) || (vec >= ISRVECTORED + NISRVECTORED)) 180 panic("isrunlink_vectored: bad vec 0x%x", vec); 181 182 if (vectab[vec] != intrhand_vectored) 183 panic("isrunlink_vectored: not vectored interrupt"); 184 185 vectab[vec] = badtrap; 186 memset(&isr_vectored[vec - ISRVECTORED], 0, sizeof(struct isr_vectored)); 187 } 188 189 /* 190 * This is the dispatcher called by the low-level 191 * assembly language autovectored interrupt routine. 192 */ 193 void 194 isrdispatch_autovec(int evec) 195 /* evec: format | vector offset */ 196 { 197 struct isr_autovec *isr; 198 isr_autovec_list_t *list; 199 int handled = 0, ipl, vec; 200 static int straycount, unexpected; 201 202 idepth++; 203 vec = (evec & 0xfff) >> 2; 204 if ((vec < ISRAUTOVEC) || (vec >= (ISRAUTOVEC + NISRAUTOVEC))) 205 panic("isrdispatch_autovec: bad vec 0x%x", vec); 206 ipl = vec - ISRAUTOVEC; 207 208 intrcnt[ipl]++; 209 curcpu()->ci_data.cpu_nintr++; 210 211 list = &isr_autovec[ipl]; 212 if (list->lh_first == NULL) { 213 printf("isrdispatch_autovec: ipl %d unexpected\n", ipl); 214 if (++unexpected > 10) 215 panic("too many unexpected interrupts"); 216 idepth--; 217 return; 218 } 219 220 /* Give all the handlers a chance. */ 221 for (isr = list->lh_first ; isr != NULL; isr = isr->isr_link.le_next) 222 handled |= (*isr->isr_func)(isr->isr_arg); 223 224 if (handled) 225 straycount = 0; 226 else if (++straycount > 50) 227 panic("isr_dispatch_autovec: too many stray interrupts"); 228 else 229 printf("isrdispatch_autovec: stray level %d interrupt\n", ipl); 230 idepth--; 231 } 232 233 /* 234 * This is the dispatcher called by the low-level 235 * assembly language vectored interrupt routine. 236 */ 237 void 238 isrdispatch_vectored(int pc, int evec, void *frame) 239 { 240 struct isr_vectored *isr; 241 int ipl, vec; 242 243 idepth++; 244 vec = (evec & 0xfff) >> 2; 245 ipl = (getsr() >> 8) & 7; 246 247 intrcnt[ipl]++; 248 curcpu()->ci_data.cpu_nintr++; 249 250 if ((vec < ISRVECTORED) || (vec >= (ISRVECTORED + NISRVECTORED))) 251 panic("isrdispatch_vectored: bad vec 0x%x", vec); 252 isr = &isr_vectored[vec - ISRVECTORED]; 253 254 if (isr->isr_func == NULL) { 255 printf("isrdispatch_vectored: no handler for vec 0x%x\n", vec); 256 vectab[vec] = badtrap; 257 idepth--; 258 return; 259 } 260 261 /* 262 * Handler gets exception frame if argument is NULL. 263 */ 264 if ((*isr->isr_func)(isr->isr_arg ? isr->isr_arg : frame) == 0) 265 printf("isrdispatch_vectored: vec 0x%x not claimed\n", vec); 266 idepth--; 267 } 268 269 bool 270 cpu_intr_p(void) 271 { 272 273 return idepth != 0; 274 } 275 276 const uint16_t ipl2psl_table[NIPL] = { 277 [IPL_NONE] = PSL_S|PSL_IPL0, 278 [IPL_SOFTCLOCK] = PSL_S|PSL_IPL1, 279 [IPL_SOFTBIO] = PSL_S|PSL_IPL1, 280 [IPL_SOFTNET] = PSL_S|PSL_IPL1, 281 [IPL_SOFTSERIAL] = PSL_S|PSL_IPL1, 282 [IPL_VM] = PSL_S|PSL_IPL7, 283 [IPL_SCHED] = PSL_S|PSL_IPL7, 284 [IPL_HIGH] = PSL_S|PSL_IPL7, 285 }; 286