xref: /netbsd/sys/arch/sun68k/sun68k/isr.c (revision e20e2cb2)
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