xref: /openbsd-src/sys/arch/macppc/dev/openpic.c (revision be691f3bb6417f04a68938fadbcaee2d5795e764)
1 /*	$OpenBSD: openpic.c,v 1.87 2021/03/11 11:16:58 jsg Exp $	*/
2 
3 /*-
4  * Copyright (c) 2008 Dale Rahn <drahn@openbsd.org>
5  * Copyright (c) 1995 Per Fogelstrom
6  * Copyright (c) 1993, 1994 Charles M. Hannum.
7  * Copyright (c) 1990 The Regents of the University of California.
8  * All rights reserved.
9  *
10  * This code is derived from software contributed to Berkeley by
11  * William Jolitz and Don Ahn.
12  *
13  * Redistribution and use in source and binary forms, with or without
14  * modification, are permitted provided that the following conditions
15  * are met:
16  * 1. Redistributions of source code must retain the above copyright
17  *    notice, this list of conditions and the following disclaimer.
18  * 2. Redistributions in binary form must reproduce the above copyright
19  *    notice, this list of conditions and the following disclaimer in the
20  *    documentation and/or other materials provided with the distribution.
21  * 3. Neither the name of the University nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  *
37  *	@(#)isa.c	7.2 (Berkeley) 5/12/91
38  */
39 
40 #include "hpb.h"
41 
42 #include <sys/param.h>
43 #include <sys/device.h>
44 #include <sys/systm.h>
45 #include <sys/malloc.h>
46 #include <sys/atomic.h>
47 
48 #include <uvm/uvm_extern.h>
49 
50 #include <machine/autoconf.h>
51 #include <machine/intr.h>
52 #include <machine/psl.h>
53 #include <machine/pio.h>
54 #include <dev/ofw/openfirm.h>
55 
56 #include <macppc/dev/openpicreg.h>
57 
58 #ifdef OPENPIC_DEBUG
59 #define DPRINTF(x...)	do { printf(x); } while(0)
60 #else
61 #define DPRINTF(x...)
62 #endif
63 
64 #define ICU_LEN 128
65 int openpic_numirq = ICU_LEN;
66 #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
67 
68 int openpic_pri_share[IPL_NUM];
69 
70 struct intrq openpic_handler[ICU_LEN];
71 
72 struct openpic_softc {
73 	struct device sc_dev;
74 };
75 
76 vaddr_t openpic_base;
77 int	openpic_big_endian;
78 struct	evcount openpic_spurious;
79 int	openpic_spurious_irq = 255;
80 
81 int	openpic_match(struct device *parent, void *cf, void *aux);
82 void	openpic_attach(struct device *, struct device *, void *);
83 
84 int	openpic_splraise(int);
85 int	openpic_spllower(int);
86 void	openpic_splx(int);
87 
88 u_int	openpic_read(int reg);
89 void	openpic_write(int reg, u_int val);
90 
91 void	openpic_acknowledge_irq(int, int);
92 void	openpic_enable_irq(int, int, int);
93 void	openpic_disable_irq(int, int);
94 
95 void	openpic_calc_mask(void);
96 void	openpic_set_priority(int, int);
97 void	*openpic_intr_establish(void *, int, int, int, int (*)(void *), void *,
98 	    const char *);
99 void	openpic_intr_disestablish(void *, void *);
100 void	openpic_collect_preconf_intr(void);
101 void	openpic_ext_intr(void);
102 int	openpic_ext_intr_handler(struct intrhand *, int *);
103 
104 /* Generic IRQ management routines. */
105 void	openpic_gen_acknowledge_irq(int, int);
106 void	openpic_gen_enable_irq(int, int, int);
107 void	openpic_gen_disable_irq(int, int);
108 
109 #if NHPB > 0
110 /* CPC945 IRQ management routines. */
111 void	openpic_cpc945_acknowledge_irq(int, int);
112 void	openpic_cpc945_enable_irq(int, int, int);
113 void	openpic_cpc945_disable_irq(int, int);
114 #endif /* NHPB */
115 
116 struct openpic_ops {
117 	void	(*acknowledge_irq)(int, int);
118 	void	(*enable_irq)(int, int, int);
119 	void	(*disable_irq)(int, int);
120 } openpic_ops = {
121 	openpic_gen_acknowledge_irq,
122 	openpic_gen_enable_irq,
123 	openpic_gen_disable_irq
124 };
125 
126 #ifdef MULTIPROCESSOR
127 void	openpic_ipi_ddb(void);
128 
129 /* IRQ vector used for inter-processor interrupts. */
130 #define IPI_VECTOR_NOP	64
131 #define IPI_VECTOR_DDB	65
132 
133 static struct evcount ipi_count;
134 
135 static int ipi_irq = IPI_VECTOR_NOP;
136 
137 intr_send_ipi_t openpic_send_ipi;
138 #endif /* MULTIPROCESSOR */
139 
140 const struct cfattach openpic_ca = {
141 	sizeof(struct openpic_softc), openpic_match, openpic_attach
142 };
143 
144 struct cfdriver openpic_cd = {
145 	NULL, "openpic", DV_DULL
146 };
147 
148 u_int
149 openpic_read(int reg)
150 {
151 	char *addr = (void *)(openpic_base + reg);
152 
153 	membar_sync();
154 	if (openpic_big_endian)
155 		return in32(addr);
156 	else
157 		return in32rb(addr);
158 }
159 
160 void
161 openpic_write(int reg, u_int val)
162 {
163 	char *addr = (void *)(openpic_base + reg);
164 
165 	if (openpic_big_endian)
166 		out32(addr, val);
167 	else
168 		out32rb(addr, val);
169 	membar_sync();
170 }
171 
172 static inline int
173 openpic_read_irq(int cpu)
174 {
175 	return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
176 }
177 
178 static inline void
179 openpic_eoi(int cpu)
180 {
181 	openpic_write(OPENPIC_EOI(cpu), 0);
182 }
183 
184 int
185 openpic_match(struct device *parent, void *cf, void *aux)
186 {
187 	char type[40];
188 	int pirq;
189 	struct confargs *ca = aux;
190 
191 	bzero (type, sizeof(type));
192 
193 	if (OF_getprop(ca->ca_node, "interrupt-parent", &pirq, sizeof(pirq))
194 	    == sizeof(pirq))
195 		return 0; /* XXX */
196 
197 	if (strcmp(ca->ca_name, "interrupt-controller") != 0 &&
198 	    strcmp(ca->ca_name, "mpic") != 0)
199 		return 0;
200 
201 	OF_getprop(ca->ca_node, "device_type", type, sizeof(type));
202 	if (strcmp(type, "open-pic") != 0)
203 		return 0;
204 
205 	if (ca->ca_nreg < 8)
206 		return 0;
207 
208 	return 1;
209 }
210 
211 void
212 openpic_attach(struct device *parent, struct device *self, void *aux)
213 {
214 	struct cpu_info *ci = curcpu();
215 	struct confargs *ca = aux;
216 	struct intrq *iq;
217 	uint32_t reg = 0;
218 	int i, irq;
219 	u_int x;
220 
221 	if (OF_getprop(ca->ca_node, "big-endian", &reg, sizeof reg) == 0)
222 		openpic_big_endian = 1;
223 
224 	openpic_base = (vaddr_t) mapiodev (ca->ca_baseaddr +
225 			ca->ca_reg[0], 0x40000);
226 
227 	/* Reset the PIC */
228 	x = openpic_read(OPENPIC_CONFIG) | OPENPIC_CONFIG_RESET;
229 	openpic_write(OPENPIC_CONFIG, x);
230 
231 	while (openpic_read(OPENPIC_CONFIG) & OPENPIC_CONFIG_RESET)
232 		delay(100);
233 
234 	/* openpic may support more than 128 interrupts but driver doesn't */
235 	openpic_numirq = ((openpic_read(OPENPIC_FEATURE) >> 16) & 0x7f)+1;
236 
237 	printf(": version 0x%x feature %x %s",
238 	    openpic_read(OPENPIC_VENDOR_ID),
239 	    openpic_read(OPENPIC_FEATURE),
240 		openpic_big_endian ? "BE" : "LE" );
241 
242 	openpic_set_priority(ci->ci_cpuid, 15);
243 
244 	/* disable all interrupts */
245 	for (irq = 0; irq < openpic_numirq; irq++)
246 		openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK);
247 
248 	for (i = 0; i < openpic_numirq; i++) {
249 		iq = &openpic_handler[i];
250 		TAILQ_INIT(&iq->iq_list);
251 	}
252 
253 	/* we don't need 8259 pass through mode */
254 	x = openpic_read(OPENPIC_CONFIG);
255 	x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
256 	openpic_write(OPENPIC_CONFIG, x);
257 
258 	/* initialize all vectors to something sane */
259 	for (irq = 0; irq < ICU_LEN; irq++) {
260 		x = irq;
261 		x |= OPENPIC_IMASK;
262 		x |= OPENPIC_POLARITY_NEGATIVE;
263 		x |= OPENPIC_SENSE_LEVEL;
264 		x |= 8 << OPENPIC_PRIORITY_SHIFT;
265 		openpic_write(OPENPIC_SRC_VECTOR(irq), x);
266 	}
267 
268 	/* send all interrupts to cpu 0 */
269 	for (irq = 0; irq < openpic_numirq; irq++)
270 		openpic_write(OPENPIC_IDEST(irq), 1 << 0);
271 
272 	/* clear all pending interrunts */
273 	for (irq = 0; irq < ICU_LEN; irq++) {
274 		openpic_read_irq(ci->ci_cpuid);
275 		openpic_eoi(ci->ci_cpuid);
276 	}
277 
278 #ifdef MULTIPROCESSOR
279 	/* Set up inter-processor interrupts. */
280 	/* IPI0 - NOP */
281 	x = IPI_VECTOR_NOP;
282 	x |= 15 << OPENPIC_PRIORITY_SHIFT;
283 	openpic_write(OPENPIC_IPI_VECTOR(0), x);
284 	/* IPI1 - DDB */
285 	x = IPI_VECTOR_DDB;
286 	x |= 15 << OPENPIC_PRIORITY_SHIFT;
287 	openpic_write(OPENPIC_IPI_VECTOR(1), x);
288 
289 	evcount_attach(&ipi_count, "ipi", &ipi_irq);
290 #endif
291 
292 	/* clear all pending interrunts */
293 	for (irq = 0; irq < ICU_LEN; irq++) {
294 		openpic_read_irq(0);
295 		openpic_eoi(0);
296 	}
297 
298 #if 0
299 	openpic_write(OPENPIC_SPURIOUS_VECTOR, 255);
300 #endif
301 
302 #if NHPB > 0
303 	/* Only U4 systems have a big-endian MPIC. */
304 	if (openpic_big_endian) {
305 		openpic_ops.acknowledge_irq = openpic_cpc945_acknowledge_irq;
306 		openpic_ops.enable_irq = openpic_cpc945_enable_irq;
307 		openpic_ops.disable_irq = openpic_cpc945_disable_irq;
308 	}
309 #endif
310 
311 	install_extint(openpic_ext_intr);
312 
313 	openpic_set_priority(ci->ci_cpuid, 0);
314 
315 	intr_establish_func  = openpic_intr_establish;
316 	intr_disestablish_func = openpic_intr_disestablish;
317 #ifdef MULTIPROCESSOR
318 	intr_send_ipi_func = openpic_send_ipi;
319 #endif
320 
321 	ppc_smask_init();
322 
323 	openpic_collect_preconf_intr();
324 
325 	evcount_attach(&openpic_spurious, "spurious", &openpic_spurious_irq);
326 
327 	ppc_intr_func.raise = openpic_splraise;
328 	ppc_intr_func.lower = openpic_spllower;
329 	ppc_intr_func.x = openpic_splx;
330 
331 	openpic_set_priority(0, ci->ci_cpl);
332 
333 	ppc_intr_enable(1);
334 
335 	printf("\n");
336 }
337 
338 /* Must be called with interrupt disable. */
339 static inline void
340 openpic_setipl(int newcpl)
341 {
342 	struct cpu_info *ci = curcpu();
343 
344 	ci->ci_cpl = newcpl;
345 	openpic_set_priority(ci->ci_cpuid, newcpl);
346 }
347 
348 int
349 openpic_splraise(int newcpl)
350 {
351 	struct cpu_info *ci = curcpu();
352 	int ocpl = ci->ci_cpl;
353 	int s;
354 
355 	newcpl = openpic_pri_share[newcpl];
356 	if (ocpl > newcpl)
357 		newcpl = ocpl;
358 
359 	s = ppc_intr_disable();
360 	openpic_setipl(newcpl);
361 	ppc_intr_enable(s);
362 
363 	return ocpl;
364 }
365 
366 int
367 openpic_spllower(int newcpl)
368 {
369 	struct cpu_info *ci = curcpu();
370 	int ocpl = ci->ci_cpl;
371 
372 	openpic_splx(newcpl);
373 
374 	return ocpl;
375 }
376 
377 void
378 openpic_splx(int newcpl)
379 {
380 	struct cpu_info *ci = curcpu();
381 	int intr, s;
382 
383 	intr = ppc_intr_disable();
384 	openpic_setipl(newcpl);
385 	if (newcpl < IPL_SOFTTTY && (ci->ci_ipending & ppc_smask[newcpl])) {
386 		s = splsofttty();
387 		dosoftint(newcpl);
388 		openpic_setipl(s); /* no-overhead splx */
389 	}
390 	ppc_intr_enable(intr);
391 }
392 
393 void
394 openpic_collect_preconf_intr(void)
395 {
396 	int i;
397 	for (i = 0; i < ppc_configed_intr_cnt; i++) {
398 		DPRINTF("\n\t%s irq %d level %d fun %p arg %p",
399 		    ppc_configed_intr[i].ih_what, ppc_configed_intr[i].ih_irq,
400 		    ppc_configed_intr[i].ih_level, ppc_configed_intr[i].ih_fun,
401 		    ppc_configed_intr[i].ih_arg);
402 		openpic_intr_establish(NULL, ppc_configed_intr[i].ih_irq,
403 		    IST_LEVEL, ppc_configed_intr[i].ih_level,
404 		    ppc_configed_intr[i].ih_fun, ppc_configed_intr[i].ih_arg,
405 		    ppc_configed_intr[i].ih_what);
406 	}
407 }
408 
409 /*
410  * Register an interrupt handler.
411  */
412 void *
413 openpic_intr_establish(void *lcv, int irq, int type, int level,
414     int (*ih_fun)(void *), void *ih_arg, const char *name)
415 {
416 	struct intrhand *ih;
417 	struct intrq *iq;
418 	int s, flags;
419 
420 	if (!LEGAL_IRQ(irq) || type == IST_NONE) {
421 		printf("%s: bogus irq %d or type %d", __func__, irq, type);
422 		return (NULL);
423 	}
424 
425 	/* no point in sleeping unless someone can free memory. */
426 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
427 	if (ih == NULL)
428 		panic("%s: can't malloc handler info", __func__);
429 
430 	iq = &openpic_handler[irq];
431 	switch (iq->iq_ist) {
432 	case IST_NONE:
433 		iq->iq_ist = type;
434 		break;
435 	case IST_EDGE:
436 		intr_shared_edge = 1;
437 		/* FALLTHROUGH */
438 	case IST_LEVEL:
439 		if (type == iq->iq_ist)
440 			break;
441 	case IST_PULSE:
442 		if (type != IST_NONE)
443 			panic("intr_establish: can't share %s with %s",
444 			    ppc_intr_typename(iq->iq_ist),
445 			    ppc_intr_typename(type));
446 		break;
447 	}
448 
449 	flags = level & IPL_MPSAFE;
450 	level &= ~IPL_MPSAFE;
451 
452 	KASSERT(level <= IPL_TTY || level >= IPL_CLOCK || flags & IPL_MPSAFE);
453 
454 	ih->ih_fun = ih_fun;
455 	ih->ih_arg = ih_arg;
456 	ih->ih_level = level;
457 	ih->ih_flags = flags;
458 	ih->ih_irq = irq;
459 
460 	evcount_attach(&ih->ih_count, name, &ih->ih_irq);
461 
462 	/*
463 	 * Append handler to end of list
464 	 */
465 	s = ppc_intr_disable();
466 
467 	TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
468 	openpic_calc_mask();
469 
470 	ppc_intr_enable(s);
471 
472 	return (ih);
473 }
474 
475 /*
476  * Deregister an interrupt handler.
477  */
478 void
479 openpic_intr_disestablish(void *lcp, void *arg)
480 {
481 	struct intrhand *ih = arg;
482 	int irq = ih->ih_irq;
483 	struct intrq *iq = &openpic_handler[irq];
484 	int s;
485 
486 	if (!LEGAL_IRQ(irq)) {
487 		printf("%s: bogus irq %d", __func__, irq);
488 		return;
489 	}
490 
491 	/*
492 	 * Remove the handler from the chain.
493 	 */
494 	s = ppc_intr_disable();
495 
496 	TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
497 	openpic_calc_mask();
498 
499 	ppc_intr_enable(s);
500 
501 	evcount_detach(&ih->ih_count);
502 	free(ih, M_DEVBUF, sizeof *ih);
503 
504 	if (TAILQ_EMPTY(&iq->iq_list))
505 		iq->iq_ist = IST_NONE;
506 }
507 
508 /*
509  * Recalculate the interrupt masks from scratch.
510  * We could code special registry and deregistry versions of this function that
511  * would be faster, but the code would be nastier, and we don't expect this to
512  * happen very much anyway.
513  */
514 
515 void
516 openpic_calc_mask(void)
517 {
518 	struct cpu_info *ci = curcpu();
519 	int irq;
520 	struct intrhand *ih;
521 	int i;
522 
523 	/* disable all openpic interrupts */
524 	openpic_set_priority(ci->ci_cpuid, 15);
525 
526 	for (i = IPL_NONE; i < IPL_NUM; i++) {
527 		openpic_pri_share[i] = i;
528 	}
529 
530 	for (irq = 0; irq < openpic_numirq; irq++) {
531 		int maxipl = IPL_NONE;
532 		int minipl = IPL_HIGH;
533 		struct intrq *iq = &openpic_handler[irq];
534 
535 		TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
536 			if (ih->ih_level > maxipl)
537 				maxipl = ih->ih_level;
538 			if (ih->ih_level < minipl)
539 				minipl = ih->ih_level;
540 		}
541 
542 		if (maxipl == IPL_NONE) {
543 			minipl = IPL_NONE; /* Interrupt not enabled */
544 
545 			openpic_disable_irq(irq, iq->iq_ist);
546 		} else {
547 			for (i = minipl; i <= maxipl; i++) {
548 				openpic_pri_share[i] = maxipl;
549 			}
550 			openpic_enable_irq(irq, iq->iq_ist, maxipl);
551 		}
552 
553 		iq->iq_ipl = maxipl;
554 	}
555 
556 	/* restore interrupts */
557 	openpic_set_priority(ci->ci_cpuid, ci->ci_cpl);
558 }
559 
560 void
561 openpic_gen_acknowledge_irq(int irq, int cpuid)
562 {
563 	openpic_eoi(cpuid);
564 }
565 
566 void
567 openpic_gen_enable_irq(int irq, int ist, int pri)
568 {
569 	u_int x;
570 
571 	x = irq;
572 
573 	if (ist == IST_LEVEL)
574 		x |= OPENPIC_SENSE_LEVEL;
575 	else
576 		x |= OPENPIC_SENSE_EDGE;
577 	x |= OPENPIC_POLARITY_NEGATIVE;
578 	x |= pri << OPENPIC_PRIORITY_SHIFT;
579 	openpic_write(OPENPIC_SRC_VECTOR(irq), x);
580 }
581 
582 void
583 openpic_gen_disable_irq(int irq, int ist)
584 {
585 	u_int x;
586 
587 	x = openpic_read(OPENPIC_SRC_VECTOR(irq));
588 	x |= OPENPIC_IMASK;
589 	openpic_write(OPENPIC_SRC_VECTOR(irq), x);
590 }
591 
592 void
593 openpic_set_priority(int cpu, int pri)
594 {
595 	openpic_write(OPENPIC_CPU_PRIORITY(cpu), pri);
596 }
597 
598 int openpic_irqnest[PPC_MAXPROCS];
599 int openpic_irqloop[PPC_MAXPROCS];
600 
601 void
602 openpic_ext_intr(void)
603 {
604 	struct cpu_info *ci = curcpu();
605 	int irq, pcpl, ret;
606 	int maxipl = IPL_NONE;
607 	struct intrhand *ih;
608 	struct intrq *iq;
609 	int spurious;
610 
611 	pcpl = ci->ci_cpl;
612 
613 	openpic_irqloop[ci->ci_cpuid] = 0;
614 	irq = openpic_read_irq(ci->ci_cpuid);
615 	openpic_irqnest[ci->ci_cpuid]++;
616 
617 	while (irq != 255) {
618 		openpic_irqloop[ci->ci_cpuid]++;
619 #ifdef OPENPIC_DEBUG
620 		if (openpic_irqloop[ci->ci_cpuid] > 20 ||
621 		    openpic_irqnest[ci->ci_cpuid] > 3) {
622 			printf("irqloop %d irqnest %d\n",
623 			    openpic_irqloop[ci->ci_cpuid],
624 			    openpic_irqnest[ci->ci_cpuid]);
625 		}
626 #endif
627 		if (openpic_irqloop[ci->ci_cpuid] > 20) {
628 			DPRINTF("irqloop %d irqnest %d: returning\n",
629 			    openpic_irqloop[ci->ci_cpuid],
630 			    openpic_irqnest[ci->ci_cpuid]);
631 			openpic_irqnest[ci->ci_cpuid]--;
632 			return;
633 		}
634 #ifdef MULTIPROCESSOR
635 		if (irq == IPI_VECTOR_NOP || irq == IPI_VECTOR_DDB) {
636 			ipi_count.ec_count++;
637 			openpic_eoi(ci->ci_cpuid);
638 			if (irq == IPI_VECTOR_DDB)
639 				openpic_ipi_ddb();
640 			irq = openpic_read_irq(ci->ci_cpuid);
641 			continue;
642 		}
643 #endif
644 		iq = &openpic_handler[irq];
645 
646 #ifdef OPENPIC_DEBUG
647 		if (iq->iq_ipl <= pcpl)
648 			printf("invalid interrupt %d lvl %d at %d hw %d\n",
649 			    irq, iq->iq_ipl, pcpl,
650 			    openpic_read(OPENPIC_CPU_PRIORITY(ci->ci_cpuid)));
651 #endif
652 
653 		if (iq->iq_ipl > maxipl)
654 			maxipl = iq->iq_ipl;
655 		openpic_splraise(iq->iq_ipl);
656 		openpic_acknowledge_irq(irq, ci->ci_cpuid);
657 
658 		spurious = 1;
659 		TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
660 			ppc_intr_enable(1);
661 			ret = openpic_ext_intr_handler(ih, &spurious);
662 			(void)ppc_intr_disable();
663 			if (intr_shared_edge == 00 && ret == 1)
664 				break;
665  		}
666 		if (spurious) {
667 			openpic_spurious.ec_count++;
668 			DPRINTF("spurious intr %d\n", irq);
669 		}
670 
671 		uvmexp.intrs++;
672 		openpic_setipl(pcpl);
673 
674 		irq = openpic_read_irq(ci->ci_cpuid);
675 	}
676 
677 	openpic_splx(pcpl);	/* Process pendings. */
678 	openpic_irqnest[ci->ci_cpuid]--;
679 }
680 
681 int
682 openpic_ext_intr_handler(struct intrhand *ih, int *spurious)
683 {
684 	int ret;
685 #ifdef MULTIPROCESSOR
686 	int need_lock;
687 
688 	if (ih->ih_flags & IPL_MPSAFE)
689 		need_lock = 0;
690 	else
691 		need_lock = 1;
692 
693 	if (need_lock)
694 		KERNEL_LOCK();
695 #endif
696 	ret = (*ih->ih_fun)(ih->ih_arg);
697 	if (ret) {
698 		ih->ih_count.ec_count++;
699 		*spurious = 0;
700 	}
701 
702 #ifdef MULTIPROCESSOR
703 	if (need_lock)
704 		KERNEL_UNLOCK();
705 #endif
706 
707 	return (ret);
708 }
709 
710 void
711 openpic_acknowledge_irq(int irq, int cpuid)
712 {
713 	(openpic_ops.acknowledge_irq)(irq, cpuid);
714 }
715 
716 void
717 openpic_enable_irq(int irq, int ist, int pri)
718 {
719 	(openpic_ops.enable_irq)(irq, ist, pri);
720 }
721 
722 void
723 openpic_disable_irq(int irq, int ist)
724 {
725 	(openpic_ops.disable_irq)(irq, ist);
726 }
727 
728 #ifdef MULTIPROCESSOR
729 void
730 openpic_send_ipi(struct cpu_info *ci, int id)
731 {
732 	switch (id) {
733 	case PPC_IPI_NOP:
734 		id = 0;
735 		break;
736 	case PPC_IPI_DDB:
737 		id = 1;
738 		break;
739 	default:
740 		panic("invalid ipi send to cpu %d %d", ci->ci_cpuid, id);
741 	}
742 
743 	openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid);
744 }
745 
746 void
747 openpic_ipi_ddb(void)
748 {
749 #ifdef DDB
750 	db_enter();
751 #endif
752 }
753 #endif /* MULTIPROCESSOR */
754 
755 #if NHPB > 0
756 extern int	hpb_enable_irq(int, int);
757 extern int	hpb_disable_irq(int, int);
758 extern void	hpb_eoi(int);
759 
760 void
761 openpic_cpc945_acknowledge_irq(int irq, int cpuid)
762 {
763 	hpb_eoi(irq);
764 	openpic_gen_acknowledge_irq(irq, cpuid);
765 }
766 
767 void
768 openpic_cpc945_enable_irq(int irq, int ist, int pri)
769 {
770 	if (hpb_enable_irq(irq, ist)) {
771 		u_int x = irq;
772 
773 		x |= OPENPIC_SENSE_EDGE;
774 		x |= OPENPIC_POLARITY_POSITIVE;
775 		x |= pri << OPENPIC_PRIORITY_SHIFT;
776 		openpic_write(OPENPIC_SRC_VECTOR(irq), x);
777 
778 		hpb_eoi(irq);
779 	} else
780 		openpic_gen_enable_irq(irq, ist, pri);
781 }
782 
783 void
784 openpic_cpc945_disable_irq(int irq, int ist)
785 {
786 	hpb_disable_irq(irq, ist);
787 	openpic_gen_disable_irq(irq, ist);
788 }
789 #endif /* NHPB */
790 
791