1 /* $NetBSD: isr.c,v 1.1 2001/05/14 18:23:01 drochner 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 REGENTS OR CONTRIBUTORS BE 30 * 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 "opt_inet.h" 44 #include "opt_atalk.h" 45 #include "opt_ccitt.h" 46 #include "opt_iso.h" 47 #include "opt_ns.h" 48 49 #include <sys/param.h> 50 #include <sys/systm.h> 51 #include <sys/queue.h> 52 #include <sys/malloc.h> 53 #include <sys/vmmeter.h> 54 55 #include <uvm/uvm_extern.h> 56 57 #include <net/netisr.h> 58 59 #include <machine/cpu.h> 60 61 #include <cesfic/cesfic/isr.h> 62 63 typedef LIST_HEAD(, isr) isr_list_t; 64 isr_list_t isr_list[NISR]; 65 66 u_short cesfic_bioipl, cesfic_netipl, cesfic_ttyipl, cesfic_impipl; 67 68 extern int intrcnt[]; /* from locore.s */ 69 70 void isrcomputeipl __P((void)); 71 72 void 73 isrinit() 74 { 75 int i; 76 77 /* Initialize the ISR lists. */ 78 for (i = 0; i < NISR; ++i) { 79 LIST_INIT(&isr_list[i]); 80 } 81 82 /* Default interrupt priorities. */ 83 cesfic_bioipl = cesfic_netipl = cesfic_ttyipl = cesfic_impipl = 84 (PSL_S|PSL_IPL3); 85 } 86 87 /* 88 * Scan all of the ISRs, recomputing the interrupt levels for the spl*() 89 * calls. This doesn't have to be fast. 90 */ 91 void 92 isrcomputeipl() 93 { 94 struct isr *isr; 95 int ipl; 96 97 /* Start with low values. */ 98 cesfic_bioipl = cesfic_netipl = cesfic_ttyipl = cesfic_impipl = 99 (PSL_S|PSL_IPL3); 100 101 for (ipl = 0; ipl < NISR; ipl++) { 102 for (isr = isr_list[ipl].lh_first; isr != NULL; 103 isr = isr->isr_link.le_next) { 104 /* 105 * Bump up the level for a given priority, 106 * if necessary. 107 */ 108 switch (isr->isr_priority) { 109 case ISRPRI_BIO: 110 if (ipl > PSLTOIPL(cesfic_bioipl)) 111 cesfic_bioipl = IPLTOPSL(ipl); 112 break; 113 114 case ISRPRI_NET: 115 if (ipl > PSLTOIPL(cesfic_netipl)) 116 cesfic_netipl = IPLTOPSL(ipl); 117 break; 118 119 case ISRPRI_TTY: 120 case ISRPRI_TTYNOBUF: 121 if (ipl > PSLTOIPL(cesfic_ttyipl)) 122 cesfic_ttyipl = IPLTOPSL(ipl); 123 break; 124 125 default: 126 printf("priority = %d\n", isr->isr_priority); 127 panic("isrcomputeipl: bad priority"); 128 } 129 } 130 } 131 132 /* 133 * Enforce `bio <= net <= tty <= imp' 134 */ 135 136 if (cesfic_netipl < cesfic_bioipl) 137 cesfic_netipl = cesfic_bioipl; 138 139 if (cesfic_ttyipl < cesfic_netipl) 140 cesfic_ttyipl = cesfic_netipl; 141 142 if (cesfic_impipl < cesfic_ttyipl) 143 cesfic_impipl = cesfic_ttyipl; 144 } 145 146 void 147 isrprintlevels() 148 { 149 150 #ifdef DEBUG 151 printf("psl: bio = 0x%x, net = 0x%x, tty = 0x%x, imp = 0x%x\n", 152 cesfic_bioipl, cesfic_netipl, cesfic_ttyipl, cesfic_impipl); 153 #endif 154 155 printf("interrupt levels: bio = %d, net = %d, tty = %d\n", 156 PSLTOIPL(cesfic_bioipl), PSLTOIPL(cesfic_netipl), 157 PSLTOIPL(cesfic_ttyipl)); 158 } 159 160 /* 161 * Establish an interrupt handler. 162 * Called by driver attach functions. 163 */ 164 void * 165 isrlink(func, arg, ipl, priority) 166 int (*func) __P((void *)); 167 void *arg; 168 int ipl; 169 int priority; 170 { 171 struct isr *newisr, *curisr; 172 isr_list_t *list; 173 174 if ((ipl < 0) || (ipl >= NISR)) 175 panic("isrlink: bad ipl %d", ipl); 176 177 newisr = (struct isr *)malloc(sizeof(struct isr), M_DEVBUF, M_NOWAIT); 178 if (newisr == NULL) 179 panic("isrlink: can't allocate space for isr"); 180 181 /* Fill in the new entry. */ 182 newisr->isr_func = func; 183 newisr->isr_arg = arg; 184 newisr->isr_ipl = ipl; 185 newisr->isr_priority = priority; 186 187 /* 188 * Some devices are particularly sensitive to interrupt 189 * handling latency. The DCA, for example, can lose many 190 * characters if its interrupt isn't handled with reasonable 191 * speed. 192 * 193 * To work around this problem, each device can give itself a 194 * "priority". An unbuffered DCA would give itself a higher 195 * priority than a SCSI device, for example. 196 * 197 * This is necessary because of the flat spl scheme employed by 198 * the hp300. Each device can be set from ipl 3 to ipl 5, which 199 * in turn means that splbio, splnet, and spltty must all be at 200 * spl5. 201 * 202 * Don't blame me...I just work here. 203 */ 204 205 /* 206 * Get the appropriate ISR list. If the list is empty, no 207 * additional work is necessary; we simply insert ourselves 208 * at the head of the list. 209 */ 210 list = &isr_list[ipl]; 211 if (list->lh_first == NULL) { 212 LIST_INSERT_HEAD(list, newisr, isr_link); 213 goto compute; 214 } 215 216 /* 217 * A little extra work is required. We traverse the list 218 * and place ourselves after any ISRs with our current (or 219 * higher) priority. 220 */ 221 for (curisr = list->lh_first; curisr->isr_link.le_next != NULL; 222 curisr = curisr->isr_link.le_next) { 223 if (newisr->isr_priority > curisr->isr_priority) { 224 LIST_INSERT_BEFORE(curisr, newisr, isr_link); 225 goto compute; 226 } 227 } 228 229 /* 230 * We're the least important entry, it seems. We just go 231 * on the end. 232 */ 233 LIST_INSERT_AFTER(curisr, newisr, isr_link); 234 235 compute: 236 /* Compute new interrupt levels. */ 237 isrcomputeipl(); 238 return (newisr); 239 } 240 241 /* 242 * Disestablish an interrupt handler. 243 */ 244 void 245 isrunlink(arg) 246 void *arg; 247 { 248 struct isr *isr = arg; 249 250 LIST_REMOVE(isr, isr_link); 251 free(isr, M_DEVBUF); 252 isrcomputeipl(); 253 } 254 255 /* 256 * This is the dispatcher called by the low-level 257 * assembly language interrupt routine. 258 */ 259 void 260 isrdispatch(evec) 261 int evec; /* format | vector offset */ 262 { 263 struct isr *isr; 264 isr_list_t *list; 265 int handled, ipl, vec; 266 static int straycount, unexpected; 267 268 vec = (evec & 0xfff) >> 2; 269 if ((vec < ISRLOC) || (vec >= (ISRLOC + NISR))) 270 panic("isrdispatch: bad vec 0x%x\n", vec); 271 ipl = vec - ISRLOC; 272 273 intrcnt[ipl]++; 274 uvmexp.intrs++; 275 276 list = &isr_list[ipl]; 277 if (list->lh_first == NULL) { 278 printf("intrhand: ipl %d unexpected\n", ipl); 279 if (++unexpected > 10) 280 panic("isrdispatch: too many unexpected interrupts"); 281 return; 282 } 283 284 handled = 0; 285 /* Give all the handlers a chance. */ 286 for (isr = list->lh_first ; isr != NULL; isr = isr->isr_link.le_next) 287 handled |= (*isr->isr_func)(isr->isr_arg); 288 289 if (handled) 290 straycount = 0; 291 else if (++straycount > 50) 292 panic("isrdispatch: too many stray interrupts"); 293 else 294 printf("isrdispatch: stray level %d interrupt\n", ipl); 295 } 296 297 /* 298 * XXX Why on earth isn't this in a common file?! 299 */ 300 void netintr __P((void)); 301 void arpintr __P((void)); 302 void ipintr __P((void)); 303 void nsintr __P((void)); 304 void clnintr __P((void)); 305 void ccittintr __P((void)); 306 void pppintr __P((void)); 307 308 void 309 netintr() 310 { 311 #ifdef INET 312 if (netisr & (1 << NETISR_ARP)) { 313 netisr &= ~(1 << NETISR_ARP); 314 arpintr(); 315 } 316 if (netisr & (1 << NETISR_IP)) { 317 netisr &= ~(1 << NETISR_IP); 318 ipintr(); 319 } 320 #endif 321 #ifdef NS 322 if (netisr & (1 << NETISR_NS)) { 323 netisr &= ~(1 << NETISR_NS); 324 nsintr(); 325 } 326 #endif 327 #ifdef ISO 328 if (netisr & (1 << NETISR_ISO)) { 329 netisr &= ~(1 << NETISR_ISO); 330 clnlintr(); 331 } 332 #endif 333 #ifdef CCITT 334 if (netisr & (1 << NETISR_CCITT)) { 335 netisr &= ~(1 << NETISR_CCITT); 336 ccittintr(); 337 } 338 #endif 339 #include "ppp.h" 340 #if NPPP > 0 341 if (netisr & (1 << NETISR_PPP)) { 342 netisr &= ~(1 << NETISR_PPP); 343 pppintr(); 344 } 345 #endif 346 } 347