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