1 /* 2 * Copyright (c) 1992, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This software was developed by the Computer Systems Engineering group 6 * at Lawrence Berkeley Laboratory under DARPA contract BG 91-66 and 7 * contributed to Berkeley. 8 * 9 * All advertising materials mentioning features or use of this software 10 * must display the following acknowledgement: 11 * This product includes software developed by the University of 12 * California, Lawrence Berkeley Laboratory. 13 * 14 * %sccs.include.redist.c% 15 * 16 * @(#)intr.c 8.1 (Berkeley) 06/11/93 17 * 18 * from: $Header: intr.c,v 1.20 92/11/26 03:04:53 torek Exp $ (LBL) 19 */ 20 21 #include <sys/param.h> 22 #include <sys/kernel.h> 23 24 #include <net/netisr.h> 25 26 #include <machine/cpu.h> 27 #include <machine/ctlreg.h> 28 #ifdef DIAGNOSTIC 29 #include <machine/instr.h> 30 #endif 31 #include <machine/trap.h> 32 33 #include <sparc/sparc/clockreg.h> 34 35 /* 36 * Stray interrupt handler. Clear it if possible. 37 * If not, and if we get 10 interrupts in 10 seconds, panic. 38 */ 39 void 40 strayintr(fp) 41 struct clockframe *fp; 42 { 43 static int straytime, nstray; 44 int timesince; 45 46 printf("stray interrupt ipl %x pc=%x npc=%x psr=%b\n", 47 fp->ipl, fp->pc, fp->npc, fp->psr, PSR_BITS); 48 timesince = time.tv_sec - straytime; 49 straytime = time.tv_sec; 50 if (timesince <= 10) { 51 if (++nstray > 9) 52 panic("crazy interrupts"); 53 } else { 54 straytime = time.tv_sec; 55 nstray = 1; 56 } 57 } 58 59 extern int clockintr(); /* level 10 (clock) interrupt code */ 60 static struct intrhand level10 = { clockintr }; 61 62 extern int statintr(); /* level 14 (statclock) interrupt code */ 63 static struct intrhand level14 = { statintr }; 64 65 /* 66 * Level 1 software interrupt (could also be Sbus level 1 interrupt). 67 * Three possible reasons: 68 * ROM console input needed 69 * Network software interrupt 70 * Soft clock interrupt 71 */ 72 int 73 soft01intr(fp) 74 void *fp; 75 { 76 extern int rom_console_input; 77 78 if (rom_console_input && cnrom()) 79 cnrint(); 80 if (sir.sir_any) { 81 /* 82 * XXX this is bogus: should just have a list of 83 * routines to call, a la timeouts. Mods to 84 * netisr are not atomic and must be protected (gah). 85 */ 86 if (sir.sir_which[SIR_NET]) { 87 int n, s; 88 89 s = splhigh(); 90 n = netisr; 91 netisr = 0; 92 splx(s); 93 sir.sir_which[SIR_NET] = 0; 94 #ifdef INET 95 if (n & (1 << NETISR_ARP)) 96 arpintr(); 97 if (n & (1 << NETISR_IP)) 98 ipintr(); 99 #endif 100 #ifdef NS 101 if (n & (1 << NETISR_NS)) 102 nsintr(); 103 #endif 104 #ifdef ISO 105 if (n & (1 << NETISR_ISO)) 106 clnlintr(); 107 #endif 108 } 109 if (sir.sir_which[SIR_CLOCK]) { 110 sir.sir_which[SIR_CLOCK] = 0; 111 softclock(); 112 } 113 } 114 return (1); 115 } 116 117 static struct intrhand level01 = { soft01intr }; 118 119 /* 120 * Level 15 interrupts are special, and not vectored here. 121 * Only `prewired' interrupts appear here; boot-time configured devices 122 * are attached via intr_establish() below. 123 */ 124 struct intrhand *intrhand[15] = { 125 NULL, /* 0 = error */ 126 &level01, /* 1 = software level 1 + Sbus */ 127 NULL, /* 2 = Sbus level 2 */ 128 NULL, /* 3 = SCSI + DMA + Sbus level 3 */ 129 NULL, /* 4 = software level 4 (tty softint) */ 130 NULL, /* 5 = Ethernet + Sbus level 4 */ 131 NULL, /* 6 = software level 6 (not used) */ 132 NULL, /* 7 = video + Sbus level 5 */ 133 NULL, /* 8 = Sbus level 6 */ 134 NULL, /* 9 = Sbus level 7 */ 135 &level10, /* 10 = counter 0 = clock */ 136 NULL, /* 11 = floppy */ 137 NULL, /* 12 = zs hardware interrupt */ 138 NULL, /* 13 = audio chip */ 139 &level14, /* 14 = counter 1 = profiling timer */ 140 }; 141 142 static int fastvec; /* marks fast vectors (see below) */ 143 #ifdef DIAGNOSTIC 144 extern int sparc_interrupt[]; 145 #endif 146 147 /* 148 * Attach an interrupt handler to the vector chain for the given level. 149 * This is not possible if it has been taken away as a fast vector. 150 */ 151 void 152 intr_establish(level, ih) 153 int level; 154 struct intrhand *ih; 155 { 156 register struct intrhand **p, *q; 157 #ifdef DIAGNOSTIC 158 register struct trapvec *tv; 159 register int displ; 160 #endif 161 int s; 162 163 s = splhigh(); 164 if (fastvec & (1 << level)) 165 panic("intr_establish: level %d interrupt tied to fast vector", 166 level); 167 #ifdef DIAGNOSTIC 168 /* double check for legal hardware interrupt */ 169 if (level != 1 && level != 4 && level != 6) { 170 tv = &trapbase[T_L1INT - 1 + level]; 171 displ = &sparc_interrupt[0] - &tv->tv_instr[1]; 172 /* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */ 173 if (tv->tv_instr[0] != I_MOVi(I_L3, level) || 174 tv->tv_instr[1] != I_BA(0, displ) || 175 tv->tv_instr[2] != I_RDPSR(I_L0)) 176 panic("intr_establish(%d, %x)\n%x %x %x != %x %x %x", 177 level, ih, 178 tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2], 179 I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0)); 180 } 181 #endif 182 /* 183 * This is O(N^2) for long chains, but chains are never long 184 * and we do want to preserve order. 185 */ 186 for (p = &intrhand[level]; (q = *p) != NULL; p = &q->ih_next) 187 continue; 188 *p = ih; 189 ih->ih_next = NULL; 190 splx(s); 191 } 192 193 /* 194 * Like intr_establish, but wires a fast trap vector. Only one such fast 195 * trap is legal for any interrupt, and it must be a hardware interrupt. 196 */ 197 void 198 intr_fasttrap(level, vec) 199 int level; 200 void (*vec) __P((void)); 201 { 202 register struct trapvec *tv; 203 register u_long hi22, lo10; 204 #ifdef DIAGNOSTIC 205 register int displ; /* suspenders, belt, and buttons too */ 206 #endif 207 int s; 208 209 tv = &trapbase[T_L1INT - 1 + level]; 210 hi22 = ((u_long)vec) >> 10; 211 lo10 = ((u_long)vec) & 0x3ff; 212 s = splhigh(); 213 if ((fastvec & (1 << level)) != 0 || intrhand[level] != NULL) 214 panic("intr_fasttrap: already handling level %d interrupts", 215 level); 216 #ifdef DIAGNOSTIC 217 displ = &sparc_interrupt[0] - &tv->tv_instr[1]; 218 /* has to be `mov level,%l3; ba _sparc_interrupt; rdpsr %l0' */ 219 if (tv->tv_instr[0] != I_MOVi(I_L3, level) || 220 tv->tv_instr[1] != I_BA(0, displ) || 221 tv->tv_instr[2] != I_RDPSR(I_L0)) 222 panic("intr_fasttrap(%d, %x)\n%x %x %x != %x %x %x", 223 level, vec, 224 tv->tv_instr[0], tv->tv_instr[1], tv->tv_instr[2], 225 I_MOVi(I_L3, level), I_BA(0, displ), I_RDPSR(I_L0)); 226 #endif 227 tv->tv_instr[0] = I_SETHI(I_L3, hi22); /* sethi %hi(vec),%l3 */ 228 tv->tv_instr[1] = I_JMPLri(I_G0, I_L3, lo10);/* jmpl %l3+%lo(vec),%g0 */ 229 tv->tv_instr[2] = I_RDPSR(I_L0); /* mov %psr, %l0 */ 230 fastvec |= 1 << level; 231 splx(s); 232 } 233