1 /* $NetBSD: intr.c,v 1.8 2000/06/29 08:28:23 mrg 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, Jason R. Thorpe, and Leo Weppelman. 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 #include <sys/param.h> 40 #include <sys/systm.h> 41 #include <sys/kernel.h> 42 #include <sys/malloc.h> 43 #include <sys/vmmeter.h> 44 #include <sys/queue.h> 45 #include <sys/device.h> 46 47 #include <uvm/uvm_extern.h> 48 49 #include <machine/cpu.h> 50 51 #include <atari/atari/intr.h> 52 53 #define AVEC_MIN 1 54 #define AVEC_MAX 7 55 #define AVEC_LOC 25 56 #define UVEC_MIN 0 57 #define UVEC_MAX 191 58 #define UVEC_LOC 64 59 60 typedef LIST_HEAD(, intrhand) ih_list_t; 61 ih_list_t autovec_list[AVEC_MAX - AVEC_MIN + 1]; 62 ih_list_t uservec_list[UVEC_MAX - UVEC_MIN + 1]; 63 64 void 65 intr_init() 66 { 67 int i; 68 69 for (i = 0; i < (AVEC_MAX - AVEC_MIN + 1); ++i) { 70 LIST_INIT(&autovec_list[i]); 71 } 72 for (i = 0; i < (UVEC_MAX - UVEC_MIN + 1); ++i) { 73 LIST_INIT(&uservec_list[i]); 74 } 75 } 76 77 /* 78 * Establish an interrupt vector. 79 * - vector 80 * The vector numer the interrupt should be hooked on. It can either 81 * be an auto-vector or a user-vector. 82 * - type 83 * A bit-wise of: 84 * - AUTO_VEC (mutually exclusive with USER_VEC) 85 * Attach to one of the 7 auto vectors 86 * - USER_VEC (mutually exclusive with AUTO_VEC) 87 * Attach to one of the 192 user vectors 88 * - FAST_VEC 89 * The interrupt function 'ih_fun' will be 90 * put into the 'real' interrupt table. This 91 * means: 92 * - This vector can't be shared 93 * - 'ih_fun' must save registers 94 * - 'ih_fun' must do it's own interrupt accounting 95 * - The argument to 'ih_fun' is a standard 96 * interrupt frame. 97 * - ARG_CLOCKRAME 98 * The 'ih_fun' function will be called with 99 * a standard clock-frame instead of 'ih_arg'. 100 * 101 * - pri 102 * When multiple interrupts are established on the same vector, 103 * interrupts with the highest priority will be called first. The 104 * basic ordering is the order of establishment. 105 * - ih_fun 106 * The interrupt function to be called 107 * - ih_arg 108 * The argument given to 'ih_fun' when ARG_CLOCKFRAME is not 109 * specified. 110 */ 111 112 struct intrhand * 113 intr_establish(vector, type, pri, ih_fun, ih_arg) 114 void *ih_arg; 115 int vector; 116 int type; 117 int pri; 118 hw_ifun_t ih_fun; 119 { 120 struct intrhand *ih, *cur_vec; 121 ih_list_t *vec_list; 122 u_long *hard_vec; 123 int s; 124 125 /* no point in sleeping unless someone can free memory. */ 126 ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK); 127 if (ih == NULL) 128 panic("intr_establish: can't malloc handler info"); 129 130 /* 131 * Initialize vector info 132 */ 133 ih->ih_fun = ih_fun; 134 ih->ih_arg = ih_arg; 135 ih->ih_type = type; 136 ih->ih_pri = pri; 137 ih->ih_vector = vector; 138 139 /* 140 * Do some validity checking on the 'vector' argument and determine 141 * vector list this interrupt should be on. 142 */ 143 switch(type & (AUTO_VEC|USER_VEC)) { 144 case AUTO_VEC: 145 if (vector < AVEC_MIN || vector > AVEC_MAX) 146 return (NULL); 147 vec_list = &autovec_list[vector-1]; 148 hard_vec = &autovects[vector-1]; 149 ih->ih_intrcnt = &intrcnt_auto[vector-1]; 150 break; 151 case USER_VEC: 152 if (vector < UVEC_MIN || vector > UVEC_MAX) 153 return (NULL); 154 vec_list = &uservec_list[vector]; 155 hard_vec = &uservects[vector]; 156 ih->ih_intrcnt = &intrcnt_user[vector]; 157 break; 158 default: 159 printf("intr_establish: bogus vector type\n"); 160 free(ih, M_DEVBUF); 161 return(NULL); 162 } 163 164 /* 165 * If the vec_list is empty, we insert ourselves at the head of the 166 * list and we re-route the 'hard-vector' to the appropriate handler. 167 */ 168 if (vec_list->lh_first == NULL) { 169 170 s = splhigh(); 171 LIST_INSERT_HEAD(vec_list, ih, ih_link); 172 if (type & FAST_VEC) 173 *hard_vec = (u_long)ih->ih_fun; 174 else if(*hard_vec != (u_long)intr_glue) { 175 /* 176 * Normally, all settable vectors are already 177 * re-routed to the intr_glue() function. The 178 * marvelous exeption to these are the HBL/VBL 179 * interrupts. They happen *very* often and 180 * can't be turned off on the Falcon. So they 181 * are normally vectored to an 'rte' instruction. 182 */ 183 *hard_vec = (u_long)intr_glue; 184 } 185 186 splx(s); 187 188 return ih; 189 } 190 191 /* 192 * Check for FAST_VEC botches 193 */ 194 cur_vec = vec_list->lh_first; 195 if (cur_vec->ih_type & FAST_VEC) { 196 free(ih, M_DEVBUF); 197 printf("intr_establish: vector cannot be shared\n"); 198 return (NULL); 199 } 200 201 /* 202 * We traverse the list and place ourselves after any handlers with 203 * our current (or higher) priority level. 204 */ 205 for (cur_vec = vec_list->lh_first; cur_vec->ih_link.le_next != NULL; 206 cur_vec = cur_vec->ih_link.le_next) { 207 if (ih->ih_pri > cur_vec->ih_pri) { 208 209 s = splhigh(); 210 LIST_INSERT_BEFORE(cur_vec, ih, ih_link); 211 splx(s); 212 213 return (ih); 214 } 215 } 216 217 /* 218 * We're the least important entry, it seems. We just go 219 * on the end. 220 */ 221 s = splhigh(); 222 LIST_INSERT_AFTER(cur_vec, ih, ih_link); 223 splx(s); 224 225 return ih; 226 } 227 228 int 229 intr_disestablish(ih) 230 struct intrhand *ih; 231 { 232 ih_list_t *vec_list; 233 u_long *hard_vec; 234 int vector, s; 235 struct intrhand *cur_vec; 236 237 vector = ih->ih_vector; 238 switch(ih->ih_type & (AUTO_VEC|USER_VEC)) { 239 case AUTO_VEC: 240 if (vector < AVEC_MIN || vector > AVEC_MAX) 241 return 0; 242 vec_list = &autovec_list[vector-1]; 243 hard_vec = &autovects[vector-1]; 244 break; 245 case USER_VEC: 246 if (vector < UVEC_MIN || vector > UVEC_MAX) 247 return 0; 248 vec_list = &uservec_list[vector]; 249 hard_vec = &uservects[vector]; 250 break; 251 default: 252 printf("intr_disestablish: bogus vector type\n"); 253 return 0; 254 } 255 256 /* 257 * Check if the vector is really in the list we think it's in.... 258 */ 259 for (cur_vec = vec_list->lh_first; cur_vec->ih_link.le_next != NULL; 260 cur_vec = cur_vec->ih_link.le_next) { 261 if (ih == cur_vec) 262 break; 263 } 264 if (ih != cur_vec) { 265 printf("intr_disestablish: 'ih' has inconsistent data\n"); 266 return 0; 267 } 268 269 s = splhigh(); 270 LIST_REMOVE(ih, ih_link); 271 if ((vec_list->lh_first == NULL) && (ih->ih_type & FAST_VEC)) 272 *hard_vec = (u_long)intr_glue; 273 splx(s); 274 275 free(ih, M_DEVBUF); 276 return 1; 277 } 278 279 /* 280 * This is the dispatcher called by the low-level 281 * assembly language interrupt-glue routine. 282 */ 283 void 284 intr_dispatch(frame) 285 struct clockframe frame; 286 { 287 static int unexpected, straycount; 288 int vector; 289 int handled = 0; 290 ih_list_t *vec_list; 291 struct intrhand *ih; 292 293 uvmexp.intrs++; 294 vector = (frame.cf_vo & 0xfff) >> 2; 295 if (vector < (AVEC_LOC+AVEC_MAX) && vector >= AVEC_LOC) 296 vec_list = &autovec_list[vector - AVEC_LOC]; 297 else if (vector <= (UVEC_LOC+UVEC_MAX) && vector >= UVEC_LOC) 298 vec_list = &uservec_list[vector - UVEC_LOC]; 299 else panic("intr_dispatch: Bogus vector %d\n", vector); 300 301 if ((ih = vec_list->lh_first) == NULL) { 302 printf("intr_dispatch: vector %d unexpected\n", vector); 303 if (++unexpected > 10) 304 panic("intr_dispatch: too many unexpected interrupts"); 305 return; 306 } 307 ih->ih_intrcnt[0]++; 308 309 /* Give all the handlers a chance. */ 310 for ( ; ih != NULL; ih = ih->ih_link.le_next) 311 handled |= (*ih->ih_fun)((ih->ih_type & ARG_CLOCKFRAME) 312 ? &frame : ih->ih_arg, frame.cf_sr); 313 314 if (handled) 315 straycount = 0; 316 else if (++straycount > 50) 317 panic("intr_dispatch: too many stray interrupts"); 318 else 319 printf("intr_dispatch: stray level %d interrupt\n", vector); 320 } 321