xref: /netbsd/sys/arch/mac68k/mac68k/intr.c (revision 6550d01e)
1 /*	$NetBSD: intr.c,v 1.29 2010/12/20 00:25:36 matt 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  *
19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29  * POSSIBILITY OF SUCH DAMAGE.
30  */
31 
32 /*
33  * Link and dispatch interrupts.
34  */
35 
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.29 2010/12/20 00:25:36 matt Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/malloc.h>
42 #include <sys/vmmeter.h>
43 #include <sys/cpu.h>
44 #include <sys/intr.h>
45 
46 #include <machine/psc.h>
47 #include <machine/viareg.h>
48 
49 #define	NISR	8
50 #define	ISRLOC	0x18
51 
52 static int intr_noint(void *);
53 
54 static int ((*intr_func[NISR])(void *)) = {
55 	intr_noint,
56 	intr_noint,
57 	intr_noint,
58 	intr_noint,
59 	intr_noint,
60 	intr_noint,
61 	intr_noint,
62 	intr_noint
63 };
64 static void *intr_arg[NISR] = {
65 	(void *)0,
66 	(void *)1,
67 	(void *)2,
68 	(void *)3,
69 	(void *)4,
70 	(void *)5,
71 	(void *)6,
72 	(void *)7
73 };
74 
75 #ifdef DEBUG
76 int	intr_debug = 0;
77 #endif
78 
79 /*
80  * Some of the below are not used yet, but might be used someday on the
81  * IIfx/Q700/900/950/etc. where the interrupt controller may be reprogrammed
82  * to interrupt on different levels as listed in locore.s
83  */
84 uint16_t ipl2psl_table[NIPL];
85 int idepth;
86 volatile int ssir;
87 
88 extern	int intrcnt[];		/* from locore.s */
89 
90 void	intr_computeipl(void);
91 
92 #define MAX_INAME_LENGTH 53
93 #define STD_INAMES \
94 	"spur\0via1\0via2\0unused1\0scc\0unused2\0unused3\0nmi\0clock\0"
95 #define AUX_INAMES \
96 	"spur\0soft\0via2\0ethernet\0scc\0sound\0via1\0nmi\0clock\0    "
97 #define AV_INAMES \
98 	"spur\0via1\0via2\0ethernet\0scc\0dsp\0unused1\0nmi\0clock\0   "
99 
100 void
101 intr_init(void)
102 {
103 	extern long	intrnames;
104 	const char	*inames;
105 	char		*g_inames;
106 
107 	ipl2psl_table[IPL_NONE]       = 0;
108 	ipl2psl_table[IPL_SOFTCLOCK]  = PSL_S|PSL_IPL1;
109 	ipl2psl_table[IPL_SOFTNET]    = PSL_S|PSL_IPL1;
110 	ipl2psl_table[IPL_SOFTSERIAL] = PSL_S|PSL_IPL1;
111 	ipl2psl_table[IPL_SOFTBIO]    = PSL_S|PSL_IPL1;
112 	ipl2psl_table[IPL_HIGH]       = PSL_S|PSL_IPL7;
113 
114 	g_inames = (char *) &intrnames;
115 	if (mac68k_machine.aux_interrupts) {
116 		inames = AUX_INAMES;
117 
118 		/* Standard spl(9) interrupt priorities */
119 		ipl2psl_table[IPL_VM]        = (PSL_S | PSL_IPL6);
120 		ipl2psl_table[IPL_SCHED]     = (PSL_S | PSL_IPL6);
121 	} else {
122 		inames = STD_INAMES;
123 
124 		/* Standard spl(9) interrupt priorities */
125 		ipl2psl_table[IPL_VM]        = (PSL_S | PSL_IPL2);
126 		ipl2psl_table[IPL_SCHED]     = (PSL_S | PSL_IPL3);
127 
128 		if (current_mac_model->class == MACH_CLASSAV) {
129 			inames = AV_INAMES;
130 			ipl2psl_table[IPL_VM]    = (PSL_S | PSL_IPL4);
131 			ipl2psl_table[IPL_SCHED] = (PSL_S | PSL_IPL4);
132 		}
133 	}
134 
135 	memcpy(g_inames, inames, MAX_INAME_LENGTH);
136 
137 	intr_computeipl();
138 
139 	/* Initialize the VIAs */
140 	via_init();
141 
142 	/* Initialize the PSC (if present) */
143 	psc_init();
144 }
145 
146 
147 /*
148  * Compute the interrupt levels for the spl*()
149  * calls.  This doesn't have to be fast.
150  */
151 void
152 intr_computeipl(void)
153 {
154 	/*
155 	 * Enforce the following relationship, as defined in spl(9):
156 	 * `bio <= net <= tty <= vm <= statclock <= clock <= sched <= serial'
157 	 */
158 	if (ipl2psl_table[IPL_VM] > ipl2psl_table[IPL_SCHED])
159 		ipl2psl_table[IPL_SCHED] = ipl2psl_table[IPL_VM];
160 
161 	if (ipl2psl_table[IPL_SCHED] > ipl2psl_table[IPL_HIGH])
162 		ipl2psl_table[IPL_HIGH] = ipl2psl_table[IPL_SCHED];
163 }
164 
165 /*
166  * Establish an autovectored interrupt handler.
167  * Called by driver attach functions.
168  *
169  * XXX Warning!  DO NOT use Macintosh ROM traps from an interrupt handler
170  * established by this routine, either directly or indirectly, without
171  * properly saving and restoring all registers.  If not, chaos _will_
172  * ensue!  (sar 19980806)
173  */
174 void
175 intr_establish(int (*func)(void *), void *arg, int ipl)
176 {
177 	if ((ipl < 0) || (ipl >= NISR))
178 		panic("intr_establish: bad ipl %d", ipl);
179 
180 #ifdef DIAGNOSTIC
181 	if (intr_func[ipl] != intr_noint)
182 		printf("intr_establish: attempt to share ipl %d\n", ipl);
183 #endif
184 
185 	intr_func[ipl] = func;
186 	intr_arg[ipl] = arg;
187 }
188 
189 /*
190  * Disestablish an interrupt handler.
191  */
192 void
193 intr_disestablish(int ipl)
194 {
195 	if ((ipl < 0) || (ipl >= NISR))
196 		panic("intr_disestablish: bad ipl %d", ipl);
197 
198 	intr_func[ipl] = intr_noint;
199 	intr_arg[ipl] = (void *)ipl;
200 }
201 
202 /*
203  * This is the dispatcher called by the low-level
204  * assembly language interrupt routine.
205  *
206  * XXX Note: see the warning in intr_establish()
207  */
208 void
209 intr_dispatch(int evec)		/* format | vector offset */
210 {
211 	int ipl, vec;
212 
213 	idepth++;
214 	vec = (evec & 0xfff) >> 2;
215 #ifdef DIAGNOSTIC
216 	if ((vec < ISRLOC) || (vec >= (ISRLOC + NISR)))
217 		panic("intr_dispatch: bad vec 0x%x", vec);
218 #endif
219 	ipl = vec - ISRLOC;
220 
221 	intrcnt[ipl]++;
222 	curcpu()->ci_data.cpu_nintr++;
223 
224 	(void)(*intr_func[ipl])(intr_arg[ipl]);
225 	idepth--;
226 }
227 
228 /*
229  * Default interrupt handler:  do nothing.
230  */
231 static int
232 intr_noint(void *arg)
233 {
234 #ifdef DEBUG
235 	idepth++;
236 	if (intr_debug)
237 		printf("intr_noint: ipl %d\n", (int)arg);
238 	idepth--;
239 #endif
240 	return 0;
241 }
242 
243 bool
244 cpu_intr_p(void)
245 {
246 
247 	return idepth != 0;
248 }
249