xref: /netbsd/sys/arch/luna68k/luna68k/isr.c (revision 6550d01e)
1 /*	$NetBSD: isr.c,v 1.20 2010/12/20 00:25:36 matt 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  *
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 #include <sys/cdefs.h>			/* RCS ID & Copyright macro defns */
33 
34 __KERNEL_RCSID(0, "$NetBSD: isr.c,v 1.20 2010/12/20 00:25:36 matt Exp $");
35 
36 /*
37  * Link and dispatch interrupts.
38  */
39 
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/malloc.h>
43 #include <sys/vmmeter.h>
44 #include <sys/cpu.h>
45 
46 #include <uvm/uvm_extern.h>
47 
48 #include <luna68k/luna68k/isr.h>
49 
50 isr_autovec_list_t isr_autovec[NISRAUTOVEC];
51 struct	isr_vectored isr_vectored[NISRVECTORED];
52 int	idepth;
53 volatile int	ssir;
54 
55 extern	int intrcnt[];		/* from locore.s */
56 extern	void (*vectab[])(void);
57 extern	void badtrap(void);
58 extern	void intrhand_vectored(void);
59 
60 extern	int getsr(void);	/* in locore.s */
61 
62 void
63 isrinit(void)
64 {
65 	int i;
66 
67 	/* Initialize the autovector lists. */
68 	for (i = 0; i < NISRAUTOVEC; ++i) {
69 		LIST_INIT(&isr_autovec[i]);
70 	}
71 }
72 
73 /*
74  * Establish an autovectored interrupt handler.
75  * Called by driver attach functions.
76  */
77 void
78 isrlink_autovec(int (*func)(void *), void *arg, int ipl, int priority)
79 {
80 	struct isr_autovec *newisr, *curisr;
81 	isr_autovec_list_t *list;
82 
83 	if ((ipl < 0) || (ipl >= NISRAUTOVEC))
84 		panic("isrlink_autovec: bad ipl %d", ipl);
85 
86 	newisr = (struct isr_autovec *)malloc(sizeof(struct isr_autovec),
87 	    M_DEVBUF, M_NOWAIT);
88 	if (newisr == NULL)
89 		panic("isrlink_autovec: can't allocate space for isr");
90 
91 	/* Fill in the new entry. */
92 	newisr->isr_func = func;
93 	newisr->isr_arg = arg;
94 	newisr->isr_ipl = ipl;
95 	newisr->isr_priority = priority;
96 
97 	/*
98 	 * Some devices are particularly sensitive to interrupt
99 	 * handling latency.  The SCC, for example, can lose many
100 	 * characters if its interrupt isn't handled with reasonable
101 	 * speed.
102 	 *
103 	 * To work around this problem, each device can give itself a
104 	 * "priority".  An unbuffered SCC would give itself a higher
105 	 * priority than a SCSI device, for example.
106 	 *
107 	 * This solution was originally developed for the hp300, which
108 	 * has a flat spl scheme (by necessity).  Thankfully, the
109 	 * MVME systems don't have this problem, though this may serve
110 	 * a useful purpose in any case.
111 	 */
112 
113 	/*
114 	 * Get the appropriate ISR list.  If the list is empty, no
115 	 * additional work is necessary; we simply insert ourselves
116 	 * at the head of the list.
117 	 */
118 	list = &isr_autovec[ipl];
119 	if (list->lh_first == NULL) {
120 		LIST_INSERT_HEAD(list, newisr, isr_link);
121 		return;
122 	}
123 
124 	/*
125 	 * A little extra work is required.  We traverse the list
126 	 * and place ourselves after any ISRs with our current (or
127 	 * higher) priority.
128 	 */
129 	for (curisr = list->lh_first; curisr->isr_link.le_next != NULL;
130 	    curisr = curisr->isr_link.le_next) {
131 		if (newisr->isr_priority > curisr->isr_priority) {
132 			LIST_INSERT_BEFORE(curisr, newisr, isr_link);
133 			return;
134 		}
135 	}
136 
137 	/*
138 	 * We're the least important entry, it seems.  We just go
139 	 * on the end.
140 	 */
141 	LIST_INSERT_AFTER(curisr, newisr, isr_link);
142 }
143 
144 /*
145  * Establish a vectored interrupt handler.
146  * Called by bus interrupt establish functions.
147  */
148 void
149 isrlink_vectored(int (*func)(void *), void *arg, int ipl, int vec)
150 {
151 	struct isr_vectored *isr;
152 
153 	if ((ipl < 0) || (ipl >= NISRAUTOVEC))
154 		panic("isrlink_vectored: bad ipl %d", ipl);
155 	if ((vec < ISRVECTORED) || (vec >= ISRVECTORED + NISRVECTORED))
156 		panic("isrlink_vectored: bad vec 0x%x", vec);
157 
158 	isr = &isr_vectored[vec - ISRVECTORED];
159 
160 	if ((vectab[vec] != badtrap) || (isr->isr_func != NULL))
161 		panic("isrlink_vectored: vec 0x%x not available", vec);
162 
163 	/* Fill in the new entry. */
164 	isr->isr_func = func;
165 	isr->isr_arg = arg;
166 	isr->isr_ipl = ipl;
167 
168 	/* Hook into the vector table. */
169 	vectab[vec] = intrhand_vectored;
170 }
171 
172 /*
173  * Unhook a vectored interrupt.
174  */
175 void
176 isrunlink_vectored(int vec)
177 {
178 
179 	if ((vec < ISRVECTORED) || (vec >= ISRVECTORED + NISRVECTORED))
180 		panic("isrunlink_vectored: bad vec 0x%x", vec);
181 
182 	if (vectab[vec] != intrhand_vectored)
183 		panic("isrunlink_vectored: not vectored interrupt");
184 
185 	vectab[vec] = badtrap;
186 	memset(&isr_vectored[vec - ISRVECTORED], 0, sizeof(struct isr_vectored));
187 }
188 
189 /*
190  * This is the dispatcher called by the low-level
191  * assembly language autovectored interrupt routine.
192  */
193 void
194 isrdispatch_autovec(int evec)
195 	/* evec:		 format | vector offset */
196 {
197 	struct isr_autovec *isr;
198 	isr_autovec_list_t *list;
199 	int handled = 0, ipl, vec;
200 	static int straycount, unexpected;
201 
202 	idepth++;
203 	vec = (evec & 0xfff) >> 2;
204 	if ((vec < ISRAUTOVEC) || (vec >= (ISRAUTOVEC + NISRAUTOVEC)))
205 		panic("isrdispatch_autovec: bad vec 0x%x", vec);
206 	ipl = vec - ISRAUTOVEC;
207 
208 	intrcnt[ipl]++;
209 	curcpu()->ci_data.cpu_nintr++;
210 
211 	list = &isr_autovec[ipl];
212 	if (list->lh_first == NULL) {
213 		printf("isrdispatch_autovec: ipl %d unexpected\n", ipl);
214 		if (++unexpected > 10)
215 			panic("too many unexpected interrupts");
216 		idepth--;
217 		return;
218 	}
219 
220 	/* Give all the handlers a chance. */
221 	for (isr = list->lh_first ; isr != NULL; isr = isr->isr_link.le_next)
222 		handled |= (*isr->isr_func)(isr->isr_arg);
223 
224 	if (handled)
225 		straycount = 0;
226 	else if (++straycount > 50)
227 		panic("isr_dispatch_autovec: too many stray interrupts");
228 	else
229 		printf("isrdispatch_autovec: stray level %d interrupt\n", ipl);
230 	idepth--;
231 }
232 
233 /*
234  * This is the dispatcher called by the low-level
235  * assembly language vectored interrupt routine.
236  */
237 void
238 isrdispatch_vectored(int pc, int evec, void *frame)
239 {
240 	struct isr_vectored *isr;
241 	int ipl, vec;
242 
243 	idepth++;
244 	vec = (evec & 0xfff) >> 2;
245 	ipl = (getsr() >> 8) & 7;
246 
247 	intrcnt[ipl]++;
248 	curcpu()->ci_data.cpu_nintr++;
249 
250 	if ((vec < ISRVECTORED) || (vec >= (ISRVECTORED + NISRVECTORED)))
251 		panic("isrdispatch_vectored: bad vec 0x%x", vec);
252 	isr = &isr_vectored[vec - ISRVECTORED];
253 
254 	if (isr->isr_func == NULL) {
255 		printf("isrdispatch_vectored: no handler for vec 0x%x\n", vec);
256 		vectab[vec] = badtrap;
257 		idepth--;
258 		return;
259 	}
260 
261 	/*
262 	 * Handler gets exception frame if argument is NULL.
263 	 */
264 	if ((*isr->isr_func)(isr->isr_arg ? isr->isr_arg : frame) == 0)
265 		printf("isrdispatch_vectored: vec 0x%x not claimed\n", vec);
266 	idepth--;
267 }
268 
269 bool
270 cpu_intr_p(void)
271 {
272 
273 	return idepth != 0;
274 }
275 
276 const uint16_t ipl2psl_table[NIPL] = {
277 	[IPL_NONE]       = PSL_S|PSL_IPL0,
278 	[IPL_SOFTCLOCK]  = PSL_S|PSL_IPL1,
279 	[IPL_SOFTBIO]    = PSL_S|PSL_IPL1,
280 	[IPL_SOFTNET]    = PSL_S|PSL_IPL1,
281 	[IPL_SOFTSERIAL] = PSL_S|PSL_IPL1,
282 	[IPL_VM]         = PSL_S|PSL_IPL7,
283 	[IPL_SCHED]      = PSL_S|PSL_IPL7,
284 	[IPL_HIGH]       = PSL_S|PSL_IPL7,
285 };
286