xref: /original-bsd/sys/sparc/sparc/intr.c (revision f860c383)
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