xref: /netbsd-src/sys/arch/hppa/hppa/intr.c (revision ec6aa33e7a2f3f2be898b76a82d820ece4871c14)
1 /*	$NetBSD: intr.c,v 1.8 2022/09/29 06:39:59 skrll Exp $	*/
2 /*	$OpenBSD: intr.c,v 1.27 2009/12/31 12:52:35 jsing Exp $	*/
3 
4 /*
5  * Copyright (c) 2002 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Matthew Fredette.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  *
20  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
21  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
22  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
23  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
24  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
25  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
26  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
27  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
28  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
29  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
30  * POSSIBILITY OF SUCH DAMAGE.
31  */
32 
33 /*
34  * Interrupt handling for NetBSD/hppa.
35  */
36 
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.8 2022/09/29 06:39:59 skrll Exp $");
39 
40 #define __MUTEX_PRIVATE
41 
42 #include <sys/param.h>
43 #include <sys/cpu.h>
44 
45 #include <uvm/uvm_extern.h>
46 
47 #include <machine/autoconf.h>
48 #include <machine/cpufunc.h>
49 #include <machine/intr.h>
50 #include <machine/reg.h>
51 
52 #include <hppa/hppa/machdep.h>
53 
54 #include <machine/mutex.h>
55 
56 #if defined(_KERNEL_OPT)
57 #include "opt_lockdebug.h"
58 #endif
59 
60 static int hppa_intr_ipl_next(struct cpu_info *);
61 void hppa_intr_calculatemasks(struct cpu_info *);
62 int hppa_intr_ipending(struct hppa_interrupt_register *, int);
63 void hppa_intr_dispatch(int , int , struct trapframe *);
64 
65 /* The list of all interrupt registers. */
66 struct hppa_interrupt_register *hppa_interrupt_registers[HPPA_INTERRUPT_BITS];
67 
68 
69 /*
70  * This establishes a new interrupt register.
71  */
72 void
hppa_interrupt_register_establish(struct cpu_info * ci,struct hppa_interrupt_register * ir)73 hppa_interrupt_register_establish(struct cpu_info *ci,
74     struct hppa_interrupt_register *ir)
75 {
76 	int idx;
77 
78 	/* Initialize the register structure. */
79 	memset(ir, 0, sizeof(*ir));
80 	ir->ir_ci = ci;
81 
82 	for (idx = 0; idx < HPPA_INTERRUPT_BITS; idx++)
83 		ir->ir_bits_map[idx] = IR_BIT_UNUSED;
84 
85 	ir->ir_bits = ~0;
86 	/* Add this structure to the list. */
87 	for (idx = 0; idx < HPPA_INTERRUPT_BITS; idx++)
88 		if (hppa_interrupt_registers[idx] == NULL)
89 			break;
90 	if (idx == HPPA_INTERRUPT_BITS)
91 		panic("%s: too many regs", __func__);
92 	hppa_interrupt_registers[idx] = ir;
93 }
94 
95 /*
96  * This initialise interrupts for a CPU.
97  */
98 void
hppa_intr_initialise(struct cpu_info * ci)99 hppa_intr_initialise(struct cpu_info *ci)
100 {
101 	int i;
102 
103 	/* Initialize all prority level masks to mask everything. */
104 	for (i = 0; i < NIPL; i++)
105 		ci->ci_imask[i] = -1;
106 
107 	/* We are now at the highest priority level. */
108 	ci->ci_cpl = -1;
109 
110 	/* There are no pending interrupts. */
111 	ci->ci_ipending = 0;
112 
113 	/* We are not running an interrupt handler. */
114 	ci->ci_intr_depth = 0;
115 
116 	/* There are no interrupt handlers. */
117 	memset(ci->ci_ib, 0, sizeof(ci->ci_ib));
118 
119 	/* There are no interrupt registers. */
120 	memset(hppa_interrupt_registers, 0, sizeof(hppa_interrupt_registers));
121 }
122 
123 /*
124  * This establishes a new interrupt handler.
125  */
126 void *
hppa_intr_establish(int ipl,int (* handler)(void *),void * arg,struct hppa_interrupt_register * ir,int bit_pos)127 hppa_intr_establish(int ipl, int (*handler)(void *), void *arg,
128     struct hppa_interrupt_register *ir, int bit_pos)
129 {
130 	struct hppa_interrupt_bit *ib;
131 	struct cpu_info *ci = ir->ir_ci;
132 	int idx;
133 
134 	/* Panic on a bad interrupt bit. */
135 	if (bit_pos < 0 || bit_pos >= HPPA_INTERRUPT_BITS)
136 		panic("%s: bad interrupt bit %d", __func__, bit_pos);
137 
138 	/*
139 	 * Panic if this interrupt bit is already handled, but allow
140 	 * shared interrupts for cascaded registers, e.g. dino and gsc
141 	 * XXX This could be improved.
142 	 */
143 	if (handler != NULL) {
144 		if (IR_BIT_USED_P(ir->ir_bits_map[31 ^ bit_pos]))
145 			panic("%s: interrupt already handled", __func__);
146 	}
147 
148 	/*
149 	 * If this interrupt bit leads us to another interrupt register,
150 	 * simply note that in the mapping for the bit.
151 	 */
152 	if (handler == NULL) {
153 		for (idx = 1; idx < HPPA_INTERRUPT_BITS; idx++)
154 			if (hppa_interrupt_registers[idx] == arg)
155 				break;
156 		if (idx == HPPA_INTERRUPT_BITS)
157 			panic("%s: unknown int reg", __func__);
158 
159 		ir->ir_bits_map[31 ^ bit_pos] = IR_BIT_REG(idx);
160 
161 		return NULL;
162 	}
163 
164 	/*
165 	 * Otherwise, allocate a new bit in the spl.
166 	 */
167 	idx = hppa_intr_ipl_next(ir->ir_ci);
168 
169 	ir->ir_bits &= ~(1 << bit_pos);
170 	ir->ir_rbits &= ~(1 << bit_pos);
171 	if (!IR_BIT_USED_P(ir->ir_bits_map[31 ^ bit_pos])) {
172 		ir->ir_bits_map[31 ^ bit_pos] = 1 << idx;
173 	} else {
174 		int j;
175 
176 		ir->ir_bits_map[31 ^ bit_pos] |= 1 << idx;
177 		j = (ir - hppa_interrupt_registers[0]);
178 		ci->ci_ishared |= (1 << j);
179 	}
180 	ib = &ci->ci_ib[idx];
181 
182 	/* Fill this interrupt bit. */
183 	ib->ib_reg = ir;
184 	ib->ib_ipl = ipl;
185 	ib->ib_spl = (1 << idx);
186 	snprintf(ib->ib_name, sizeof(ib->ib_name), "irq %d", bit_pos);
187 
188 	evcnt_attach_dynamic(&ib->ib_evcnt, EVCNT_TYPE_INTR, NULL, ir->ir_name,
189 	     ib->ib_name);
190 	ib->ib_handler = handler;
191 	ib->ib_arg = arg;
192 
193 	hppa_intr_calculatemasks(ci);
194 
195 	return ib;
196 }
197 
198 /*
199  * This allocates an interrupt bit within an interrupt register.
200  * It returns the bit position, or -1 if no bits were available.
201  */
202 int
hppa_intr_allocate_bit(struct hppa_interrupt_register * ir,int irq)203 hppa_intr_allocate_bit(struct hppa_interrupt_register *ir, int irq)
204 {
205 	int bit_pos;
206 	int last_bit;
207 	u_int mask;
208 	int *bits;
209 
210 	if (irq == -1) {
211 		bit_pos = 31;
212 		last_bit = 0;
213 		bits = &ir->ir_bits;
214 	} else {
215 		bit_pos = irq;
216 		last_bit = irq;
217 		bits = &ir->ir_rbits;
218 	}
219 	for (mask = (1 << bit_pos); bit_pos >= last_bit; bit_pos--) {
220 		if (*bits & mask)
221 			break;
222 		mask >>= 1;
223 	}
224 	if (bit_pos >= last_bit) {
225 		*bits &= ~mask;
226 		return bit_pos;
227 	}
228 
229 	return -1;
230 }
231 
232 /*
233  * This returns the next available spl bit.
234  */
235 static int
hppa_intr_ipl_next(struct cpu_info * ci)236 hppa_intr_ipl_next(struct cpu_info *ci)
237 {
238 	int idx;
239 
240 	for (idx = 0; idx < HPPA_INTERRUPT_BITS; idx++)
241 		if (ci->ci_ib[idx].ib_reg == NULL)
242 			break;
243 	if (idx == HPPA_INTERRUPT_BITS)
244 		panic("%s: too many devices", __func__);
245 	return idx;
246 }
247 
248 /*
249  * This finally initializes interrupts.
250  */
251 void
hppa_intr_calculatemasks(struct cpu_info * ci)252 hppa_intr_calculatemasks(struct cpu_info *ci)
253 {
254 	struct hppa_interrupt_bit *ib;
255 	struct hppa_interrupt_register *ir;
256 	int idx, bit_pos;
257 	int mask;
258 	int ipl;
259 
260 	/*
261 	 * Put together the initial imask for each level.
262 	 */
263 	memset(ci->ci_imask, 0, sizeof(ci->ci_imask));
264 	for (bit_pos = 0; bit_pos < HPPA_INTERRUPT_BITS; bit_pos++) {
265 		ib = &ci->ci_ib[bit_pos];
266 		if (ib->ib_reg == NULL)
267 			continue;
268 		ci->ci_imask[ib->ib_ipl] |= ib->ib_spl;
269 	}
270 
271 	/*
272 	 * IPL_NONE is used for hardware interrupts that are never blocked,
273 	 * and do not block anything else.
274 	 */
275 	ci->ci_imask[IPL_NONE] = 0;
276 
277 	/*
278 	 * Enforce a hierarchy that gives slow devices a better chance at not
279 	 * dropping data.
280 	 */
281 	for (ipl = NIPL - 1; ipl > 0; ipl--)
282 		ci->ci_imask[ipl - 1] |= ci->ci_imask[ipl];
283 
284 	/*
285 	 * Load all mask registers, loading %eiem last.  This will finally
286 	 * enable interrupts, but since cpl and ipending should be -1 and 0,
287 	 * respectively, no interrupts will get dispatched until the priority
288 	 * level is lowered.
289 	 */
290 	KASSERT(ci->ci_cpl == -1);
291 	KASSERT(ci->ci_ipending == 0);
292 
293 	for (idx = 0; idx < HPPA_INTERRUPT_BITS; idx++) {
294 		ir = hppa_interrupt_registers[idx];
295 		if (ir == NULL || ir->ir_ci != ci)
296 			continue;
297 		mask = 0;
298 		for (bit_pos = 0; bit_pos < HPPA_INTERRUPT_BITS; bit_pos++) {
299 			if (!IR_BIT_UNUSED_P(ir->ir_bits_map[31 ^ bit_pos]))
300 				mask |= (1 << bit_pos);
301 		}
302 		if (ir->ir_iscpu)
303 			ir->ir_ci->ci_eiem = mask;
304 		else if (ir->ir_mask != NULL)
305 			*ir->ir_mask = mask;
306 	}
307 }
308 
309 void
hppa_intr_enable(void)310 hppa_intr_enable(void)
311 {
312 	struct cpu_info *ci = curcpu();
313 
314 	mtctl(ci->ci_eiem, CR_EIEM);
315 	ci->ci_psw |= PSW_I;
316 	hppa_enable_irq();
317 }
318 
319 
320 /*
321  * Service interrupts.  This doesn't necessarily dispatch them.  This is called
322  * with %eiem loaded with zero.  It's named hppa_intr instead of hppa_intr
323  * because trap.c calls it.
324  */
325 void
hppa_intr(struct trapframe * frame)326 hppa_intr(struct trapframe *frame)
327 {
328 	struct cpu_info *ci = curcpu();
329 	int eirr;
330 	int i;
331 
332 #ifndef LOCKDEBUG
333 	extern char mutex_enter_crit_start[];
334 	extern char mutex_enter_crit_end[];
335 
336 #ifndef	MULTIPROCESSOR
337 	extern char _lock_cas_ras_start[];
338 	extern char _lock_cas_ras_end[];
339 
340 	if (frame->tf_iisq_head == HPPA_SID_KERNEL &&
341 	    frame->tf_iioq_head > (u_int)_lock_cas_ras_start &&
342 	    frame->tf_iioq_head < (u_int)_lock_cas_ras_end) {
343 		frame->tf_iioq_head = (u_int)_lock_cas_ras_start;
344 		frame->tf_iioq_tail = (u_int)_lock_cas_ras_start + 4;
345 	}
346 #endif
347 
348 	/*
349 	 * If we interrupted in the middle of mutex_enter(), we must patch up
350 	 * the lock owner value quickly if we got the interlock.  If any of the
351 	 * interrupt handlers need to acquire the mutex, they could deadlock if
352 	 * the owner value is left unset.
353 	 */
354 	if (frame->tf_iisq_head == HPPA_SID_KERNEL &&
355 	    frame->tf_iioq_head > (u_int)mutex_enter_crit_start &&
356 	    frame->tf_iioq_head < (u_int)mutex_enter_crit_end &&
357 	    frame->tf_ret0 != 0)
358 		((kmutex_t *)frame->tf_arg0)->mtx_owner = (uintptr_t)curlwp;
359 #endif
360 
361 	/*
362 	 * Read the CPU interrupt register and acknowledge all interrupts.
363 	 * Starting with this value, get our set of new pending interrupts and
364 	 * add these new bits to ipending.
365 	 */
366 	mfctl(CR_EIRR, eirr);
367 	mtctl(eirr, CR_EIRR);
368 
369 	ci->ci_ipending |= hppa_intr_ipending(&ci->ci_ir, eirr);
370 
371 	i = 0;
372 	/* If we have interrupts to dispatch, do so. */
373 	while (ci->ci_ipending & ~ci->ci_cpl) {
374 		int shared;
375 
376 		hppa_intr_dispatch(ci->ci_cpl, frame->tf_eiem, frame);
377 
378 		shared = ci->ci_ishared;
379 		while (shared) {
380 			struct hppa_interrupt_register *sir;
381 			int sbit, lvl;
382 
383 			sbit = ffs(shared) - 1;
384 			sir = hppa_interrupt_registers[sbit];
385 			lvl = *sir->ir_level;
386 
387 			ci->ci_ipending |= hppa_intr_ipending(sir, lvl);
388 			shared &= ~(1 << sbit);
389 		}
390 		i++;
391 		KASSERTMSG(i <= 2,
392 		    "%s: ci->ipending %08x ci->ci_cpl %08x shared %08x\n",
393 		    __func__, ci->ci_ipending, ci->ci_cpl, shared);
394 	}
395 }
396 
397 /*
398  * Dispatch interrupts.  This dispatches at least one interrupt.
399  * This is called with %eiem loaded with zero.
400  */
401 void
hppa_intr_dispatch(int ncpl,int eiem,struct trapframe * frame)402 hppa_intr_dispatch(int ncpl, int eiem, struct trapframe *frame)
403 {
404 	struct cpu_info *ci = curcpu();
405 	struct hppa_interrupt_bit *ib;
406 	struct clockframe clkframe;
407 	int ipending_run;
408 	int bit_pos;
409 	void *arg;
410 	int handled __unused;
411 	bool locked = false;
412 
413 	/*
414 	 * Increment our depth
415 	 */
416 	ci->ci_intr_depth++;
417 
418 	/* Loop while we have interrupts to dispatch. */
419 	for (;;) {
420 
421 		/* Read ipending and mask it with ncpl. */
422 		ipending_run = (ci->ci_ipending & ~ncpl);
423 		if (ipending_run == 0)
424 			break;
425 
426 		/* Choose one of the resulting bits to dispatch. */
427 		bit_pos = ffs(ipending_run) - 1;
428 
429 		/*
430 		 * If this interrupt handler takes the clockframe
431 		 * as an argument, conjure one up.
432 		 */
433 		ib = &ci->ci_ib[bit_pos];
434 		ib->ib_evcnt.ev_count++;
435 		arg = ib->ib_arg;
436 		if (arg == NULL) {
437 			clkframe.cf_flags = (ci->ci_intr_depth > 1 ?
438 			    TFF_INTR : 0);
439 			clkframe.cf_spl = ncpl;
440 			if (frame != NULL) {
441 				clkframe.cf_flags |= frame->tf_flags;
442 				clkframe.cf_pc = frame->tf_iioq_head;
443 			}
444 			arg = &clkframe;
445 		}
446 
447 		/*
448 		 * Remove this bit from ipending, raise spl to
449 		 * the level required to run this interrupt,
450 		 * and reenable interrupts.
451 		 */
452 		ci->ci_ipending &= ~(1 << bit_pos);
453 		ci->ci_cpl = ncpl | ci->ci_imask[ib->ib_ipl];
454 		mtctl(eiem, CR_EIEM);
455 
456 		if (ib->ib_ipl == IPL_VM) {
457 			KERNEL_LOCK(1, NULL);
458 			locked = true;
459 		}
460 
461 		/* Count and dispatch the interrupt. */
462 		ci->ci_data.cpu_nintr++;
463 		handled = (*ib->ib_handler)(arg);
464 #if 0
465 		if (!handled)
466 			printf("%s: can't handle interrupt\n",
467 				ib->ib_evcnt.ev_name);
468 #endif
469 		if (locked) {
470 			KERNEL_UNLOCK_ONE(NULL);
471 			locked = false;
472 		}
473 
474 		/* Disable interrupts and loop. */
475 		mtctl(0, CR_EIEM);
476 	}
477 
478 	/* Interrupts are disabled again, restore cpl and the depth. */
479 	ci->ci_cpl = ncpl;
480 	ci->ci_intr_depth--;
481 }
482 
483 
484 int
hppa_intr_ipending(struct hppa_interrupt_register * ir,int eirr)485 hppa_intr_ipending(struct hppa_interrupt_register *ir, int eirr)
486 {
487 	int pending = 0;
488 	int idx;
489 
490 	for (idx = 31; idx >= 0; idx--) {
491 		if ((eirr & (1 << idx)) == 0)
492 			continue;
493 		if (IR_BIT_NESTED_P(ir->ir_bits_map[31 ^ idx])) {
494 			struct hppa_interrupt_register *nir;
495 			int reg = ir->ir_bits_map[31 ^ idx] & ~IR_BIT_MASK;
496 
497 			nir = hppa_interrupt_registers[reg];
498 			pending |= hppa_intr_ipending(nir, *(nir->ir_req));
499 		} else {
500 			pending |= ir->ir_bits_map[31 ^ idx];
501 		}
502 	}
503 
504 	return pending;
505 }
506 
507 bool
cpu_intr_p(void)508 cpu_intr_p(void)
509 {
510 	struct cpu_info *ci = curcpu();
511 
512 #ifdef __HAVE_FAST_SOFTINTS
513 #error this should not count fast soft interrupts
514 #else
515 	return ci->ci_intr_depth != 0;
516 #endif
517 }
518