xref: /openbsd/sys/arch/macppc/dev/openpic.c (revision de052479)
1 /*	$OpenBSD: openpic.c,v 1.90 2022/07/24 00:28:09 cheloha 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
openpic_read(int reg)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
openpic_write(int reg,u_int val)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
openpic_read_irq(int cpu)173 openpic_read_irq(int cpu)
174 {
175 	return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
176 }
177 
178 static inline void
openpic_eoi(int cpu)179 openpic_eoi(int cpu)
180 {
181 	openpic_write(OPENPIC_EOI(cpu), 0);
182 }
183 
184 int
openpic_match(struct device * parent,void * cf,void * aux)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
openpic_attach(struct device * parent,struct device * self,void * aux)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 interrupts */
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 interrupts */
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
openpic_setipl(int newcpl)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
openpic_splraise(int newcpl)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
openpic_spllower(int newcpl)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
openpic_splx(int newcpl)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 (ci->ci_dec_deferred && newcpl < IPL_CLOCK) {
386 		ppc_mtdec(0);
387 		ppc_mtdec(UINT32_MAX);	/* raise DEC exception */
388 	}
389 	if (newcpl < IPL_SOFTTTY && (ci->ci_ipending & ppc_smask[newcpl])) {
390 		s = splsofttty();
391 		dosoftint(newcpl);
392 		openpic_setipl(s); /* no-overhead splx */
393 	}
394 	ppc_intr_enable(intr);
395 }
396 
397 void
openpic_collect_preconf_intr(void)398 openpic_collect_preconf_intr(void)
399 {
400 	int i;
401 	for (i = 0; i < ppc_configed_intr_cnt; i++) {
402 		DPRINTF("\n\t%s irq %d level %d fun %p arg %p",
403 		    ppc_configed_intr[i].ih_what, ppc_configed_intr[i].ih_irq,
404 		    ppc_configed_intr[i].ih_level, ppc_configed_intr[i].ih_fun,
405 		    ppc_configed_intr[i].ih_arg);
406 		openpic_intr_establish(NULL, ppc_configed_intr[i].ih_irq,
407 		    IST_LEVEL, ppc_configed_intr[i].ih_level,
408 		    ppc_configed_intr[i].ih_fun, ppc_configed_intr[i].ih_arg,
409 		    ppc_configed_intr[i].ih_what);
410 	}
411 }
412 
413 /*
414  * Register an interrupt handler.
415  */
416 void *
openpic_intr_establish(void * lcv,int irq,int type,int level,int (* ih_fun)(void *),void * ih_arg,const char * name)417 openpic_intr_establish(void *lcv, int irq, int type, int level,
418     int (*ih_fun)(void *), void *ih_arg, const char *name)
419 {
420 	struct intrhand *ih;
421 	struct intrq *iq;
422 	int s, flags;
423 
424 	if (!LEGAL_IRQ(irq) || type == IST_NONE) {
425 		printf("%s: bogus irq %d or type %d", __func__, irq, type);
426 		return (NULL);
427 	}
428 
429 	/* no point in sleeping unless someone can free memory. */
430 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
431 	if (ih == NULL)
432 		panic("%s: can't malloc handler info", __func__);
433 
434 	iq = &openpic_handler[irq];
435 	switch (iq->iq_ist) {
436 	case IST_NONE:
437 		iq->iq_ist = type;
438 		break;
439 	case IST_EDGE:
440 		intr_shared_edge = 1;
441 		/* FALLTHROUGH */
442 	case IST_LEVEL:
443 		if (type == iq->iq_ist)
444 			break;
445 	case IST_PULSE:
446 		if (type != IST_NONE)
447 			panic("intr_establish: can't share %s with %s",
448 			    ppc_intr_typename(iq->iq_ist),
449 			    ppc_intr_typename(type));
450 		break;
451 	}
452 
453 	flags = level & IPL_MPSAFE;
454 	level &= ~IPL_MPSAFE;
455 
456 	KASSERT(level <= IPL_TTY || level >= IPL_CLOCK || flags & IPL_MPSAFE);
457 
458 	ih->ih_fun = ih_fun;
459 	ih->ih_arg = ih_arg;
460 	ih->ih_level = level;
461 	ih->ih_flags = flags;
462 	ih->ih_irq = irq;
463 
464 	evcount_attach(&ih->ih_count, name, &ih->ih_irq);
465 
466 	/*
467 	 * Append handler to end of list
468 	 */
469 	s = ppc_intr_disable();
470 
471 	TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
472 	openpic_calc_mask();
473 
474 	ppc_intr_enable(s);
475 
476 	return (ih);
477 }
478 
479 /*
480  * Deregister an interrupt handler.
481  */
482 void
openpic_intr_disestablish(void * lcp,void * arg)483 openpic_intr_disestablish(void *lcp, void *arg)
484 {
485 	struct intrhand *ih = arg;
486 	int irq = ih->ih_irq;
487 	struct intrq *iq;
488 	int s;
489 
490 	if (!LEGAL_IRQ(irq)) {
491 		printf("%s: bogus irq %d", __func__, irq);
492 		return;
493 	}
494 	iq = &openpic_handler[irq];
495 
496 	/*
497 	 * Remove the handler from the chain.
498 	 */
499 	s = ppc_intr_disable();
500 
501 	TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
502 	openpic_calc_mask();
503 
504 	ppc_intr_enable(s);
505 
506 	evcount_detach(&ih->ih_count);
507 	free(ih, M_DEVBUF, sizeof *ih);
508 
509 	if (TAILQ_EMPTY(&iq->iq_list))
510 		iq->iq_ist = IST_NONE;
511 }
512 
513 /*
514  * Recalculate the interrupt masks from scratch.
515  * We could code special registry and deregistry versions of this function that
516  * would be faster, but the code would be nastier, and we don't expect this to
517  * happen very much anyway.
518  */
519 
520 void
openpic_calc_mask(void)521 openpic_calc_mask(void)
522 {
523 	struct cpu_info *ci = curcpu();
524 	int irq;
525 	struct intrhand *ih;
526 	int i;
527 
528 	/* disable all openpic interrupts */
529 	openpic_set_priority(ci->ci_cpuid, 15);
530 
531 	for (i = IPL_NONE; i < IPL_NUM; i++) {
532 		openpic_pri_share[i] = i;
533 	}
534 
535 	for (irq = 0; irq < openpic_numirq; irq++) {
536 		int maxipl = IPL_NONE;
537 		int minipl = IPL_HIGH;
538 		struct intrq *iq = &openpic_handler[irq];
539 
540 		TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
541 			if (ih->ih_level > maxipl)
542 				maxipl = ih->ih_level;
543 			if (ih->ih_level < minipl)
544 				minipl = ih->ih_level;
545 		}
546 
547 		if (maxipl == IPL_NONE) {
548 			minipl = IPL_NONE; /* Interrupt not enabled */
549 
550 			openpic_disable_irq(irq, iq->iq_ist);
551 		} else {
552 			for (i = minipl; i <= maxipl; i++) {
553 				openpic_pri_share[i] = maxipl;
554 			}
555 			openpic_enable_irq(irq, iq->iq_ist, maxipl);
556 		}
557 
558 		iq->iq_ipl = maxipl;
559 	}
560 
561 	/* restore interrupts */
562 	openpic_set_priority(ci->ci_cpuid, ci->ci_cpl);
563 }
564 
565 void
openpic_gen_acknowledge_irq(int irq,int cpuid)566 openpic_gen_acknowledge_irq(int irq, int cpuid)
567 {
568 	openpic_eoi(cpuid);
569 }
570 
571 void
openpic_gen_enable_irq(int irq,int ist,int pri)572 openpic_gen_enable_irq(int irq, int ist, int pri)
573 {
574 	u_int x;
575 
576 	x = irq;
577 
578 	if (ist == IST_LEVEL)
579 		x |= OPENPIC_SENSE_LEVEL;
580 	else
581 		x |= OPENPIC_SENSE_EDGE;
582 	x |= OPENPIC_POLARITY_NEGATIVE;
583 	x |= pri << OPENPIC_PRIORITY_SHIFT;
584 	openpic_write(OPENPIC_SRC_VECTOR(irq), x);
585 }
586 
587 void
openpic_gen_disable_irq(int irq,int ist)588 openpic_gen_disable_irq(int irq, int ist)
589 {
590 	u_int x;
591 
592 	x = openpic_read(OPENPIC_SRC_VECTOR(irq));
593 	x |= OPENPIC_IMASK;
594 	openpic_write(OPENPIC_SRC_VECTOR(irq), x);
595 }
596 
597 void
openpic_set_priority(int cpu,int pri)598 openpic_set_priority(int cpu, int pri)
599 {
600 	openpic_write(OPENPIC_CPU_PRIORITY(cpu), pri);
601 }
602 
603 int openpic_irqnest[PPC_MAXPROCS];
604 int openpic_irqloop[PPC_MAXPROCS];
605 
606 void
openpic_ext_intr(void)607 openpic_ext_intr(void)
608 {
609 	struct cpu_info *ci = curcpu();
610 	int irq, pcpl, ret;
611 	int maxipl = IPL_NONE;
612 	struct intrhand *ih;
613 	struct intrq *iq;
614 	int spurious;
615 
616 	pcpl = ci->ci_cpl;
617 
618 	openpic_irqloop[ci->ci_cpuid] = 0;
619 	irq = openpic_read_irq(ci->ci_cpuid);
620 	openpic_irqnest[ci->ci_cpuid]++;
621 
622 	while (irq != 255) {
623 		openpic_irqloop[ci->ci_cpuid]++;
624 #ifdef OPENPIC_DEBUG
625 		if (openpic_irqloop[ci->ci_cpuid] > 20 ||
626 		    openpic_irqnest[ci->ci_cpuid] > 3) {
627 			printf("irqloop %d irqnest %d\n",
628 			    openpic_irqloop[ci->ci_cpuid],
629 			    openpic_irqnest[ci->ci_cpuid]);
630 		}
631 #endif
632 		if (openpic_irqloop[ci->ci_cpuid] > 20) {
633 			DPRINTF("irqloop %d irqnest %d: returning\n",
634 			    openpic_irqloop[ci->ci_cpuid],
635 			    openpic_irqnest[ci->ci_cpuid]);
636 			openpic_irqnest[ci->ci_cpuid]--;
637 			return;
638 		}
639 #ifdef MULTIPROCESSOR
640 		if (irq == IPI_VECTOR_NOP || irq == IPI_VECTOR_DDB) {
641 			ipi_count.ec_count++;
642 			openpic_eoi(ci->ci_cpuid);
643 			if (irq == IPI_VECTOR_DDB)
644 				openpic_ipi_ddb();
645 			irq = openpic_read_irq(ci->ci_cpuid);
646 			continue;
647 		}
648 #endif
649 		iq = &openpic_handler[irq];
650 
651 #ifdef OPENPIC_DEBUG
652 		if (iq->iq_ipl <= pcpl)
653 			printf("invalid interrupt %d lvl %d at %d hw %d\n",
654 			    irq, iq->iq_ipl, pcpl,
655 			    openpic_read(OPENPIC_CPU_PRIORITY(ci->ci_cpuid)));
656 #endif
657 
658 		if (iq->iq_ipl > maxipl)
659 			maxipl = iq->iq_ipl;
660 		openpic_splraise(iq->iq_ipl);
661 		openpic_acknowledge_irq(irq, ci->ci_cpuid);
662 
663 		spurious = 1;
664 		TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
665 			ppc_intr_enable(1);
666 			ret = openpic_ext_intr_handler(ih, &spurious);
667 			(void)ppc_intr_disable();
668 			if (intr_shared_edge == 00 && ret == 1)
669 				break;
670  		}
671 		if (spurious) {
672 			openpic_spurious.ec_count++;
673 			DPRINTF("spurious intr %d\n", irq);
674 		}
675 
676 		uvmexp.intrs++;
677 		openpic_setipl(pcpl);
678 
679 		irq = openpic_read_irq(ci->ci_cpuid);
680 	}
681 
682 	openpic_splx(pcpl);	/* Process pendings. */
683 	openpic_irqnest[ci->ci_cpuid]--;
684 }
685 
686 int
openpic_ext_intr_handler(struct intrhand * ih,int * spurious)687 openpic_ext_intr_handler(struct intrhand *ih, int *spurious)
688 {
689 	int ret;
690 #ifdef MULTIPROCESSOR
691 	int need_lock;
692 
693 	if (ih->ih_flags & IPL_MPSAFE)
694 		need_lock = 0;
695 	else
696 		need_lock = 1;
697 
698 	if (need_lock)
699 		KERNEL_LOCK();
700 #endif
701 	ret = (*ih->ih_fun)(ih->ih_arg);
702 	if (ret) {
703 		ih->ih_count.ec_count++;
704 		*spurious = 0;
705 	}
706 
707 #ifdef MULTIPROCESSOR
708 	if (need_lock)
709 		KERNEL_UNLOCK();
710 #endif
711 
712 	return (ret);
713 }
714 
715 void
openpic_acknowledge_irq(int irq,int cpuid)716 openpic_acknowledge_irq(int irq, int cpuid)
717 {
718 	(openpic_ops.acknowledge_irq)(irq, cpuid);
719 }
720 
721 void
openpic_enable_irq(int irq,int ist,int pri)722 openpic_enable_irq(int irq, int ist, int pri)
723 {
724 	(openpic_ops.enable_irq)(irq, ist, pri);
725 }
726 
727 void
openpic_disable_irq(int irq,int ist)728 openpic_disable_irq(int irq, int ist)
729 {
730 	(openpic_ops.disable_irq)(irq, ist);
731 }
732 
733 #ifdef MULTIPROCESSOR
734 void
openpic_send_ipi(struct cpu_info * ci,int id)735 openpic_send_ipi(struct cpu_info *ci, int id)
736 {
737 	switch (id) {
738 	case PPC_IPI_NOP:
739 		id = 0;
740 		break;
741 	case PPC_IPI_DDB:
742 		id = 1;
743 		break;
744 	default:
745 		panic("invalid ipi send to cpu %d %d", ci->ci_cpuid, id);
746 	}
747 
748 	openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid);
749 }
750 
751 void
openpic_ipi_ddb(void)752 openpic_ipi_ddb(void)
753 {
754 #ifdef DDB
755 	db_enter();
756 #endif
757 }
758 #endif /* MULTIPROCESSOR */
759 
760 #if NHPB > 0
761 extern int	hpb_enable_irq(int, int);
762 extern int	hpb_disable_irq(int, int);
763 extern void	hpb_eoi(int);
764 
765 void
openpic_cpc945_acknowledge_irq(int irq,int cpuid)766 openpic_cpc945_acknowledge_irq(int irq, int cpuid)
767 {
768 	hpb_eoi(irq);
769 	openpic_gen_acknowledge_irq(irq, cpuid);
770 }
771 
772 void
openpic_cpc945_enable_irq(int irq,int ist,int pri)773 openpic_cpc945_enable_irq(int irq, int ist, int pri)
774 {
775 	if (hpb_enable_irq(irq, ist)) {
776 		u_int x = irq;
777 
778 		x |= OPENPIC_SENSE_EDGE;
779 		x |= OPENPIC_POLARITY_POSITIVE;
780 		x |= pri << OPENPIC_PRIORITY_SHIFT;
781 		openpic_write(OPENPIC_SRC_VECTOR(irq), x);
782 
783 		hpb_eoi(irq);
784 	} else
785 		openpic_gen_enable_irq(irq, ist, pri);
786 }
787 
788 void
openpic_cpc945_disable_irq(int irq,int ist)789 openpic_cpc945_disable_irq(int irq, int ist)
790 {
791 	hpb_disable_irq(irq, ist);
792 	openpic_gen_disable_irq(irq, ist);
793 }
794 #endif /* NHPB */
795 
796