1 /* $NetBSD: isr.c,v 1.27 2022/09/02 23:48:10 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1996 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 and Gordon W. Ross.
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 * This handles multiple attach of autovectored interrupts.
34 */
35
36 #include <sys/cdefs.h>
37 __KERNEL_RCSID(0, "$NetBSD: isr.c,v 1.27 2022/09/02 23:48:10 thorpej Exp $");
38
39 #include <sys/param.h>
40 #include <sys/systm.h>
41 #include <sys/device.h>
42 #include <sys/kmem.h>
43 #include <sys/vmmeter.h>
44 #include <sys/cpu.h>
45 #include <sys/intr.h>
46
47 #include <uvm/uvm_extern.h>
48
49 #include <machine/autoconf.h>
50 #include <machine/mon.h>
51
52 #include <sun68k/sun68k/vector.h>
53
54 extern int intrcnt[]; /* statistics */
55
56 #define NUM_LEVELS 8
57
58 struct isr {
59 struct isr *isr_next;
60 isr_func_t isr_intr;
61 void *isr_arg;
62 int isr_ipl;
63 };
64
65 #if 0
66 #define _IPL_NSOFT (_IPL_SOFT_LEVEL_MAX - _IPL_SOFT_LEVEL_MIN + 1)
67 #endif
68
69 int idepth;
70
71 void set_vector_entry(int, void *);
72 void *get_vector_entry(int);
73
74 /*
75 * These are called from locore. The "struct clockframe" arg
76 * is really just the normal H/W interrupt frame format.
77 * (kern_clock really wants it to be named that...)
78 */
79 void isr_autovec (struct clockframe);
80 void isr_vectored(struct clockframe);
81
82 void
isr_add_custom(int level,void * handler)83 isr_add_custom(int level, void *handler)
84 {
85
86 set_vector_entry(AUTOVEC_BASE + level, handler);
87 }
88
89
90 static struct isr *isr_autovec_list[NUM_LEVELS];
91
92 /*
93 * This is called by the assembly routines
94 * for handling auto-vectored interrupts.
95 */
96 void
isr_autovec(struct clockframe cf)97 isr_autovec(struct clockframe cf)
98 {
99 struct isr *isr;
100 int n, ipl, vec;
101
102 idepth++;
103
104 vec = (cf.cf_vo & 0xFFF) >> 2;
105 #ifdef DIAGNOSTIC
106 if ((vec < AUTOVEC_BASE) || (vec >= (AUTOVEC_BASE + NUM_LEVELS)))
107 panic("isr_autovec: bad vec");
108 #endif
109 ipl = vec - AUTOVEC_BASE;
110
111 n = intrcnt[ipl];
112 intrcnt[ipl] = n + 1;
113 curcpu()->ci_data.cpu_nintr++;
114
115 isr = isr_autovec_list[ipl];
116 if (isr == NULL) {
117 if (n == 0)
118 printf("isr_autovec: ipl %d unexpected\n", ipl);
119 goto out;
120 }
121
122 /* Give all the handlers a chance. */
123 n = 0;
124 while (isr) {
125 n |= (*isr->isr_intr)(isr->isr_arg);
126 isr = isr->isr_next;
127 }
128 if (n == 0)
129 printf("isr_autovec: ipl %d not claimed\n", ipl);
130
131 out:
132 idepth--;
133
134 ATOMIC_CAS_CHECK(&cf);
135 }
136
137 /*
138 * Establish an interrupt handler.
139 * Called by driver attach functions.
140 */
141 void
isr_add_autovect(isr_func_t handler,void * arg,int level)142 isr_add_autovect(isr_func_t handler, void *arg, int level)
143 {
144 struct isr *new_isr;
145
146 if ((level < 0) || (level >= NUM_LEVELS))
147 panic("isr_add: bad level=%d", level);
148 new_isr = kmem_alloc(sizeof(struct isr), KM_SLEEP);
149 new_isr->isr_intr = handler;
150 new_isr->isr_arg = arg;
151 new_isr->isr_ipl = level;
152 new_isr->isr_next = isr_autovec_list[level];
153 isr_autovec_list[level] = new_isr;
154 }
155
156 struct vector_handler {
157 isr_func_t func;
158 void *arg;
159 };
160 static struct vector_handler isr_vector_handlers[192];
161
162 /*
163 * This is called by the assembly glue
164 * for handling vectored interrupts.
165 */
166 void
isr_vectored(struct clockframe cf)167 isr_vectored(struct clockframe cf)
168 {
169 struct vector_handler *vh;
170 int ipl, vec;
171
172 idepth++;
173
174 vec = (cf.cf_vo & 0xFFF) >> 2;
175 ipl = _getsr();
176 ipl = (ipl >> 8) & 7;
177
178 intrcnt[ipl]++;
179 curcpu()->ci_data.cpu_nintr++;
180
181 #ifdef DIAGNOSTIC
182 if (vec < 64 || vec >= 256) {
183 printf("isr_vectored: vector=0x%x (invalid)\n", vec);
184 goto out;
185 }
186 #endif
187 vh = &isr_vector_handlers[vec - 64];
188 if (vh->func == NULL) {
189 printf("isr_vectored: vector=0x%x (nul func)\n", vec);
190 set_vector_entry(vec, (void *)badtrap);
191 goto out;
192 }
193
194 /* OK, call the isr function. */
195 if ((*vh->func)(vh->arg) == 0)
196 printf("isr_vectored: vector=0x%x (not claimed)\n", vec);
197
198 out:
199 idepth--;
200 ATOMIC_CAS_CHECK(&cf);
201 }
202
203 /*
204 * Establish an interrupt handler.
205 * Called by driver attach functions.
206 */
207 extern void _isr_vectored(void);
208
209 void
isr_add_vectored(isr_func_t func,void * arg,int level,int vec)210 isr_add_vectored(isr_func_t func, void *arg, int level, int vec)
211 {
212 struct vector_handler *vh;
213
214 if (vec < 64 || vec >= 256) {
215 printf("isr_add_vectored: vect=0x%x (invalid)\n", vec);
216 return;
217 }
218 vh = &isr_vector_handlers[vec - 64];
219 if (vh->func) {
220 printf("isr_add_vectored: vect=0x%x (in use)\n", vec);
221 return;
222 }
223 vh->func = func;
224 vh->arg = arg;
225 set_vector_entry(vec, (void *)_isr_vectored);
226 }
227
228 /*
229 * XXX - could just kill these...
230 */
231 void
set_vector_entry(int entry,void * handler)232 set_vector_entry(int entry, void *handler)
233 {
234
235 if ((entry < 0) || (entry >= NVECTORS))
236 panic("set_vector_entry: setting vector too high or low");
237 vector_table[entry] = handler;
238 }
239
240 void *
get_vector_entry(int entry)241 get_vector_entry(int entry)
242 {
243
244 if ((entry < 0) || (entry >= NVECTORS))
245 panic("get_vector_entry: setting vector too high or low");
246 return (void *)vector_table[entry];
247 }
248
249 const uint16_t ipl2psl_table[NIPL] = {
250 [IPL_NONE] = PSL_S | PSL_IPL0,
251 [IPL_SOFTBIO] = PSL_S | PSL_IPL1,
252 [IPL_SOFTCLOCK] = PSL_S | PSL_IPL1,
253 [IPL_SOFTNET] = PSL_S | PSL_IPL1,
254 [IPL_SOFTSERIAL] = PSL_S | PSL_IPL3,
255 [IPL_VM] = PSL_S | PSL_IPL4,
256 [IPL_SCHED] = PSL_S | PSL_IPL6,
257 [IPL_HIGH] = PSL_S | PSL_IPL7,
258 };
259