xref: /netbsd-src/sys/arch/mac68k/mac68k/intr.c (revision 3ced769fe7a334399fec58501b354c1d245c9a4f)
1 /*	$NetBSD: intr.c,v 1.36 2024/02/28 13:05:40 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  *
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.36 2024/02/28 13:05:40 thorpej Exp $");
38 
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/vmmeter.h>
42 #include <sys/cpu.h>
43 #include <sys/intr.h>
44 
45 #include <m68k/vectors.h>
46 
47 #include <machine/psc.h>
48 #include <machine/viareg.h>
49 
50 #define	NISR	8
51 #define	ISRLOC	0x18
52 
53 static int intr_noint(void *);
54 
55 static int ((*intr_func[NISR])(void *)) = {
56 	intr_noint,
57 	intr_noint,
58 	intr_noint,
59 	intr_noint,
60 	intr_noint,
61 	intr_noint,
62 	intr_noint,
63 	intr_noint
64 };
65 static void *intr_arg[NISR] = {
66 	NULL,
67 	NULL,
68 	NULL,
69 	NULL,
70 	NULL,
71 	NULL,
72 	NULL,
73 	NULL
74 };
75 
76 #ifdef DEBUG
77 int	intr_debug = 0;
78 #endif
79 
80 /*
81  * Some of the below are not used yet, but might be used someday on the
82  * IIfx/Q700/900/950/etc. where the interrupt controller may be reprogrammed
83  * to interrupt on different levels as listed in locore.s
84  */
85 uint16_t ipl2psl_table[NIPL];
86 volatile unsigned int intr_depth;
87 volatile int ssir;
88 
89 extern	u_int intrcnt[];	/* from locore.s */
90 
91 void	intr_computeipl(void);
92 
93 #define MAX_INAME_LENGTH 53
94 #define STD_INAMES \
95 	"spur\0via1\0via2\0unused1\0scc\0unused2\0unused3\0nmi\0clock\0"
96 #define AUX_INAMES \
97 	"spur\0soft\0via2\0ethernet\0scc\0sound\0via1\0nmi\0clock\0    "
98 #define AV_INAMES \
99 	"spur\0via1\0via2\0ethernet\0scc\0dsp\0unused1\0nmi\0clock\0   "
100 
101 void
intr_init(void)102 intr_init(void)
103 {
104 	extern char	intrnames[MAX_INAME_LENGTH];
105 	extern char	eintrnames[] __diagused;
106 	const char	*inames;
107 
108 	ipl2psl_table[IPL_NONE]       = 0;
109 	ipl2psl_table[IPL_SOFTCLOCK]  = PSL_S|PSL_IPL1;
110 	ipl2psl_table[IPL_SOFTNET]    = PSL_S|PSL_IPL1;
111 	ipl2psl_table[IPL_SOFTSERIAL] = PSL_S|PSL_IPL1;
112 	ipl2psl_table[IPL_SOFTBIO]    = PSL_S|PSL_IPL1;
113 	ipl2psl_table[IPL_HIGH]       = PSL_S|PSL_IPL7;
114 
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 	KASSERT(MAX_INAME_LENGTH <=
136 		((uintptr_t)eintrnames - (uintptr_t)intrnames));
137 	memcpy(intrnames, inames, MAX_INAME_LENGTH);
138 
139 	intr_computeipl();
140 
141 	/* Initialize the VIAs */
142 	via_init();
143 
144 	/* Initialize the PSC (if present) */
145 	psc_init();
146 }
147 
148 
149 /*
150  * Compute the interrupt levels for the spl*()
151  * calls.  This doesn't have to be fast.
152  */
153 void
intr_computeipl(void)154 intr_computeipl(void)
155 {
156 	/*
157 	 * Enforce the following relationship, as defined in spl(9):
158 	 * `bio <= net <= tty <= vm <= statclock <= clock <= sched <= serial'
159 	 */
160 	if (ipl2psl_table[IPL_VM] > ipl2psl_table[IPL_SCHED])
161 		ipl2psl_table[IPL_SCHED] = ipl2psl_table[IPL_VM];
162 
163 	if (ipl2psl_table[IPL_SCHED] > ipl2psl_table[IPL_HIGH])
164 		ipl2psl_table[IPL_HIGH] = ipl2psl_table[IPL_SCHED];
165 }
166 
167 /*
168  * Establish an autovectored interrupt handler.
169  * Called by driver attach functions.
170  *
171  * XXX Warning!  DO NOT use Macintosh ROM traps from an interrupt handler
172  * established by this routine, either directly or indirectly, without
173  * properly saving and restoring all registers.  If not, chaos _will_
174  * ensue!  (sar 19980806)
175  */
176 void
intr_establish(int (* func)(void *),void * arg,int ipl)177 intr_establish(int (*func)(void *), void *arg, int ipl)
178 {
179 	if ((ipl < 0) || (ipl >= NISR))
180 		panic("intr_establish: bad ipl %d", ipl);
181 
182 #ifdef DIAGNOSTIC
183 	if (intr_func[ipl] != intr_noint)
184 		printf("intr_establish: attempt to share ipl %d\n", ipl);
185 #endif
186 
187 	intr_func[ipl] = func;
188 	intr_arg[ipl] = arg;
189 }
190 
191 /*
192  * Disestablish an interrupt handler.
193  */
194 void
intr_disestablish(int ipl)195 intr_disestablish(int ipl)
196 {
197 	if ((ipl < 0) || (ipl >= NISR))
198 		panic("intr_disestablish: bad ipl %d", ipl);
199 
200 	intr_func[ipl] = intr_noint;
201 	intr_arg[ipl] = NULL;
202 }
203 
204 /*
205  * This is the dispatcher called by the low-level
206  * assembly language interrupt routine.
207  *
208  * XXX Note: see the warning in intr_establish()
209  */
210 void
intr_dispatch(struct clockframe frame)211 intr_dispatch(struct clockframe frame)
212 {
213 	const int ipl = VECO_TO_VECI(frame.cf_vo) - VECI_INTRAV0;
214 
215 	intr_depth++;
216 
217 	intrcnt[ipl]++;
218 	curcpu()->ci_data.cpu_nintr++;
219 
220 	(void)(*intr_func[ipl])(intr_arg[ipl] ? intr_arg[ipl] : &frame);
221 	intr_depth--;
222 }
223 
224 /*
225  * Default interrupt handler:  do nothing.
226  */
227 static int
intr_noint(void * arg)228 intr_noint(void *arg)
229 {
230 #ifdef DEBUG
231 	intr_depth++;
232 	if (intr_debug) {
233 		const struct clockframe *frame = arg;
234 		const int ipl = VECO_TO_VECI(frame->cf_vo) - VECI_INTRAV0;
235 		printf("intr_noint: ipl %d\n", ipl);
236 	}
237 	intr_depth--;
238 #endif
239 	return 0;
240 }
241 
242 bool
cpu_intr_p(void)243 cpu_intr_p(void)
244 {
245 
246 	return intr_depth != 0;
247 }
248