1 /* $NetBSD: intr.c,v 1.42 2002/05/06 19:19:48 eeh Exp $ */ 2 3 /* 4 * Copyright (c) 1992, 1993 5 * The Regents of the University of California. All rights reserved. 6 * 7 * This software was developed by the Computer Systems Engineering group 8 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 9 * contributed to Berkeley. 10 * 11 * All advertising materials mentioning features or use of this software 12 * must display the following acknowledgement: 13 * This product includes software developed by the University of 14 * California, Lawrence Berkeley Laboratory. 15 * 16 * Redistribution and use in source and binary forms, with or without 17 * modification, are permitted provided that the following conditions 18 * are met: 19 * 1. Redistributions of source code must retain the above copyright 20 * notice, this list of conditions and the following disclaimer. 21 * 2. Redistributions in binary form must reproduce the above copyright 22 * notice, this list of conditions and the following disclaimer in the 23 * documentation and/or other materials provided with the distribution. 24 * 3. All advertising materials mentioning features or use of this software 25 * must display the following acknowledgement: 26 * This product includes software developed by the University of 27 * California, Berkeley and its contributors. 28 * 4. Neither the name of the University nor the names of its contributors 29 * may be used to endorse or promote products derived from this software 30 * without specific prior written permission. 31 * 32 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 33 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT OT LIMITED TO, THE 34 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 35 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 36 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 37 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 38 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 39 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 40 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 41 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 42 * SUCH DAMAGE. 43 * 44 * @(#)intr.c 8.3 (Berkeley) 11/11/93 45 */ 46 47 #include "opt_ddb.h" 48 #include "pcons.h" 49 50 #include <sys/param.h> 51 #include <sys/systm.h> 52 #include <sys/kernel.h> 53 #include <sys/malloc.h> 54 55 #include <dev/cons.h> 56 57 #include <net/netisr.h> 58 59 #include <machine/cpu.h> 60 #include <machine/ctlreg.h> 61 #include <machine/instr.h> 62 #include <machine/trap.h> 63 64 /* 65 * The following array is to used by locore.s to map interrupt packets 66 * to the proper IPL to send ourselves a softint. It should be filled 67 * in as the devices are probed. We should eventually change this to a 68 * vector table and call these things directly. 69 */ 70 struct intrhand *intrlev[MAXINTNUM]; 71 72 void strayintr __P((const struct trapframe64 *, int)); 73 int softintr __P((void *)); 74 int softnet __P((void *)); 75 int intr_list_handler __P((void *)); 76 77 /* 78 * Stray interrupt handler. Clear it if possible. 79 * If not, and if we get 10 interrupts in 10 seconds, panic. 80 */ 81 int ignore_stray = 1; 82 int straycnt[16]; 83 84 void 85 strayintr(fp, vectored) 86 const struct trapframe64 *fp; 87 int vectored; 88 { 89 static int straytime, nstray; 90 int timesince; 91 char buf[256]; 92 #if 0 93 extern int swallow_zsintrs; 94 #endif 95 96 if (fp->tf_pil < 16) 97 straycnt[(int)fp->tf_pil]++; 98 99 if (ignore_stray) 100 return; 101 102 /* If we're in polled mode ignore spurious interrupts */ 103 if ((fp->tf_pil == PIL_SER) /* && swallow_zsintrs */) return; 104 105 printf("stray interrupt ipl %u pc=%llx npc=%llx pstate=%s vecttored=%d\n", 106 fp->tf_pil, (unsigned long long)fp->tf_pc, 107 (unsigned long long)fp->tf_npc, 108 bitmask_snprintf((fp->tf_tstate>>TSTATE_PSTATE_SHIFT), 109 PSTATE_BITS, buf, sizeof(buf)), vectored); 110 111 timesince = time.tv_sec - straytime; 112 if (timesince <= 10) { 113 if (++nstray > 500) 114 panic("crazy interrupts"); 115 } else { 116 straytime = time.tv_sec; 117 nstray = 1; 118 } 119 #ifdef DDB 120 Debugger(); 121 #endif 122 } 123 124 /* 125 * Level 1 software interrupt (could also be Sbus level 1 interrupt). 126 * Three possible reasons: 127 * Network software interrupt 128 * Soft clock interrupt 129 */ 130 int 131 softintr(fp) 132 void *fp; 133 { 134 #if NPCONS >0 135 extern void pcons_dopoll __P((void)); 136 137 pcons_dopoll(); 138 #endif 139 return (1); 140 } 141 142 int 143 softnet(fp) 144 void *fp; 145 { 146 int n, s; 147 148 s = splhigh(); 149 n = netisr; 150 netisr = 0; 151 splx(s); 152 153 #define DONETISR(bit, fn) do { \ 154 if (n & (1 << bit)) \ 155 fn(); \ 156 } while (0) 157 #include <net/netisr_dispatch.h> 158 #undef DONETISR 159 return (1); 160 } 161 162 struct intrhand soft01intr = { softintr, NULL, 1 }; 163 struct intrhand soft01net = { softnet, NULL, 1 }; 164 165 #if 1 166 void 167 setsoftint() { 168 send_softint(-1, IPL_SOFTINT, &soft01intr); 169 } 170 void 171 setsoftnet() { 172 send_softint(-1, IPL_SOFTNET, &soft01net); 173 } 174 #endif 175 176 /* 177 * Level 15 interrupts are special, and not vectored here. 178 * Only `prewired' interrupts appear here; boot-time configured devices 179 * are attached via intr_establish() below. 180 */ 181 struct intrhand *intrhand[16] = { 182 NULL, /* 0 = error */ 183 &soft01intr, /* 1 = software level 1 + Sbus */ 184 NULL, /* 2 = Sbus level 2 (4m: Sbus L1) */ 185 NULL, /* 3 = SCSI + DMA + Sbus level 3 (4m: L2,lpt)*/ 186 NULL, /* 4 = software level 4 (tty softint) (scsi) */ 187 NULL, /* 5 = Ethernet + Sbus level 4 (4m: Sbus L3) */ 188 NULL, /* 6 = software level 6 (not used) (4m: enet)*/ 189 NULL, /* 7 = video + Sbus level 5 */ 190 NULL, /* 8 = Sbus level 6 */ 191 NULL, /* 9 = Sbus level 7 */ 192 NULL, /* 10 = counter 0 = clock */ 193 NULL, /* 11 = floppy */ 194 NULL, /* 12 = zs hardware interrupt */ 195 NULL, /* 13 = audio chip */ 196 NULL, /* 14 = counter 1 = profiling timer */ 197 NULL /* 15 = async faults */ 198 }; 199 200 int fastvec = 0; 201 202 /* 203 * PCI devices can share interrupts so we need to have 204 * a handler to hand out interrupts. 205 */ 206 int 207 intr_list_handler(arg) 208 void * arg; 209 { 210 int claimed = 0; 211 struct intrhand *ih = (struct intrhand *)arg; 212 213 if (!arg) panic("intr_list_handler: no handlers!"); 214 while (ih && !claimed) { 215 claimed = (*ih->ih_fun)(ih->ih_arg); 216 #ifdef DEBUG 217 { 218 extern int intrdebug; 219 if (intrdebug & 1) 220 printf("intr %p %x arg %p %s\n", 221 ih, ih->ih_number, ih->ih_arg, 222 claimed ? "claimed" : ""); 223 } 224 #endif 225 ih = ih->ih_next; 226 } 227 return (claimed); 228 } 229 230 231 /* 232 * Attach an interrupt handler to the vector chain for the given level. 233 * This is not possible if it has been taken away as a fast vector. 234 */ 235 void 236 intr_establish(level, ih) 237 int level; 238 struct intrhand *ih; 239 { 240 register struct intrhand **p, *q = NULL; 241 int s; 242 243 s = splhigh(); 244 /* 245 * This is O(N^2) for long chains, but chains are never long 246 * and we do want to preserve order. 247 */ 248 ih->ih_pil = level; /* XXXX caller should have done this before */ 249 ih->ih_pending = 0; /* XXXX caller should have done this before */ 250 ih->ih_next = NULL; 251 252 /* 253 * Store in fast lookup table 254 */ 255 #ifdef NOT_DEBUG 256 if (!ih->ih_number) { 257 printf("\nintr_establish: NULL vector fun %p arg %p pil %p\n", 258 ih->ih_fun, ih->ih_arg, ih->ih_number, ih->ih_pil); 259 Debugger(); 260 } 261 #endif 262 if (ih->ih_number < MAXINTNUM && ih->ih_number >= 0) { 263 if ((q = intrlev[ih->ih_number])) { 264 struct intrhand *nih; 265 /* 266 * Interrupt is already there. We need to create a 267 * new interrupt handler and interpose it. 268 */ 269 #ifdef DEBUG 270 printf("intr_establish: intr reused %x\n", 271 ih->ih_number); 272 #endif 273 if (q->ih_fun != intr_list_handler) { 274 nih = (struct intrhand *) 275 malloc(sizeof(struct intrhand), 276 M_DEVBUF, M_NOWAIT); 277 /* Point the old IH at the new handler */ 278 *nih = *q; 279 q->ih_fun = intr_list_handler; 280 q->ih_arg = (void *)nih; 281 nih->ih_next = NULL; 282 } 283 /* Add the ih to the head of the list */ 284 ih->ih_next = (struct intrhand *)q->ih_arg; 285 q->ih_arg = (void *)ih; 286 } else { 287 intrlev[ih->ih_number] = ih; 288 } 289 #ifdef NOT_DEBUG 290 printf("\nintr_establish: vector %x pil %x mapintr %p " 291 "clrintr %p fun %p arg %p\n", 292 ih->ih_number, ih->ih_pil, (void *)ih->ih_map, 293 (void *)ih->ih_clr, (void *)ih->ih_fun, 294 (void *)ih->ih_arg); 295 /*Debugger();*/ 296 #endif 297 } else 298 panic("intr_establish: bad intr number %x", ih->ih_number); 299 300 /* If it's not shared, stick it in the intrhand list for that level. */ 301 if (q != NULL) { 302 for (p = &intrhand[level]; (q = *p) != NULL; p = &q->ih_next) 303 ; 304 *p = ih; 305 } 306 307 splx(s); 308 } 309 310 void * 311 softintr_establish(level, fun, arg) 312 int level; 313 void (*fun) __P((void *)); 314 void *arg; 315 { 316 struct intrhand *ih; 317 318 ih = malloc(sizeof(*ih), M_DEVBUF, 0); 319 bzero(ih, sizeof(*ih)); 320 ih->ih_fun = (int (*) __P((void *)))fun; /* XXX */ 321 ih->ih_arg = arg; 322 ih->ih_pil = level; 323 ih->ih_pending = 0; 324 ih->ih_clr = NULL; 325 return (void *)ih; 326 } 327 328 void 329 softintr_disestablish(cookie) 330 void *cookie; 331 { 332 free(cookie, M_DEVBUF); 333 } 334 335 void 336 softintr_schedule(cookie) 337 void *cookie; 338 { 339 struct intrhand *ih = (struct intrhand *)cookie; 340 341 send_softint(-1, ih->ih_pil, ih); 342 } 343