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