xref: /netbsd/sys/arch/sun68k/sun68k/isr.c (revision bf9ec67e)
1 /*	$NetBSD: isr.c,v 1.2 2001/11/30 17:47:04 fredette 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  * 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  * This handles multiple attach of autovectored interrupts,
41  * and the handy software interrupt request register.
42  */
43 
44 #include <sys/param.h>
45 #include <sys/systm.h>
46 #include <sys/device.h>
47 #include <sys/malloc.h>
48 #include <sys/vmmeter.h>
49 
50 #include <uvm/uvm_extern.h>
51 
52 #include <net/netisr.h>
53 
54 #include <machine/autoconf.h>
55 #include <machine/cpu.h>
56 #include <machine/intr.h>
57 #include <machine/mon.h>
58 
59 #include <sun68k/sun68k/vector.h>
60 
61 extern int intrcnt[];	/* statistics */
62 
63 #define NUM_LEVELS 8
64 
65 struct isr {
66 	struct	isr *isr_next;
67 	isr_func_t isr_intr;
68 	void *isr_arg;
69 	int	isr_ipl;
70 };
71 
72 /*
73  * Generic soft interrupt support.
74  */
75 struct softintr_head soft_level_heads[(_IPL_SOFT_LEVEL_MAX - _IPL_SOFT_LEVEL_MIN) + 1];
76 void *softnet_cookie;
77 static int softintr_handler __P((void *));
78 
79 void set_vector_entry __P((int, void *));
80 void * get_vector_entry __P((int));
81 
82 /*
83  * These are called from locore.  The "struct clockframe" arg
84  * is really just the normal H/W interrupt frame format.
85  * (kern_clock really wants it to be named that...)
86  */
87 void	isr_autovec  __P((struct clockframe));
88 void	isr_vectored __P((struct clockframe));
89 
90 
91 void
92 isr_add_custom(level, handler)
93 	int level;
94 	void *handler;
95 {
96 	set_vector_entry(AUTOVEC_BASE + level, handler);
97 }
98 
99 
100 /*
101  * netisr junk...
102  * should use an array of chars instead of
103  * a bitmask to avoid atomicity locking issues.
104  */
105 
106 void netintr()
107 {
108 	int n, s;
109 
110 	s = splhigh();
111 	n = netisr;
112 	netisr = 0;
113 	splx(s);
114 
115 #define DONETISR(bit, fn) do {		\
116 	if (n & (1 << bit))		\
117 		fn();			\
118 } while (0)
119 
120 #include <net/netisr_dispatch.h>
121 
122 #undef DONETISR
123 }
124 
125 
126 static struct isr *isr_autovec_list[NUM_LEVELS];
127 
128 /*
129  * This is called by the assembly routines
130  * for handling auto-vectored interupts.
131  */
132 void isr_autovec(cf)
133 	struct clockframe cf;
134 {
135 	struct isr *isr;
136 	int n, ipl, vec;
137 
138 	vec = (cf.cf_vo & 0xFFF) >> 2;
139 	if ((vec < AUTOVEC_BASE) || (vec >= (AUTOVEC_BASE+8)))
140 		panic("isr_autovec: bad vec");
141 	ipl = vec - AUTOVEC_BASE;
142 
143 	n = intrcnt[ipl];
144 	intrcnt[ipl] = n+1;
145 	uvmexp.intrs++;
146 
147 	isr = isr_autovec_list[ipl];
148 	if (isr == NULL) {
149 		if (n == 0)
150 			printf("isr_autovec: ipl %d unexpected\n", ipl);
151 		return;
152 	}
153 
154 	/* Give all the handlers a chance. */
155 	n = 0;
156 	while (isr) {
157 		n |= isr->isr_intr(isr->isr_arg);
158 		isr = isr->isr_next;
159 	}
160 	if (!n)
161 		printf("isr_autovec: ipl %d not claimed\n", ipl);
162 }
163 
164 /*
165  * Establish an interrupt handler.
166  * Called by driver attach functions.
167  */
168 void isr_add_autovect(handler, arg, level)
169 	isr_func_t handler;
170 	void *arg;
171 	int level;
172 {
173 	struct isr *new_isr;
174 
175 	if ((level < 0) || (level >= NUM_LEVELS))
176 		panic("isr_add: bad level=%d", level);
177 	new_isr = (struct isr *)
178 		malloc(sizeof(struct isr), M_DEVBUF, M_NOWAIT);
179 	if (!new_isr)
180 		panic("isr_add: malloc failed");
181 
182 	new_isr->isr_intr = handler;
183 	new_isr->isr_arg = arg;
184 	new_isr->isr_ipl = level;
185 	new_isr->isr_next = isr_autovec_list[level];
186 	isr_autovec_list[level] = new_isr;
187 }
188 
189 struct vector_handler {
190 	isr_func_t func;
191 	void *arg;
192 };
193 static struct vector_handler isr_vector_handlers[192];
194 
195 /*
196  * This is called by the assembly glue
197  * for handling vectored interupts.
198  */
199 void
200 isr_vectored(cf)
201 	struct clockframe cf;
202 {
203 	struct vector_handler *vh;
204 	int ipl, vec;
205 
206 	vec = (cf.cf_vo & 0xFFF) >> 2;
207 	ipl = _getsr();
208 	ipl = (ipl >> 8) & 7;
209 
210 	intrcnt[ipl]++;
211 	uvmexp.intrs++;
212 
213 	if (vec < 64 || vec >= 256) {
214 		printf("isr_vectored: vector=0x%x (invalid)\n", vec);
215 		return;
216 	}
217 	vh = &isr_vector_handlers[vec - 64];
218 	if (vh->func == NULL) {
219 		printf("isr_vectored: vector=0x%x (nul func)\n", vec);
220 		set_vector_entry(vec, (void *)badtrap);
221 		return;
222 	}
223 
224 	/* OK, call the isr function. */
225 	if (vh->func(vh->arg) == 0)
226 		printf("isr_vectored: vector=0x%x (not claimed)\n", vec);
227 }
228 
229 /*
230  * Establish an interrupt handler.
231  * Called by driver attach functions.
232  */
233 extern void _isr_vectored __P((void));
234 void
235 isr_add_vectored(func, arg, level, vec)
236 	isr_func_t func;
237 	void *arg;
238 	int level, vec;
239 {
240 	struct vector_handler *vh;
241 
242 	if (vec < 64 || vec >= 256) {
243 		printf("isr_add_vectored: vect=0x%x (invalid)\n", vec);
244 		return;
245 	}
246 	vh = &isr_vector_handlers[vec - 64];
247 	if (vh->func) {
248 		printf("isr_add_vectored: vect=0x%x (in use)\n", vec);
249 		return;
250 	}
251 	vh->func = func;
252 	vh->arg = arg;
253 	set_vector_entry(vec, (void *)_isr_vectored);
254 }
255 
256 /*
257  * Generic soft interrupt support.
258  */
259 
260 /*
261  * The soft interrupt handler.
262  */
263 static int
264 softintr_handler(void *arg)
265 {
266 	struct softintr_head *shd = arg;
267 	struct softintr_handler *sh;
268 
269 	/* Clear the interrupt. */
270 	isr_soft_clear(shd->shd_ipl);
271 	uvmexp.softs++;
272 
273 	/* Dispatch any pending handlers. */
274 	for(sh = LIST_FIRST(&shd->shd_intrs); sh != NULL; sh = LIST_NEXT(sh, sh_link)) {
275 		if (sh->sh_pending) {
276 			(*sh->sh_func)(sh->sh_arg);
277 			sh->sh_pending = 0;
278 		}
279 	}
280 
281 	return (1);
282 }
283 
284 /*
285  * This initializes soft interrupts.
286  */
287 void
288 softintr_init(void)
289 {
290 	int ipl;
291 	struct softintr_head *shd;
292 
293 	for(ipl = _IPL_SOFT_LEVEL_MIN; ipl <= _IPL_SOFT_LEVEL_MAX; ipl++) {
294 		shd = &soft_level_heads[ipl - _IPL_SOFT_LEVEL_MIN];
295 		shd->shd_ipl = ipl;
296 		LIST_INIT(&shd->shd_intrs);
297 		isr_add_autovect(softintr_handler, shd, ipl);
298 	}
299 
300 	softnet_cookie = softintr_establish(IPL_SOFTNET, (void (*) __P((void *))) netintr, NULL);
301 }
302 
303 /*
304  * This establishes a soft interrupt handler.
305  */
306 void *
307 softintr_establish(int ipl, void (*func)(void *), void *arg)
308 {
309 	struct softintr_handler *sh;
310 	struct softintr_head *shd;
311 
312 	if (ipl < _IPL_SOFT_LEVEL_MIN || ipl > _IPL_SOFT_LEVEL_MAX)
313 		panic("softintr_establish: unsupported soft IPL");
314 
315 	shd = &soft_level_heads[ipl - _IPL_SOFT_LEVEL_MIN];
316 
317 	sh = malloc(sizeof(*sh), M_SOFTINTR, M_NOWAIT);
318 	if (sh == NULL)
319 		return NULL;
320 
321 	LIST_INSERT_HEAD(&shd->shd_intrs, sh, sh_link);
322 	sh->sh_head = shd;
323 	sh->sh_pending = 0;
324 	sh->sh_func = func;
325 	sh->sh_arg = arg;
326 
327 	return sh;
328 }
329 
330 /*
331  * This disestablishes a soft interrupt handler.
332  */
333 void
334 softintr_disestablish(void *arg)
335 {
336 	struct softintr_handler *sh = arg;
337 	LIST_REMOVE(sh, sh_link);
338 	free(sh, M_SOFTINTR);
339 }
340 
341 
342 /*
343  * XXX - could just kill these...
344  */
345 void
346 set_vector_entry(entry, handler)
347 	int entry;
348 	void *handler;
349 {
350 	if ((entry <0) || (entry >= NVECTORS))
351 	panic("set_vector_entry: setting vector too high or low\n");
352 	vector_table[entry] = handler;
353 }
354 
355 void *
356 get_vector_entry(entry)
357 	int entry;
358 {
359 	if ((entry <0) || (entry >= NVECTORS))
360 	panic("get_vector_entry: setting vector too high or low\n");
361 	return ((void *) vector_table[entry]);
362 }
363