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