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