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
strayintr(fp)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
soft01intr(fp)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
intr_establish(level,ih)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
intr_fasttrap(level,vec)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