xref: /openbsd/sys/arch/hppa/hppa/intr.c (revision bee1c65a)
1 /*	$OpenBSD: intr.c,v 1.52 2024/10/23 07:52:55 mpi Exp $	*/
2 
3 /*
4  * Copyright (c) 2002-2004 Michael Shalayeff
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19  * IN NO EVENT SHALL THE AUTHOR OR HIS RELATIVES BE LIABLE FOR ANY DIRECT,
20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
22  * SERVICES; LOSS OF MIND, USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING
25  * IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
26  * THE POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/param.h>
30 #include <sys/systm.h>
31 #include <sys/kernel.h>
32 #include <sys/device.h>
33 #include <sys/evcount.h>
34 #include <sys/malloc.h>
35 #include <sys/atomic.h>
36 
37 #include <uvm/uvm_extern.h>
38 
39 #include <machine/autoconf.h>
40 #include <machine/frame.h>
41 #include <machine/reg.h>
42 
43 struct hppa_iv {
44 	char pri;
45 	char irq;
46 	char flags;
47 #define	HPPA_IV_CALL	0x01
48 #define	HPPA_IV_SOFT	0x02
49 	char pad;
50 	int pad2;
51 	int (*handler)(void *);
52 	void *arg;
53 	u_int bit;
54 	struct hppa_iv *share;
55 	struct hppa_iv *next;
56 	struct evcount *cnt;
57 } __packed;
58 
59 struct hppa_iv intr_store[8*2*CPU_NINTS] __attribute__ ((aligned(32))),
60     *intr_more = intr_store, *intr_list;
61 struct hppa_iv intr_table[CPU_NINTS] __attribute__ ((aligned(32))) = {
62 	{ IPL_SOFTCLOCK, 0, HPPA_IV_SOFT, 0, 0, NULL },
63 	{ IPL_SOFTNET  , 0, HPPA_IV_SOFT, 0, 0, NULL },
64 	{ 0 },
65 	{ 0 },
66 	{ IPL_SOFTTTY  , 0, HPPA_IV_SOFT, 0, 0, NULL }
67 };
68 volatile u_long imask[NIPL] = {
69 	0,
70 	1 << (IPL_SOFTCLOCK - 1),
71 	1 << (IPL_SOFTNET - 1),
72 	0,
73 	0,
74 	1 << (IPL_SOFTTTY - 1)
75 };
76 
77 #ifdef DIAGNOSTIC
78 void
splassert_check(int wantipl,const char * func)79 splassert_check(int wantipl, const char *func)
80 {
81 	struct cpu_info *ci = curcpu();
82 
83 	if (ci->ci_cpl < wantipl)
84 		splassert_fail(wantipl, ci->ci_cpl, func);
85 }
86 #endif
87 
88 void
cpu_intr_init(void)89 cpu_intr_init(void)
90 {
91 	struct cpu_info *ci = curcpu();
92 	struct hppa_iv *iv;
93 	int level, bit;
94 	u_long mask;
95 
96 	mask = ci->ci_mask | SOFTINT_MASK;
97 
98 	/* map the shared ints */
99 	while (intr_list) {
100 		iv = intr_list;
101 		intr_list = iv->next;
102 		bit = ffs(imask[(int)iv->pri]);
103 		if (!bit--) {
104 			bit = ffs(~mask);
105 			if (!bit--)
106 				panic("cpu_intr_init: out of bits");
107 
108 			iv->next = NULL;
109 			iv->bit = 1 << bit;
110 			intr_table[bit] = *iv;
111 			mask |= (1 << bit);
112 			imask[(int)iv->pri] |= (1 << bit);
113 		} else {
114 			iv->bit = 1 << bit;
115 			iv->next = intr_table[bit].next;
116 			intr_table[bit].next = iv;
117 		}
118 	}
119 
120 	for (level = 0; level < NIPL - 1; level++)
121 		imask[level + 1] |= imask[level];
122 
123 	/* XXX the whacky trick is to prevent hardclock from happening */
124 	mfctl(CR_ITMR, mask);
125 	mtctl(mask - 1, CR_ITMR);
126 
127 	mtctl(ci->ci_mask, CR_EIEM);
128 	/* ack the unwanted interrupts */
129 	mfctl(CR_EIRR, mask);
130 	mtctl(mask & (1U << 31), CR_EIRR);
131 
132 	/* in spl*() we trust, clock is started in initclocks() */
133 	ci->ci_psw |= PSL_I;
134 	ssm(PSL_I, mask);
135 }
136 
137 /*
138  * Find an available, non-shared interrupt bit.
139  * Returns -1 if all interrupt bits are in use.
140  */
141 int
cpu_intr_findirq(void)142 cpu_intr_findirq(void)
143 {
144 	int irq;
145 
146 	for (irq = 0; irq < CPU_NINTS; irq++)
147 		if (intr_table[irq].handler == NULL &&
148 		    intr_table[irq].pri == 0)
149 			return irq;
150 
151 	return -1;
152 }
153 
154 void *
cpu_intr_map(void * v,int pri,int irq,int (* handler)(void *),void * arg,const char * name)155 cpu_intr_map(void *v, int pri, int irq, int (*handler)(void *), void *arg,
156     const char *name)
157 {
158 	struct hppa_iv *iv, *pv = v, *ivb = pv->next;
159 	struct evcount *cnt;
160 
161 	if (irq < 0 || irq >= CPU_NINTS)
162 		return (NULL);
163 
164 	cnt = (struct evcount *)malloc(sizeof *cnt, M_DEVBUF, M_NOWAIT);
165 	if (!cnt)
166 		return (NULL);
167 
168 	iv = &ivb[irq];
169 	if (iv->handler) {
170 		if (!pv->share) {
171 			free(cnt, M_DEVBUF, sizeof *cnt);
172 			return (NULL);
173 		} else {
174 			iv = pv->share;
175 			pv->share = iv->share;
176 			iv->share = ivb[irq].share;
177 			ivb[irq].share = iv;
178 		}
179 	}
180 
181 	evcount_attach(cnt, name, NULL);
182 	iv->pri = pri;
183 	iv->irq = irq;
184 	iv->flags = 0;
185 	iv->handler = handler;
186 	iv->arg = arg;
187 	iv->cnt = cnt;
188 	iv->next = intr_list;
189 	intr_list = iv;
190 
191 	return (iv);
192 }
193 
194 void *
cpu_intr_establish(int pri,int irq,int (* handler)(void *),void * arg,const char * name)195 cpu_intr_establish(int pri, int irq, int (*handler)(void *), void *arg,
196     const char *name)
197 {
198 	struct cpu_info *ci = curcpu();
199 	struct hppa_iv *iv, *ev;
200 	struct evcount *cnt;
201 
202 	if (irq < 0 || irq >= CPU_NINTS || intr_table[irq].handler)
203 		return (NULL);
204 
205 	if ((intr_table[irq].flags & HPPA_IV_SOFT) != 0)
206 		return (NULL);
207 
208 	cnt = (struct evcount *)malloc(sizeof *cnt, M_DEVBUF, M_NOWAIT);
209 	if (!cnt)
210 		return (NULL);
211 
212 	ci->ci_mask |= (1 << irq);
213 	imask[pri] |= (1 << irq);
214 
215 	iv = &intr_table[irq];
216 	iv->pri = pri;
217 	iv->irq = irq;
218 	iv->bit = 1 << irq;
219 	iv->flags = 0;
220 	iv->handler = handler;
221 	iv->arg = arg;
222 	iv->cnt = cnt;
223 	iv->next = NULL;
224 	iv->share = NULL;
225 
226 	if (pri == IPL_NESTED) {
227 		iv->flags = HPPA_IV_CALL;
228 		iv->next = intr_more;
229 		intr_more += 2 * CPU_NINTS;
230 		for (ev = iv->next + CPU_NINTS; ev < intr_more; ev++)
231 			ev->share = iv->share, iv->share = ev;
232 		free(cnt, M_DEVBUF, sizeof *cnt);
233 		iv->cnt = NULL;
234 	} else if (name == NULL) {
235 		free(cnt, M_DEVBUF, sizeof *cnt);
236 		iv->cnt = NULL;
237 	} else
238 		evcount_attach(cnt, name, NULL);
239 
240 	return (iv);
241 }
242 
243 void
cpu_intr(void * v)244 cpu_intr(void *v)
245 {
246 	struct cpu_info *ci = curcpu();
247 	struct trapframe *frame = v;
248 	struct hppa_iv *iv;
249 	int pri, r, s, bit;
250 	u_long mask;
251 	void *arg;
252 
253 	mtctl(0, CR_EIEM);
254 
255 	s = ci->ci_cpl;
256 	if (ci->ci_idepth++)
257 		frame->tf_flags |= TFF_INTR;
258 
259 	/* Process higher priority interrupts first. */
260 	for (pri = NIPL - 1; pri > s; pri--) {
261 
262 		mask = imask[pri] ^ imask[pri - 1];
263 
264 		while (ci->ci_ipending & mask) {
265 			bit = fls(ci->ci_ipending & mask) - 1;
266 			iv = &intr_table[bit];
267 
268 			ci->ci_ipending &= ~(1L << bit);
269 
270 			if (iv->flags & HPPA_IV_CALL)
271 				continue;
272 
273 			uvmexp.intrs++;
274 			if (iv->flags & HPPA_IV_SOFT)
275 				uvmexp.softs++;
276 
277 			ci->ci_cpl = iv->pri;
278 			mtctl(frame->tf_eiem, CR_EIEM);
279 
280 #ifdef MULTIPROCESSOR
281 			if (pri < IPL_CLOCK)
282 				__mp_lock(&kernel_lock);
283 #endif
284 
285 			for (r = iv->flags & HPPA_IV_SOFT;
286 			     iv && iv->handler; iv = iv->next) {
287 				/* no arg means pass the frame */
288 				arg = iv->arg ? iv->arg : v;
289 				if ((iv->handler)(arg) == 1) {
290 					if (iv->cnt)
291 						iv->cnt->ec_count++;
292 					r |= 1;
293 				}
294 			}
295 #if 0	/* XXX this does not work, lasi gives us double ints */
296 			if (!r) {
297 				ci->ci_cpl = 0;
298 				printf("stray interrupt %d\n", bit);
299 			}
300 #endif
301 
302 #ifdef MULTIPROCESSOR
303 			if (pri < IPL_CLOCK)
304 				__mp_unlock(&kernel_lock);
305 #endif
306 			mtctl(0, CR_EIEM);
307 		}
308 	}
309 	ci->ci_idepth--;
310 	ci->ci_cpl = s;
311 
312 	mtctl(frame->tf_eiem, CR_EIEM);
313 }
314 
315 void
intr_barrier(void * cookie)316 intr_barrier(void *cookie)
317 {
318 	sched_barrier(NULL);
319 }
320 
321 void *
softintr_establish(int pri,void (* handler)(void *),void * arg)322 softintr_establish(int pri, void (*handler)(void *), void *arg)
323 {
324 	struct hppa_iv *iv;
325 	int irq;
326 
327 	if (pri == IPL_TTY)
328 		pri = IPL_SOFTTTY;
329 
330 	irq = pri - 1;
331 	iv = &intr_table[irq];
332 	if ((iv->flags & HPPA_IV_SOFT) == 0 || iv->pri != pri)
333 		return (NULL);
334 
335 	if (iv->handler) {
336 		struct hppa_iv *nv;
337 
338 		nv = malloc(sizeof *iv, M_DEVBUF, M_NOWAIT);
339 		if (!nv)
340 			return (NULL);
341 		while (iv->next)
342 			iv = iv->next;
343 		iv->next = nv;
344 		iv = nv;
345 	} else
346 		imask[pri] |= (1 << irq);
347 
348 	iv->pri = pri;
349 	iv->irq = 0;
350 	iv->bit = 1 << irq;
351 	iv->flags = HPPA_IV_SOFT;
352 	iv->handler = (int (*)(void *))handler;	/* XXX */
353 	iv->arg = arg;
354 	iv->cnt = NULL;
355 	iv->next = NULL;
356 	iv->share = NULL;
357 
358 	return (iv);
359 }
360 
361 void
softintr_disestablish(void * cookie)362 softintr_disestablish(void *cookie)
363 {
364 	struct hppa_iv *iv = cookie;
365 	int irq = iv->pri - 1;
366 
367 	if (&intr_table[irq] == cookie) {
368 		if (iv->next) {
369 			struct hppa_iv *nv = iv->next;
370 
371 			iv->handler = nv->handler;
372 			iv->arg = nv->arg;
373 			iv->next = nv->next;
374 			free(nv, M_DEVBUF, sizeof *nv);
375 			return;
376 		} else {
377 			iv->handler = NULL;
378 			iv->arg = NULL;
379 			return;
380 		}
381 	}
382 
383 	for (iv = &intr_table[irq]; iv; iv = iv->next) {
384 		if (iv->next == cookie) {
385 			iv->next = iv->next->next;
386 			free(cookie, M_DEVBUF, 0);
387 			return;
388 		}
389 	}
390 }
391 
392 void
softintr_schedule(void * cookie)393 softintr_schedule(void *cookie)
394 {
395 	struct hppa_iv *iv = cookie;
396 
397 	atomic_setbits_long(&curcpu()->ci_ipending, 1 << (iv->pri - 1));
398 }
399