1 /* $NetBSD: intr.c,v 1.17 2001/04/12 18:26:26 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1996, 1997 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 #include <machine/intr.h> 54 55 #include <machine/psc.h> 56 #include <machine/viareg.h> 57 58 #define NISR 8 59 #define ISRLOC 0x18 60 61 static int intr_noint __P((void *)); 62 void netintr __P((void)); 63 64 static int ((*intr_func[NISR]) __P((void *))) = { 65 intr_noint, 66 intr_noint, 67 intr_noint, 68 intr_noint, 69 intr_noint, 70 intr_noint, 71 intr_noint, 72 intr_noint 73 }; 74 static void *intr_arg[NISR] = { 75 (void *)0, 76 (void *)1, 77 (void *)2, 78 (void *)3, 79 (void *)4, 80 (void *)5, 81 (void *)6, 82 (void *)7 83 }; 84 85 #ifdef DEBUG 86 int intr_debug = 0; 87 #endif 88 89 /* 90 * Some of the below are not used yet, but might be used someday on the 91 * IIfx/Q700/900/950/etc. where the interrupt controller may be reprogrammed 92 * to interrupt on different levels as listed in locore.s 93 */ 94 u_short mac68k_ipls[MAC68K_NIPLS]; 95 96 extern int intrcnt[]; /* from locore.s */ 97 98 void intr_computeipl __P((void)); 99 100 #define MAX_INAME_LENGTH 53 101 #define STD_INAMES \ 102 "spur\0via1\0via2\0unused1\0scc\0unused2\0unused3\0nmi\0clock\0" 103 #define AUX_INAMES \ 104 "spur\0soft\0via2\0ethernet\0scc\0sound\0via1\0nmi\0clock\0 " 105 #define AV_INAMES \ 106 "spur\0via1\0via2\0ethernet\0scc\0dsp\0unused1\0nmi\0clock\0 " 107 108 void 109 intr_init() 110 { 111 extern long intrnames; 112 char *inames, *g_inames; 113 114 mac68k_ipls[MAC68K_IPL_SOFT] = PSL_S|PSL_IPL1; 115 mac68k_ipls[MAC68K_IPL_SERIAL] = PSL_S|PSL_IPL4; 116 mac68k_ipls[MAC68K_IPL_HIGH] = PSL_S|PSL_IPL7; 117 118 g_inames = (char *) &intrnames; 119 if (mac68k_machine.aux_interrupts) { 120 inames = AUX_INAMES; 121 122 /* Standard spl(9) interrupt priorities */ 123 mac68k_ipls[MAC68K_IPL_BIO] = (PSL_S | PSL_IPL2); 124 mac68k_ipls[MAC68K_IPL_NET] = (PSL_S | PSL_IPL3); 125 mac68k_ipls[MAC68K_IPL_TTY] = (PSL_S | PSL_IPL1); 126 mac68k_ipls[MAC68K_IPL_IMP] = (PSL_S | PSL_IPL6); 127 mac68k_ipls[MAC68K_IPL_STATCLOCK] = (PSL_S | PSL_IPL6); 128 mac68k_ipls[MAC68K_IPL_CLOCK] = (PSL_S | PSL_IPL6); 129 mac68k_ipls[MAC68K_IPL_SCHED] = (PSL_S | PSL_IPL6); 130 131 /* Non-standard interrupt priorities */ 132 mac68k_ipls[MAC68K_IPL_ADB] = (PSL_S | PSL_IPL6); 133 mac68k_ipls[MAC68K_IPL_AUDIO] = (PSL_S | PSL_IPL5); 134 135 } else { 136 inames = STD_INAMES; 137 138 /* Standard spl(9) interrupt priorities */ 139 mac68k_ipls[MAC68K_IPL_BIO] = (PSL_S | PSL_IPL2); 140 mac68k_ipls[MAC68K_IPL_NET] = (PSL_S | PSL_IPL2); 141 mac68k_ipls[MAC68K_IPL_TTY] = (PSL_S | PSL_IPL1); 142 mac68k_ipls[MAC68K_IPL_IMP] = (PSL_S | PSL_IPL2); 143 mac68k_ipls[MAC68K_IPL_STATCLOCK] = (PSL_S | PSL_IPL2); 144 mac68k_ipls[MAC68K_IPL_CLOCK] = (PSL_S | PSL_IPL2); 145 mac68k_ipls[MAC68K_IPL_SCHED] = (PSL_S | PSL_IPL3); 146 147 /* Non-standard interrupt priorities */ 148 mac68k_ipls[MAC68K_IPL_ADB] = (PSL_S | PSL_IPL1); 149 mac68k_ipls[MAC68K_IPL_AUDIO] = (PSL_S | PSL_IPL2); 150 151 if (current_mac_model->class == MACH_CLASSAV) { 152 inames = AV_INAMES; 153 mac68k_ipls[MAC68K_IPL_BIO] = 154 mac68k_ipls[MAC68K_IPL_NET] = (PSL_S | PSL_IPL4); 155 } 156 } 157 158 memcpy(g_inames, inames, MAX_INAME_LENGTH); 159 160 intr_computeipl(); 161 162 /* Initialize the VIAs */ 163 via_init(); 164 165 /* Initialize the PSC (if present) */ 166 psc_init(); 167 } 168 169 170 /* 171 * Compute the interrupt levels for the spl*() 172 * calls. This doesn't have to be fast. 173 */ 174 void 175 intr_computeipl() 176 { 177 /* 178 * Enforce the following relationship, as defined in spl(9): 179 * `bio <= net <= tty <= imp <= statclock <= clock <= sched <= serial' 180 */ 181 if (mac68k_ipls[MAC68K_IPL_BIO] > mac68k_ipls[MAC68K_IPL_NET]) 182 mac68k_ipls[MAC68K_IPL_NET] = mac68k_ipls[MAC68K_IPL_BIO]; 183 184 if (mac68k_ipls[MAC68K_IPL_NET] > mac68k_ipls[MAC68K_IPL_TTY]) 185 mac68k_ipls[MAC68K_IPL_TTY] = mac68k_ipls[MAC68K_IPL_NET]; 186 187 if (mac68k_ipls[MAC68K_IPL_TTY] > mac68k_ipls[MAC68K_IPL_IMP]) 188 mac68k_ipls[MAC68K_IPL_IMP] = mac68k_ipls[MAC68K_IPL_TTY]; 189 190 if (mac68k_ipls[MAC68K_IPL_IMP] > mac68k_ipls[MAC68K_IPL_STATCLOCK]) 191 mac68k_ipls[MAC68K_IPL_STATCLOCK] = mac68k_ipls[MAC68K_IPL_IMP]; 192 193 if (mac68k_ipls[MAC68K_IPL_STATCLOCK] > mac68k_ipls[MAC68K_IPL_CLOCK]) 194 mac68k_ipls[MAC68K_IPL_CLOCK] = 195 mac68k_ipls[MAC68K_IPL_STATCLOCK]; 196 197 if (mac68k_ipls[MAC68K_IPL_CLOCK] > mac68k_ipls[MAC68K_IPL_SCHED]) 198 mac68k_ipls[MAC68K_IPL_SCHED] = mac68k_ipls[MAC68K_IPL_CLOCK]; 199 200 if (mac68k_ipls[MAC68K_IPL_SCHED] > mac68k_ipls[MAC68K_IPL_SERIAL]) 201 mac68k_ipls[MAC68K_IPL_SERIAL] = mac68k_ipls[MAC68K_IPL_SCHED]; 202 } 203 204 /* 205 * Establish an autovectored interrupt handler. 206 * Called by driver attach functions. 207 * 208 * XXX Warning! DO NOT use Macintosh ROM traps from an interrupt handler 209 * established by this routine, either directly or indirectly, without 210 * properly saving and restoring all registers. If not, chaos _will_ 211 * ensue! (sar 19980806) 212 */ 213 void 214 intr_establish(func, arg, ipl) 215 int (*func) __P((void *)); 216 void *arg; 217 int ipl; 218 { 219 if ((ipl < 0) || (ipl >= NISR)) 220 panic("intr_establish: bad ipl %d", ipl); 221 222 #ifdef DIAGNOSTIC 223 if (intr_func[ipl] != intr_noint) 224 printf("intr_establish: attempt to share ipl %d\n", ipl); 225 #endif 226 227 intr_func[ipl] = func; 228 intr_arg[ipl] = arg; 229 } 230 231 /* 232 * Disestablish an interrupt handler. 233 */ 234 void 235 intr_disestablish(ipl) 236 int ipl; 237 { 238 if ((ipl < 0) || (ipl >= NISR)) 239 panic("intr_disestablish: bad ipl %d", ipl); 240 241 intr_func[ipl] = intr_noint; 242 intr_arg[ipl] = (void *)ipl; 243 } 244 245 /* 246 * This is the dispatcher called by the low-level 247 * assembly language interrupt routine. 248 * 249 * XXX Note: see the warning in intr_establish() 250 */ 251 void 252 intr_dispatch(evec) 253 int evec; /* format | vector offset */ 254 { 255 int ipl, vec; 256 257 vec = (evec & 0xfff) >> 2; 258 #ifdef DIAGNOSTIC 259 if ((vec < ISRLOC) || (vec >= (ISRLOC + NISR))) 260 panic("intr_dispatch: bad vec 0x%x\n", vec); 261 #endif 262 ipl = vec - ISRLOC; 263 264 intrcnt[ipl]++; 265 uvmexp.intrs++; 266 267 (void)(*intr_func[ipl])(intr_arg[ipl]); 268 } 269 270 /* 271 * Default interrupt handler: do nothing. 272 */ 273 static int 274 intr_noint(arg) 275 void *arg; 276 { 277 #ifdef DEBUG 278 if (intr_debug) 279 printf("intr_noint: ipl %d\n", (int)arg); 280 #endif 281 return 0; 282 } 283 284 void 285 netintr() 286 { 287 int s, isr; 288 289 for (;;) { 290 s = splhigh(); 291 isr = netisr; 292 netisr = 0; 293 splx(s); 294 295 if (isr == 0) 296 return; 297 298 #define DONETISR(bit, fn) do { \ 299 if (isr & (1 << bit)) \ 300 fn(); \ 301 } while (0) 302 303 #include <net/netisr_dispatch.h> 304 305 #undef DONETISR 306 } 307 } 308