1 /* $NetBSD: isr.c,v 1.2 2001/11/30 17:47:04 fredette 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 and Gordon W. Ross. 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 * This handles multiple attach of autovectored interrupts, 41 * and the handy software interrupt request register. 42 */ 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/device.h> 47 #include <sys/malloc.h> 48 #include <sys/vmmeter.h> 49 50 #include <uvm/uvm_extern.h> 51 52 #include <net/netisr.h> 53 54 #include <machine/autoconf.h> 55 #include <machine/cpu.h> 56 #include <machine/intr.h> 57 #include <machine/mon.h> 58 59 #include <sun68k/sun68k/vector.h> 60 61 extern int intrcnt[]; /* statistics */ 62 63 #define NUM_LEVELS 8 64 65 struct isr { 66 struct isr *isr_next; 67 isr_func_t isr_intr; 68 void *isr_arg; 69 int isr_ipl; 70 }; 71 72 /* 73 * Generic soft interrupt support. 74 */ 75 struct softintr_head soft_level_heads[(_IPL_SOFT_LEVEL_MAX - _IPL_SOFT_LEVEL_MIN) + 1]; 76 void *softnet_cookie; 77 static int softintr_handler __P((void *)); 78 79 void set_vector_entry __P((int, void *)); 80 void * get_vector_entry __P((int)); 81 82 /* 83 * These are called from locore. The "struct clockframe" arg 84 * is really just the normal H/W interrupt frame format. 85 * (kern_clock really wants it to be named that...) 86 */ 87 void isr_autovec __P((struct clockframe)); 88 void isr_vectored __P((struct clockframe)); 89 90 91 void 92 isr_add_custom(level, handler) 93 int level; 94 void *handler; 95 { 96 set_vector_entry(AUTOVEC_BASE + level, handler); 97 } 98 99 100 /* 101 * netisr junk... 102 * should use an array of chars instead of 103 * a bitmask to avoid atomicity locking issues. 104 */ 105 106 void netintr() 107 { 108 int n, s; 109 110 s = splhigh(); 111 n = netisr; 112 netisr = 0; 113 splx(s); 114 115 #define DONETISR(bit, fn) do { \ 116 if (n & (1 << bit)) \ 117 fn(); \ 118 } while (0) 119 120 #include <net/netisr_dispatch.h> 121 122 #undef DONETISR 123 } 124 125 126 static struct isr *isr_autovec_list[NUM_LEVELS]; 127 128 /* 129 * This is called by the assembly routines 130 * for handling auto-vectored interupts. 131 */ 132 void isr_autovec(cf) 133 struct clockframe cf; 134 { 135 struct isr *isr; 136 int n, ipl, vec; 137 138 vec = (cf.cf_vo & 0xFFF) >> 2; 139 if ((vec < AUTOVEC_BASE) || (vec >= (AUTOVEC_BASE+8))) 140 panic("isr_autovec: bad vec"); 141 ipl = vec - AUTOVEC_BASE; 142 143 n = intrcnt[ipl]; 144 intrcnt[ipl] = n+1; 145 uvmexp.intrs++; 146 147 isr = isr_autovec_list[ipl]; 148 if (isr == NULL) { 149 if (n == 0) 150 printf("isr_autovec: ipl %d unexpected\n", ipl); 151 return; 152 } 153 154 /* Give all the handlers a chance. */ 155 n = 0; 156 while (isr) { 157 n |= isr->isr_intr(isr->isr_arg); 158 isr = isr->isr_next; 159 } 160 if (!n) 161 printf("isr_autovec: ipl %d not claimed\n", ipl); 162 } 163 164 /* 165 * Establish an interrupt handler. 166 * Called by driver attach functions. 167 */ 168 void isr_add_autovect(handler, arg, level) 169 isr_func_t handler; 170 void *arg; 171 int level; 172 { 173 struct isr *new_isr; 174 175 if ((level < 0) || (level >= NUM_LEVELS)) 176 panic("isr_add: bad level=%d", level); 177 new_isr = (struct isr *) 178 malloc(sizeof(struct isr), M_DEVBUF, M_NOWAIT); 179 if (!new_isr) 180 panic("isr_add: malloc failed"); 181 182 new_isr->isr_intr = handler; 183 new_isr->isr_arg = arg; 184 new_isr->isr_ipl = level; 185 new_isr->isr_next = isr_autovec_list[level]; 186 isr_autovec_list[level] = new_isr; 187 } 188 189 struct vector_handler { 190 isr_func_t func; 191 void *arg; 192 }; 193 static struct vector_handler isr_vector_handlers[192]; 194 195 /* 196 * This is called by the assembly glue 197 * for handling vectored interupts. 198 */ 199 void 200 isr_vectored(cf) 201 struct clockframe cf; 202 { 203 struct vector_handler *vh; 204 int ipl, vec; 205 206 vec = (cf.cf_vo & 0xFFF) >> 2; 207 ipl = _getsr(); 208 ipl = (ipl >> 8) & 7; 209 210 intrcnt[ipl]++; 211 uvmexp.intrs++; 212 213 if (vec < 64 || vec >= 256) { 214 printf("isr_vectored: vector=0x%x (invalid)\n", vec); 215 return; 216 } 217 vh = &isr_vector_handlers[vec - 64]; 218 if (vh->func == NULL) { 219 printf("isr_vectored: vector=0x%x (nul func)\n", vec); 220 set_vector_entry(vec, (void *)badtrap); 221 return; 222 } 223 224 /* OK, call the isr function. */ 225 if (vh->func(vh->arg) == 0) 226 printf("isr_vectored: vector=0x%x (not claimed)\n", vec); 227 } 228 229 /* 230 * Establish an interrupt handler. 231 * Called by driver attach functions. 232 */ 233 extern void _isr_vectored __P((void)); 234 void 235 isr_add_vectored(func, arg, level, vec) 236 isr_func_t func; 237 void *arg; 238 int level, vec; 239 { 240 struct vector_handler *vh; 241 242 if (vec < 64 || vec >= 256) { 243 printf("isr_add_vectored: vect=0x%x (invalid)\n", vec); 244 return; 245 } 246 vh = &isr_vector_handlers[vec - 64]; 247 if (vh->func) { 248 printf("isr_add_vectored: vect=0x%x (in use)\n", vec); 249 return; 250 } 251 vh->func = func; 252 vh->arg = arg; 253 set_vector_entry(vec, (void *)_isr_vectored); 254 } 255 256 /* 257 * Generic soft interrupt support. 258 */ 259 260 /* 261 * The soft interrupt handler. 262 */ 263 static int 264 softintr_handler(void *arg) 265 { 266 struct softintr_head *shd = arg; 267 struct softintr_handler *sh; 268 269 /* Clear the interrupt. */ 270 isr_soft_clear(shd->shd_ipl); 271 uvmexp.softs++; 272 273 /* Dispatch any pending handlers. */ 274 for(sh = LIST_FIRST(&shd->shd_intrs); sh != NULL; sh = LIST_NEXT(sh, sh_link)) { 275 if (sh->sh_pending) { 276 (*sh->sh_func)(sh->sh_arg); 277 sh->sh_pending = 0; 278 } 279 } 280 281 return (1); 282 } 283 284 /* 285 * This initializes soft interrupts. 286 */ 287 void 288 softintr_init(void) 289 { 290 int ipl; 291 struct softintr_head *shd; 292 293 for(ipl = _IPL_SOFT_LEVEL_MIN; ipl <= _IPL_SOFT_LEVEL_MAX; ipl++) { 294 shd = &soft_level_heads[ipl - _IPL_SOFT_LEVEL_MIN]; 295 shd->shd_ipl = ipl; 296 LIST_INIT(&shd->shd_intrs); 297 isr_add_autovect(softintr_handler, shd, ipl); 298 } 299 300 softnet_cookie = softintr_establish(IPL_SOFTNET, (void (*) __P((void *))) netintr, NULL); 301 } 302 303 /* 304 * This establishes a soft interrupt handler. 305 */ 306 void * 307 softintr_establish(int ipl, void (*func)(void *), void *arg) 308 { 309 struct softintr_handler *sh; 310 struct softintr_head *shd; 311 312 if (ipl < _IPL_SOFT_LEVEL_MIN || ipl > _IPL_SOFT_LEVEL_MAX) 313 panic("softintr_establish: unsupported soft IPL"); 314 315 shd = &soft_level_heads[ipl - _IPL_SOFT_LEVEL_MIN]; 316 317 sh = malloc(sizeof(*sh), M_SOFTINTR, M_NOWAIT); 318 if (sh == NULL) 319 return NULL; 320 321 LIST_INSERT_HEAD(&shd->shd_intrs, sh, sh_link); 322 sh->sh_head = shd; 323 sh->sh_pending = 0; 324 sh->sh_func = func; 325 sh->sh_arg = arg; 326 327 return sh; 328 } 329 330 /* 331 * This disestablishes a soft interrupt handler. 332 */ 333 void 334 softintr_disestablish(void *arg) 335 { 336 struct softintr_handler *sh = arg; 337 LIST_REMOVE(sh, sh_link); 338 free(sh, M_SOFTINTR); 339 } 340 341 342 /* 343 * XXX - could just kill these... 344 */ 345 void 346 set_vector_entry(entry, handler) 347 int entry; 348 void *handler; 349 { 350 if ((entry <0) || (entry >= NVECTORS)) 351 panic("set_vector_entry: setting vector too high or low\n"); 352 vector_table[entry] = handler; 353 } 354 355 void * 356 get_vector_entry(entry) 357 int entry; 358 { 359 if ((entry <0) || (entry >= NVECTORS)) 360 panic("get_vector_entry: setting vector too high or low\n"); 361 return ((void *) vector_table[entry]); 362 } 363