xref: /netbsd/sys/arch/mac68k/mac68k/intr.c (revision bf9ec67e)
1 /*	$NetBSD: intr.c,v 1.17 2001/04/12 18:26:26 thorpej Exp $	*/
2 
3 /*-
4  * Copyright (c) 1996, 1997 The NetBSD Foundation, Inc.
5  * All rights reserved.
6  *
7  * This code is derived from software contributed to The NetBSD Foundation
8  * by Adam Glass, Gordon W. Ross, and Jason R. Thorpe.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. All advertising materials mentioning features or use of this software
19  *    must display the following acknowledgement:
20  *        This product includes software developed by the NetBSD
21  *        Foundation, Inc. and its contributors.
22  * 4. Neither the name of The NetBSD Foundation nor the names of its
23  *    contributors may be used to endorse or promote products derived
24  *    from this software without specific prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
27  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
30  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36  * POSSIBILITY OF SUCH DAMAGE.
37  */
38 
39 /*
40  * Link and dispatch interrupts.
41  */
42 
43 #include <sys/param.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/vmmeter.h>
47 
48 #include <uvm/uvm_extern.h>
49 
50 #include <net/netisr.h>
51 
52 #include <machine/cpu.h>
53 #include <machine/intr.h>
54 
55 #include <machine/psc.h>
56 #include <machine/viareg.h>
57 
58 #define	NISR	8
59 #define	ISRLOC	0x18
60 
61 static int intr_noint __P((void *));
62 void netintr __P((void));
63 
64 static int ((*intr_func[NISR]) __P((void *))) = {
65 	intr_noint,
66 	intr_noint,
67 	intr_noint,
68 	intr_noint,
69 	intr_noint,
70 	intr_noint,
71 	intr_noint,
72 	intr_noint
73 };
74 static void *intr_arg[NISR] = {
75 	(void *)0,
76 	(void *)1,
77 	(void *)2,
78 	(void *)3,
79 	(void *)4,
80 	(void *)5,
81 	(void *)6,
82 	(void *)7
83 };
84 
85 #ifdef DEBUG
86 int	intr_debug = 0;
87 #endif
88 
89 /*
90  * Some of the below are not used yet, but might be used someday on the
91  * IIfx/Q700/900/950/etc. where the interrupt controller may be reprogrammed
92  * to interrupt on different levels as listed in locore.s
93  */
94 u_short mac68k_ipls[MAC68K_NIPLS];
95 
96 extern	int intrcnt[];		/* from locore.s */
97 
98 void	intr_computeipl __P((void));
99 
100 #define MAX_INAME_LENGTH 53
101 #define STD_INAMES \
102 	"spur\0via1\0via2\0unused1\0scc\0unused2\0unused3\0nmi\0clock\0"
103 #define AUX_INAMES \
104 	"spur\0soft\0via2\0ethernet\0scc\0sound\0via1\0nmi\0clock\0    "
105 #define AV_INAMES \
106 	"spur\0via1\0via2\0ethernet\0scc\0dsp\0unused1\0nmi\0clock\0   "
107 
108 void
109 intr_init()
110 {
111 	extern long	intrnames;
112 	char		*inames, *g_inames;
113 
114 	mac68k_ipls[MAC68K_IPL_SOFT] = PSL_S|PSL_IPL1;
115 	mac68k_ipls[MAC68K_IPL_SERIAL] = PSL_S|PSL_IPL4;
116 	mac68k_ipls[MAC68K_IPL_HIGH] = PSL_S|PSL_IPL7;
117 
118 	g_inames = (char *) &intrnames;
119 	if (mac68k_machine.aux_interrupts) {
120 		inames = AUX_INAMES;
121 
122 		/* Standard spl(9) interrupt priorities */
123 		mac68k_ipls[MAC68K_IPL_BIO] = (PSL_S | PSL_IPL2);
124 		mac68k_ipls[MAC68K_IPL_NET] = (PSL_S | PSL_IPL3);
125 		mac68k_ipls[MAC68K_IPL_TTY] = (PSL_S | PSL_IPL1);
126 		mac68k_ipls[MAC68K_IPL_IMP] = (PSL_S | PSL_IPL6);
127 		mac68k_ipls[MAC68K_IPL_STATCLOCK] = (PSL_S | PSL_IPL6);
128 		mac68k_ipls[MAC68K_IPL_CLOCK] = (PSL_S | PSL_IPL6);
129 		mac68k_ipls[MAC68K_IPL_SCHED] = (PSL_S | PSL_IPL6);
130 
131 		/* Non-standard interrupt priorities */
132 		mac68k_ipls[MAC68K_IPL_ADB] = (PSL_S | PSL_IPL6);
133 		mac68k_ipls[MAC68K_IPL_AUDIO] = (PSL_S | PSL_IPL5);
134 
135 	} else {
136 		inames = STD_INAMES;
137 
138 		/* Standard spl(9) interrupt priorities */
139 		mac68k_ipls[MAC68K_IPL_BIO] = (PSL_S | PSL_IPL2);
140 		mac68k_ipls[MAC68K_IPL_NET] = (PSL_S | PSL_IPL2);
141 		mac68k_ipls[MAC68K_IPL_TTY] = (PSL_S | PSL_IPL1);
142 		mac68k_ipls[MAC68K_IPL_IMP] = (PSL_S | PSL_IPL2);
143 		mac68k_ipls[MAC68K_IPL_STATCLOCK] = (PSL_S | PSL_IPL2);
144 		mac68k_ipls[MAC68K_IPL_CLOCK] = (PSL_S | PSL_IPL2);
145 		mac68k_ipls[MAC68K_IPL_SCHED] = (PSL_S | PSL_IPL3);
146 
147 		/* Non-standard interrupt priorities */
148 		mac68k_ipls[MAC68K_IPL_ADB] = (PSL_S | PSL_IPL1);
149 		mac68k_ipls[MAC68K_IPL_AUDIO] = (PSL_S | PSL_IPL2);
150 
151 		if (current_mac_model->class == MACH_CLASSAV) {
152 			inames = AV_INAMES;
153 			mac68k_ipls[MAC68K_IPL_BIO] =
154 			    mac68k_ipls[MAC68K_IPL_NET] = (PSL_S | PSL_IPL4);
155 		}
156 	}
157 
158 	memcpy(g_inames, inames, MAX_INAME_LENGTH);
159 
160 	intr_computeipl();
161 
162 	/* Initialize the VIAs */
163 	via_init();
164 
165 	/* Initialize the PSC (if present) */
166 	psc_init();
167 }
168 
169 
170 /*
171  * Compute the interrupt levels for the spl*()
172  * calls.  This doesn't have to be fast.
173  */
174 void
175 intr_computeipl()
176 {
177 	/*
178 	 * Enforce the following relationship, as defined in spl(9):
179 	 * `bio <= net <= tty <= imp <= statclock <= clock <= sched <= serial'
180 	 */
181 	if (mac68k_ipls[MAC68K_IPL_BIO] > mac68k_ipls[MAC68K_IPL_NET])
182 		mac68k_ipls[MAC68K_IPL_NET] = mac68k_ipls[MAC68K_IPL_BIO];
183 
184 	if (mac68k_ipls[MAC68K_IPL_NET] > mac68k_ipls[MAC68K_IPL_TTY])
185 		mac68k_ipls[MAC68K_IPL_TTY] = mac68k_ipls[MAC68K_IPL_NET];
186 
187 	if (mac68k_ipls[MAC68K_IPL_TTY] > mac68k_ipls[MAC68K_IPL_IMP])
188 		mac68k_ipls[MAC68K_IPL_IMP] = mac68k_ipls[MAC68K_IPL_TTY];
189 
190 	if (mac68k_ipls[MAC68K_IPL_IMP] > mac68k_ipls[MAC68K_IPL_STATCLOCK])
191 		mac68k_ipls[MAC68K_IPL_STATCLOCK] = mac68k_ipls[MAC68K_IPL_IMP];
192 
193 	if (mac68k_ipls[MAC68K_IPL_STATCLOCK] > mac68k_ipls[MAC68K_IPL_CLOCK])
194 		mac68k_ipls[MAC68K_IPL_CLOCK] =
195 		    mac68k_ipls[MAC68K_IPL_STATCLOCK];
196 
197 	if (mac68k_ipls[MAC68K_IPL_CLOCK] > mac68k_ipls[MAC68K_IPL_SCHED])
198 		mac68k_ipls[MAC68K_IPL_SCHED] = mac68k_ipls[MAC68K_IPL_CLOCK];
199 
200 	if (mac68k_ipls[MAC68K_IPL_SCHED] > mac68k_ipls[MAC68K_IPL_SERIAL])
201 		mac68k_ipls[MAC68K_IPL_SERIAL] = mac68k_ipls[MAC68K_IPL_SCHED];
202 }
203 
204 /*
205  * Establish an autovectored interrupt handler.
206  * Called by driver attach functions.
207  *
208  * XXX Warning!  DO NOT use Macintosh ROM traps from an interrupt handler
209  * established by this routine, either directly or indirectly, without
210  * properly saving and restoring all registers.  If not, chaos _will_
211  * ensue!  (sar 19980806)
212  */
213 void
214 intr_establish(func, arg, ipl)
215 	int (*func) __P((void *));
216 	void *arg;
217 	int ipl;
218 {
219 	if ((ipl < 0) || (ipl >= NISR))
220 		panic("intr_establish: bad ipl %d", ipl);
221 
222 #ifdef DIAGNOSTIC
223 	if (intr_func[ipl] != intr_noint)
224 		printf("intr_establish: attempt to share ipl %d\n", ipl);
225 #endif
226 
227 	intr_func[ipl] = func;
228 	intr_arg[ipl] = arg;
229 }
230 
231 /*
232  * Disestablish an interrupt handler.
233  */
234 void
235 intr_disestablish(ipl)
236 	int ipl;
237 {
238 	if ((ipl < 0) || (ipl >= NISR))
239 		panic("intr_disestablish: bad ipl %d", ipl);
240 
241 	intr_func[ipl] = intr_noint;
242 	intr_arg[ipl] = (void *)ipl;
243 }
244 
245 /*
246  * This is the dispatcher called by the low-level
247  * assembly language interrupt routine.
248  *
249  * XXX Note: see the warning in intr_establish()
250  */
251 void
252 intr_dispatch(evec)
253 	int evec;		/* format | vector offset */
254 {
255 	int ipl, vec;
256 
257 	vec = (evec & 0xfff) >> 2;
258 #ifdef DIAGNOSTIC
259 	if ((vec < ISRLOC) || (vec >= (ISRLOC + NISR)))
260 		panic("intr_dispatch: bad vec 0x%x\n", vec);
261 #endif
262 	ipl = vec - ISRLOC;
263 
264 	intrcnt[ipl]++;
265 	uvmexp.intrs++;
266 
267 	(void)(*intr_func[ipl])(intr_arg[ipl]);
268 }
269 
270 /*
271  * Default interrupt handler:  do nothing.
272  */
273 static int
274 intr_noint(arg)
275 	void *arg;
276 {
277 #ifdef DEBUG
278 	if (intr_debug)
279 		printf("intr_noint: ipl %d\n", (int)arg);
280 #endif
281 	return 0;
282 }
283 
284 void
285 netintr()
286 {
287 	int s, isr;
288 
289 	for (;;) {
290 		s = splhigh();
291 		isr = netisr;
292 		netisr = 0;
293 		splx(s);
294 
295 		if (isr == 0)
296 			return;
297 
298 #define DONETISR(bit, fn) do {		\
299 	if (isr & (1 << bit))		\
300 		fn();			\
301 } while (0)
302 
303 #include <net/netisr_dispatch.h>
304 
305 #undef DONETISR
306 	}
307 }
308