xref: /netbsd/sys/arch/news68k/news68k/isr.c (revision bf9ec67e)
1 /*	$NetBSD: isr.c,v 1.7 2001/07/07 06:24:00 tsutsui 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, 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  * 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  * from mvme68k/mvme68k/isr.c and sun3/sun3/isr.c
41  * This should be in /sys/arch/m68k/m68k?
42  */
43 
44 /*
45  * Link and dispatch interrupts.
46  */
47 
48 #include <sys/param.h>
49 #include <sys/systm.h>
50 #include <sys/malloc.h>
51 
52 #include <uvm/uvm_extern.h>
53 
54 #include <net/netisr.h>
55 
56 #include <machine/cpu.h>
57 
58 #include <news68k/news68k/isr.h>
59 
60 isr_autovec_list_t isr_autovec[NISRAUTOVEC];
61 struct	isr_vectored isr_vectored[NISRVECTORED];
62 
63 void set_vector_entry __P((int, void *));
64 void * get_vector_entry __P((int));
65 
66 void
67 isrinit()
68 {
69 	int i;
70 
71 	/* Initialize the autovector lists. */
72 	for (i = 0; i < NISRAUTOVEC; ++i) {
73 		LIST_INIT(&isr_autovec[i]);
74 	}
75 }
76 
77 /*
78  * Establish an autovectored interrupt handler.
79  * Called by driver attach functions.
80  */
81 void
82 isrlink_autovec(func, arg, ipl, priority)
83 	int (*func) __P((void *));
84 	void *arg;
85 	int ipl;
86 	int priority;
87 {
88 	struct isr_autovec *newisr, *curisr;
89 	isr_autovec_list_t *list;
90 
91 	if ((ipl < 0) || (ipl >= NISRAUTOVEC))
92 		panic("isrlink_autovec: bad ipl %d", ipl);
93 
94 	newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec),
95 	    M_DEVBUF, M_NOWAIT);
96 	if (newisr == NULL)
97 		panic("isrlink_autovec: can't allocate space for isr");
98 
99 	/* Fill in the new entry. */
100 	newisr->isr_func = func;
101 	newisr->isr_arg = arg;
102 	newisr->isr_ipl = ipl;
103 	newisr->isr_priority = priority;
104 
105 	/*
106 	 * Some devices are particularly sensitive to interrupt
107 	 * handling latency.  The SCC, for example, can lose many
108 	 * characters if its interrupt isn't handled with reasonable
109 	 * speed.
110 	 *
111 	 * To work around this problem, each device can give itself a
112 	 * "priority".  An unbuffered SCC would give itself a higher
113 	 * priority than a SCSI device, for example.
114 	 *
115 	 * This solution was originally developed for the hp300, which
116 	 * has a flat spl scheme (by necessity).  Thankfully, the
117 	 * MVME systems don't have this problem, though this may serve
118 	 * a useful purpose in any case.
119 	 */
120 
121 	/*
122 	 * Get the appropriate ISR list.  If the list is empty, no
123 	 * additional work is necessary; we simply insert ourselves
124 	 * at the head of the list.
125 	 */
126 	list = &isr_autovec[ipl];
127 	if (list->lh_first == NULL) {
128 		LIST_INSERT_HEAD(list, newisr, isr_link);
129 		return;
130 	}
131 
132 	/*
133 	 * A little extra work is required.  We traverse the list
134 	 * and place ourselves after any ISRs with our current (or
135 	 * higher) priority.
136 	 */
137 	for (curisr = list->lh_first; curisr->isr_link.le_next != NULL;
138 	    curisr = curisr->isr_link.le_next) {
139 		if (newisr->isr_priority > curisr->isr_priority) {
140 			LIST_INSERT_BEFORE(curisr, newisr, isr_link);
141 			return;
142 		}
143 	}
144 
145 	/*
146 	 * We're the least important entry, it seems.  We just go
147 	 * on the end.
148 	 */
149 	LIST_INSERT_AFTER(curisr, newisr, isr_link);
150 }
151 
152 /*
153  * Establish a vectored interrupt handler.
154  * Called by bus interrupt establish functions.
155  */
156 void
157 isrlink_vectored(func, arg, ipl, vec)
158 	int (*func) __P((void *));
159 	void *arg;
160 	int ipl, vec;
161 {
162 	struct isr_vectored *isr;
163 
164 	if ((ipl < 0) || (ipl >= NISRAUTOVEC))
165 		panic("isrlink_vectored: bad ipl %d", ipl);
166 	if ((vec < ISRVECTORED) || (vec >= ISRVECTORED + NISRVECTORED))
167 		panic("isrlink_vectored: bad vec 0x%x", vec);
168 
169 	isr = &isr_vectored[vec - ISRVECTORED];
170 
171 	if ((vectab[vec] != badtrap) || (isr->isr_func != NULL))
172 		panic("isrlink_vectored: vec 0x%x not available", vec);
173 
174 	/* Fill in the new entry. */
175 	isr->isr_func = func;
176 	isr->isr_arg = arg;
177 	isr->isr_ipl = ipl;
178 
179 	/* Hook into the vector table. */
180 	vectab[vec] = intrhand_vectored;
181 }
182 
183 /*
184  * Unhook a vectored interrupt.
185  */
186 void
187 isrunlink_vectored(vec)
188 	int vec;
189 {
190 
191 	if ((vec < ISRVECTORED) || (vec >= ISRVECTORED + NISRVECTORED))
192 		panic("isrunlink_vectored: bad vec 0x%x", vec);
193 
194 	if (vectab[vec] != intrhand_vectored)
195 		panic("isrunlink_vectored: not vectored interrupt");
196 
197 	vectab[vec] = badtrap;
198 	memset(&isr_vectored[vec - ISRVECTORED], 0,
199 	    sizeof(struct isr_vectored));
200 }
201 
202 /*
203  * This is the dispatcher called by the low-level
204  * assembly language autovectored interrupt routine.
205  */
206 void
207 isrdispatch_autovec(evec)
208 	int evec;		/* format | vector offset */
209 {
210 	struct isr_autovec *isr;
211 	isr_autovec_list_t *list;
212 	int handled = 0, ipl, vec;
213 	static int straycount, unexpected;
214 
215 	vec = (evec & 0xfff) >> 2;
216 	if ((vec < ISRAUTOVEC) || (vec >= (ISRAUTOVEC + NISRAUTOVEC)))
217 		panic("isrdispatch_autovec: bad vec 0x%x\n", vec);
218 	ipl = vec - ISRAUTOVEC;
219 
220 	intrcnt[ipl]++;
221 	uvmexp.intrs++;
222 
223 	list = &isr_autovec[ipl];
224 	if (list->lh_first == NULL) {
225 		printf("isrdispatch_autovec: ipl %d unexpected\n", ipl);
226 		if (++unexpected > 10)
227 			panic("too many unexpected interrupts");
228 		return;
229 	}
230 
231 	/* Give all the handlers a chance. */
232 	for (isr = list->lh_first ; isr != NULL; isr = isr->isr_link.le_next)
233 		handled |= (*isr->isr_func)(isr->isr_arg);
234 
235 	if (handled)
236 		straycount = 0;
237 	else if (++straycount > 50)
238 		panic("isr_dispatch_autovec: too many stray interrupts");
239 	else
240 		printf("isrdispatch_autovec: stray level %d interrupt\n", ipl);
241 }
242 
243 /*
244  * This is the dispatcher called by the low-level
245  * assembly language vectored interrupt routine.
246  */
247 void
248 isrdispatch_vectored(pc, evec, frame)
249 	int pc, evec;
250 	void *frame;
251 {
252 	struct isr_vectored *isr;
253 	int ipl, vec;
254 
255 	vec = (evec & 0xfff) >> 2;
256 	ipl = (getsr() >> 8) & 7;
257 
258 	intrcnt[ipl]++;
259 	uvmexp.intrs++;
260 
261 	if ((vec < ISRVECTORED) || (vec >= (ISRVECTORED + NISRVECTORED)))
262 		panic("isrdispatch_vectored: bad vec 0x%x\n", vec);
263 	isr = &isr_vectored[vec - ISRVECTORED];
264 
265 	if (isr->isr_func == NULL) {
266 		printf("isrdispatch_vectored: no handler for vec 0x%x\n", vec);
267 		vectab[vec] = badtrap;
268 		return;
269 	}
270 
271 	/*
272 	 * Handler gets exception frame if argument is NULL.
273 	 */
274 	if ((*isr->isr_func)(isr->isr_arg ? isr->isr_arg : frame) == 0)
275 		printf("isrdispatch_vectored: vec 0x%x not claimed\n", vec);
276 }
277 
278 void
279 isrlink_custom(level, handler)
280 	int level;
281 	void *handler;
282 {
283 	set_vector_entry(ISRAUTOVEC + level, handler);
284 }
285 
286 /*
287  * XXX - could just kill these... [from sun3]
288  */
289 void
290 set_vector_entry(entry, handler)
291 	int entry;
292 	void *handler;
293 {
294 	if ((entry < 0) || (entry >= NVECTORS))
295 		panic("set_vector_entry: setting vector too high or low\n");
296 	vectab[entry] = handler;
297 }
298 
299 void *
300 get_vector_entry(entry)
301 	int entry;
302 {
303 	if ((entry < 0) || (entry >= NVECTORS))
304 		panic("get_vector_entry: setting vector too high or low\n");
305 	return ((void *) vectab[entry]);
306 }
307 
308 void
309 netintr()
310 {
311 	int s, isr;
312 
313 	s = splnet();
314 	isr = netisr;
315 	netisr = 0;
316 	splx(s);
317 
318 #define DONETISR(bit, fn) do {		\
319 	if (isr & (1 << bit)) {		\
320 		fn();			\
321 	}				\
322 } while (0)
323 
324 #include <net/netisr_dispatch.h>
325 
326 #undef DONETISR
327 
328 }
329