1 /* $NetBSD: isr.c,v 1.7 2001/07/07 06:24:00 tsutsui 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 * from mvme68k/mvme68k/isr.c and sun3/sun3/isr.c 41 * This should be in /sys/arch/m68k/m68k? 42 */ 43 44 /* 45 * Link and dispatch interrupts. 46 */ 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/malloc.h> 51 52 #include <uvm/uvm_extern.h> 53 54 #include <net/netisr.h> 55 56 #include <machine/cpu.h> 57 58 #include <news68k/news68k/isr.h> 59 60 isr_autovec_list_t isr_autovec[NISRAUTOVEC]; 61 struct isr_vectored isr_vectored[NISRVECTORED]; 62 63 void set_vector_entry __P((int, void *)); 64 void * get_vector_entry __P((int)); 65 66 void 67 isrinit() 68 { 69 int i; 70 71 /* Initialize the autovector lists. */ 72 for (i = 0; i < NISRAUTOVEC; ++i) { 73 LIST_INIT(&isr_autovec[i]); 74 } 75 } 76 77 /* 78 * Establish an autovectored interrupt handler. 79 * Called by driver attach functions. 80 */ 81 void 82 isrlink_autovec(func, arg, ipl, priority) 83 int (*func) __P((void *)); 84 void *arg; 85 int ipl; 86 int priority; 87 { 88 struct isr_autovec *newisr, *curisr; 89 isr_autovec_list_t *list; 90 91 if ((ipl < 0) || (ipl >= NISRAUTOVEC)) 92 panic("isrlink_autovec: bad ipl %d", ipl); 93 94 newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec), 95 M_DEVBUF, M_NOWAIT); 96 if (newisr == NULL) 97 panic("isrlink_autovec: can't allocate space for isr"); 98 99 /* Fill in the new entry. */ 100 newisr->isr_func = func; 101 newisr->isr_arg = arg; 102 newisr->isr_ipl = ipl; 103 newisr->isr_priority = priority; 104 105 /* 106 * Some devices are particularly sensitive to interrupt 107 * handling latency. The SCC, for example, can lose many 108 * characters if its interrupt isn't handled with reasonable 109 * speed. 110 * 111 * To work around this problem, each device can give itself a 112 * "priority". An unbuffered SCC would give itself a higher 113 * priority than a SCSI device, for example. 114 * 115 * This solution was originally developed for the hp300, which 116 * has a flat spl scheme (by necessity). Thankfully, the 117 * MVME systems don't have this problem, though this may serve 118 * a useful purpose in any case. 119 */ 120 121 /* 122 * Get the appropriate ISR list. If the list is empty, no 123 * additional work is necessary; we simply insert ourselves 124 * at the head of the list. 125 */ 126 list = &isr_autovec[ipl]; 127 if (list->lh_first == NULL) { 128 LIST_INSERT_HEAD(list, newisr, isr_link); 129 return; 130 } 131 132 /* 133 * A little extra work is required. We traverse the list 134 * and place ourselves after any ISRs with our current (or 135 * higher) priority. 136 */ 137 for (curisr = list->lh_first; curisr->isr_link.le_next != NULL; 138 curisr = curisr->isr_link.le_next) { 139 if (newisr->isr_priority > curisr->isr_priority) { 140 LIST_INSERT_BEFORE(curisr, newisr, isr_link); 141 return; 142 } 143 } 144 145 /* 146 * We're the least important entry, it seems. We just go 147 * on the end. 148 */ 149 LIST_INSERT_AFTER(curisr, newisr, isr_link); 150 } 151 152 /* 153 * Establish a vectored interrupt handler. 154 * Called by bus interrupt establish functions. 155 */ 156 void 157 isrlink_vectored(func, arg, ipl, vec) 158 int (*func) __P((void *)); 159 void *arg; 160 int ipl, vec; 161 { 162 struct isr_vectored *isr; 163 164 if ((ipl < 0) || (ipl >= NISRAUTOVEC)) 165 panic("isrlink_vectored: bad ipl %d", ipl); 166 if ((vec < ISRVECTORED) || (vec >= ISRVECTORED + NISRVECTORED)) 167 panic("isrlink_vectored: bad vec 0x%x", vec); 168 169 isr = &isr_vectored[vec - ISRVECTORED]; 170 171 if ((vectab[vec] != badtrap) || (isr->isr_func != NULL)) 172 panic("isrlink_vectored: vec 0x%x not available", vec); 173 174 /* Fill in the new entry. */ 175 isr->isr_func = func; 176 isr->isr_arg = arg; 177 isr->isr_ipl = ipl; 178 179 /* Hook into the vector table. */ 180 vectab[vec] = intrhand_vectored; 181 } 182 183 /* 184 * Unhook a vectored interrupt. 185 */ 186 void 187 isrunlink_vectored(vec) 188 int vec; 189 { 190 191 if ((vec < ISRVECTORED) || (vec >= ISRVECTORED + NISRVECTORED)) 192 panic("isrunlink_vectored: bad vec 0x%x", vec); 193 194 if (vectab[vec] != intrhand_vectored) 195 panic("isrunlink_vectored: not vectored interrupt"); 196 197 vectab[vec] = badtrap; 198 memset(&isr_vectored[vec - ISRVECTORED], 0, 199 sizeof(struct isr_vectored)); 200 } 201 202 /* 203 * This is the dispatcher called by the low-level 204 * assembly language autovectored interrupt routine. 205 */ 206 void 207 isrdispatch_autovec(evec) 208 int evec; /* format | vector offset */ 209 { 210 struct isr_autovec *isr; 211 isr_autovec_list_t *list; 212 int handled = 0, ipl, vec; 213 static int straycount, unexpected; 214 215 vec = (evec & 0xfff) >> 2; 216 if ((vec < ISRAUTOVEC) || (vec >= (ISRAUTOVEC + NISRAUTOVEC))) 217 panic("isrdispatch_autovec: bad vec 0x%x\n", vec); 218 ipl = vec - ISRAUTOVEC; 219 220 intrcnt[ipl]++; 221 uvmexp.intrs++; 222 223 list = &isr_autovec[ipl]; 224 if (list->lh_first == NULL) { 225 printf("isrdispatch_autovec: ipl %d unexpected\n", ipl); 226 if (++unexpected > 10) 227 panic("too many unexpected interrupts"); 228 return; 229 } 230 231 /* Give all the handlers a chance. */ 232 for (isr = list->lh_first ; isr != NULL; isr = isr->isr_link.le_next) 233 handled |= (*isr->isr_func)(isr->isr_arg); 234 235 if (handled) 236 straycount = 0; 237 else if (++straycount > 50) 238 panic("isr_dispatch_autovec: too many stray interrupts"); 239 else 240 printf("isrdispatch_autovec: stray level %d interrupt\n", ipl); 241 } 242 243 /* 244 * This is the dispatcher called by the low-level 245 * assembly language vectored interrupt routine. 246 */ 247 void 248 isrdispatch_vectored(pc, evec, frame) 249 int pc, evec; 250 void *frame; 251 { 252 struct isr_vectored *isr; 253 int ipl, vec; 254 255 vec = (evec & 0xfff) >> 2; 256 ipl = (getsr() >> 8) & 7; 257 258 intrcnt[ipl]++; 259 uvmexp.intrs++; 260 261 if ((vec < ISRVECTORED) || (vec >= (ISRVECTORED + NISRVECTORED))) 262 panic("isrdispatch_vectored: bad vec 0x%x\n", vec); 263 isr = &isr_vectored[vec - ISRVECTORED]; 264 265 if (isr->isr_func == NULL) { 266 printf("isrdispatch_vectored: no handler for vec 0x%x\n", vec); 267 vectab[vec] = badtrap; 268 return; 269 } 270 271 /* 272 * Handler gets exception frame if argument is NULL. 273 */ 274 if ((*isr->isr_func)(isr->isr_arg ? isr->isr_arg : frame) == 0) 275 printf("isrdispatch_vectored: vec 0x%x not claimed\n", vec); 276 } 277 278 void 279 isrlink_custom(level, handler) 280 int level; 281 void *handler; 282 { 283 set_vector_entry(ISRAUTOVEC + level, handler); 284 } 285 286 /* 287 * XXX - could just kill these... [from sun3] 288 */ 289 void 290 set_vector_entry(entry, handler) 291 int entry; 292 void *handler; 293 { 294 if ((entry < 0) || (entry >= NVECTORS)) 295 panic("set_vector_entry: setting vector too high or low\n"); 296 vectab[entry] = handler; 297 } 298 299 void * 300 get_vector_entry(entry) 301 int entry; 302 { 303 if ((entry < 0) || (entry >= NVECTORS)) 304 panic("get_vector_entry: setting vector too high or low\n"); 305 return ((void *) vectab[entry]); 306 } 307 308 void 309 netintr() 310 { 311 int s, isr; 312 313 s = splnet(); 314 isr = netisr; 315 netisr = 0; 316 splx(s); 317 318 #define DONETISR(bit, fn) do { \ 319 if (isr & (1 << bit)) { \ 320 fn(); \ 321 } \ 322 } while (0) 323 324 #include <net/netisr_dispatch.h> 325 326 #undef DONETISR 327 328 } 329