xref: /openbsd/sys/arch/macppc/dev/openpic.c (revision 404b540a)
1 /*	$OpenBSD: openpic.c,v 1.58 2009/10/01 20:19:18 kettenis Exp $	*/
2 
3 /*-
4  * Copyright (c) 1995 Per Fogelstrom
5  * Copyright (c) 1993, 1994 Charles M. Hannum.
6  * Copyright (c) 1990 The Regents of the University of California.
7  * All rights reserved.
8  *
9  * This code is derived from software contributed to Berkeley by
10  * William Jolitz and Don Ahn.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  * 3. Neither the name of the University nor the names of its contributors
21  *    may be used to endorse or promote products derived from this software
22  *    without specific prior written permission.
23  *
24  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34  * SUCH DAMAGE.
35  *
36  *	@(#)isa.c	7.2 (Berkeley) 5/12/91
37  */
38 
39 #include <sys/param.h>
40 #include <sys/device.h>
41 #include <sys/ioctl.h>
42 #include <sys/mbuf.h>
43 #include <sys/socket.h>
44 #include <sys/systm.h>
45 
46 #include <uvm/uvm.h>
47 #include <ddb/db_var.h>
48 
49 #include <machine/atomic.h>
50 #include <machine/autoconf.h>
51 #include <machine/intr.h>
52 #include <machine/psl.h>
53 #include <machine/pio.h>
54 #include <machine/powerpc.h>
55 #include <macppc/dev/openpicreg.h>
56 #include <dev/ofw/openfirm.h>
57 
58 #define ICU_LEN 128
59 #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
60 
61 int o_intrtype[ICU_LEN], o_intrmaxlvl[ICU_LEN];
62 struct intrhand *o_intrhand[ICU_LEN] = { 0 };
63 int o_hwirq[ICU_LEN], o_virq[ICU_LEN];
64 int o_virq_max;
65 
66 static int fakeintr(void *);
67 static char *intr_typename(int type);
68 void openpic_calc_mask(void);
69 static __inline int cntlzw(int x);
70 static int mapirq(int irq);
71 int openpic_prog_button(void *arg);
72 void openpic_enable_irq_mask(int irq_mask);
73 
74 #define HWIRQ_MAX (31 - (SI_NQUEUES + 1))
75 #define HWIRQ_MASK (0xffffffff >> (SI_NQUEUES + 1))
76 
77 /* IRQ vector used for inter-processor interrupts. */
78 #define IPI_VECTOR_NOP	64
79 #define IPI_VECTOR_DDB	65
80 #ifdef MULTIPROCESSOR
81 static struct evcount ipi_ddb[PPC_MAXPROCS];
82 static struct evcount ipi_nop[PPC_MAXPROCS];
83 static int ipi_nopirq = IPI_VECTOR_NOP;
84 static int ipi_ddbirq = IPI_VECTOR_DDB;
85 #endif
86 
87 static __inline u_int openpic_read(int);
88 static __inline void openpic_write(int, u_int);
89 void openpic_set_enable_irq(int, int);
90 void openpic_enable_irq(int);
91 void openpic_disable_irq(int);
92 void openpic_init(void);
93 void openpic_set_priority(int, int);
94 void openpic_ipi_ddb(void);
95 static __inline int openpic_read_irq(int);
96 static __inline void openpic_eoi(int);
97 
98 struct openpic_softc {
99 	struct device sc_dev;
100 };
101 
102 int	openpic_match(struct device *parent, void *cf, void *aux);
103 void	openpic_attach(struct device *, struct device *, void *);
104 void	openpic_do_pending_int(void);
105 void	openpic_collect_preconf_intr(void);
106 void	ext_intr_openpic(void);
107 
108 struct cfattach openpic_ca = {
109 	sizeof(struct openpic_softc),
110 	openpic_match,
111 	openpic_attach
112 };
113 
114 struct cfdriver openpic_cd = {
115 	NULL, "openpic", DV_DULL
116 };
117 
118 int
119 openpic_match(struct device *parent, void *cf, void *aux)
120 {
121 	char type[40];
122 	int pirq;
123 	struct confargs *ca = aux;
124 
125 	bzero (type, sizeof(type));
126 
127 	if (OF_getprop(ca->ca_node, "interrupt-parent", &pirq, sizeof(pirq))
128 	    == sizeof(pirq))
129 		return 0; /* XXX */
130 
131 	if (strcmp(ca->ca_name, "interrupt-controller") != 0 &&
132 	    strcmp(ca->ca_name, "mpic") != 0)
133 		return 0;
134 
135 	OF_getprop(ca->ca_node, "device_type", type, sizeof(type));
136 	if (strcmp(type, "open-pic") != 0)
137 		return 0;
138 
139 	if (ca->ca_nreg < 8)
140 		return 0;
141 
142 	return 1;
143 }
144 
145 typedef void  (void_f) (void);
146 extern void_f *pending_int_f;
147 
148 vaddr_t openpic_base;
149 void * openpic_intr_establish( void * lcv, int irq, int type, int level,
150 	int (*ih_fun)(void *), void *ih_arg, const char *name);
151 void openpic_intr_disestablish( void *lcp, void *arg);
152 #ifdef MULTIPROCESSOR
153 intr_send_ipi_t openpic_send_ipi;
154 #endif
155 void openpic_collect_preconf_intr(void);
156 int openpic_big_endian;
157 
158 void
159 openpic_attach(struct device *parent, struct device  *self, void *aux)
160 {
161 	struct confargs *ca = aux;
162 	u_int32_t reg;
163 
164 	reg = 0;
165 	if (OF_getprop(ca->ca_node, "big-endian", &reg, sizeof reg) == 0)
166 		openpic_big_endian = 1;
167 
168 	openpic_base = (vaddr_t) mapiodev (ca->ca_baseaddr +
169 			ca->ca_reg[0], 0x40000);
170 
171 	printf(": version 0x%x %s endian", openpic_read(OPENPIC_VENDOR_ID),
172 		openpic_big_endian ? "big" : "little" );
173 
174 	openpic_init();
175 
176 	pending_int_f = openpic_do_pending_int;
177 	intr_establish_func  = openpic_intr_establish;
178 	intr_disestablish_func  = openpic_intr_disestablish;
179 	mac_intr_establish_func  = openpic_intr_establish;
180 	mac_intr_disestablish_func  = openpic_intr_disestablish;
181 #ifdef MULTIPROCESSOR
182 	intr_send_ipi_func = openpic_send_ipi;
183 #endif
184 	install_extint(ext_intr_openpic);
185 
186 #if 1
187 	openpic_collect_preconf_intr();
188 #endif
189 
190 #if 1
191 	mac_intr_establish(parent, 0x37, IST_LEVEL,
192 		IPL_HIGH, openpic_prog_button, (void *)0x37, "progbutton");
193 #endif
194 
195 	ppc_intr_enable(1);
196 
197 	printf("\n");
198 }
199 
200 void
201 openpic_collect_preconf_intr()
202 {
203 	int i;
204 	for (i = 0; i < ppc_configed_intr_cnt; i++) {
205 #ifdef DEBUG
206 		printf("\n\t%s irq %d level %d fun %x arg %x",
207 		    ppc_configed_intr[i].ih_what, ppc_configed_intr[i].ih_irq,
208 		    ppc_configed_intr[i].ih_level, ppc_configed_intr[i].ih_fun,
209 		    ppc_configed_intr[i].ih_arg);
210 #endif
211 		openpic_intr_establish(NULL, ppc_configed_intr[i].ih_irq,
212 		    IST_LEVEL, ppc_configed_intr[i].ih_level,
213 		    ppc_configed_intr[i].ih_fun, ppc_configed_intr[i].ih_arg,
214 		    ppc_configed_intr[i].ih_what);
215 	}
216 }
217 
218 static int
219 fakeintr(void *arg)
220 {
221 
222 	return 0;
223 }
224 
225 /*
226  * Register an interrupt handler.
227  */
228 void *
229 openpic_intr_establish(void *lcv, int irq, int type, int level,
230     int (*ih_fun)(void *), void *ih_arg, const char *name)
231 {
232 	struct intrhand **p, *q, *ih;
233 	static struct intrhand fakehand;
234 
235 	fakehand.ih_next = NULL;
236 	fakehand.ih_fun  = fakeintr;
237 
238 #if 0
239 printf("mac_intr_establish, hI %d L %d ", irq, type);
240 #endif
241 
242 	irq = mapirq(irq);
243 #if 0
244 printf("vI %d ", irq);
245 #endif
246 
247 	/* no point in sleeping unless someone can free memory. */
248 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
249 	if (ih == NULL)
250 		panic("intr_establish: can't malloc handler info");
251 
252 	if (!LEGAL_IRQ(irq) || type == IST_NONE)
253 		panic("intr_establish: bogus irq or type");
254 
255 	switch (o_intrtype[irq]) {
256 	case IST_NONE:
257 		o_intrtype[irq] = type;
258 		break;
259 	case IST_EDGE:
260 	case IST_LEVEL:
261 		if (type == o_intrtype[irq])
262 			break;
263 	case IST_PULSE:
264 		if (type != IST_NONE)
265 			panic("intr_establish: can't share %s with %s",
266 			    intr_typename(o_intrtype[irq]),
267 			    intr_typename(type));
268 		break;
269 	}
270 
271 	/*
272 	 * Figure out where to put the handler.
273 	 * This is O(N^2), but we want to preserve the order, and N is
274 	 * generally small.
275 	 */
276 	for (p = &o_intrhand[irq]; (q = *p) != NULL; p = &q->ih_next)
277 		;
278 
279 	/*
280 	 * Actually install a fake handler momentarily, since we might be doing
281 	 * this with interrupts enabled and DON'T WANt the real routine called
282 	 * until masking is set up.
283 	 */
284 	fakehand.ih_level = level;
285 	*p = &fakehand;
286 
287 	openpic_calc_mask();
288 
289 	/*
290 	 * Poke the real handler in now.
291 	 */
292 	ih->ih_fun = ih_fun;
293 	ih->ih_arg = ih_arg;
294 	ih->ih_next = NULL;
295 	ih->ih_level = level;
296 	ih->ih_irq = irq;
297 	evcount_attach(&ih->ih_count, name, (void *)&o_hwirq[irq],
298 	    &evcount_intr);
299 	*p = ih;
300 
301 	return (ih);
302 }
303 
304 /*
305  * Deregister an interrupt handler.
306  */
307 void
308 openpic_intr_disestablish(void *lcp, void *arg)
309 {
310 	struct intrhand *ih = arg;
311 	int irq = ih->ih_irq;
312 	struct intrhand **p, *q;
313 
314 	if (!LEGAL_IRQ(irq))
315 		panic("intr_disestablish: bogus irq");
316 
317 	/*
318 	 * Remove the handler from the chain.
319 	 * This is O(n^2), too.
320 	 */
321 	for (p = &o_intrhand[irq]; (q = *p) != NULL && q != ih; p = &q->ih_next)
322 		;
323 	if (q)
324 		*p = q->ih_next;
325 	else
326 		panic("intr_disestablish: handler not registered");
327 
328 	evcount_detach(&ih->ih_count);
329 	free((void *)ih, M_DEVBUF);
330 
331 	openpic_calc_mask();
332 
333 	if (o_intrhand[irq] == NULL)
334 		o_intrtype[irq] = IST_NONE;
335 }
336 
337 
338 static char *
339 intr_typename(int type)
340 {
341 
342 	switch (type) {
343 	case IST_NONE:
344 		return ("none");
345 	case IST_PULSE:
346 		return ("pulsed");
347 	case IST_EDGE:
348 		return ("edge-triggered");
349 	case IST_LEVEL:
350 		return ("level-triggered");
351 	default:
352 		panic("intr_typename: invalid type %d", type);
353 #if 1 /* XXX */
354 		return ("unknown");
355 #endif
356 	}
357 }
358 
359 /*
360  * Recalculate the interrupt masks from scratch.
361  * We could code special registry and deregistry versions of this function that
362  * would be faster, but the code would be nastier, and we don't expect this to
363  * happen very much anyway.
364  */
365 
366 void
367 openpic_calc_mask()
368 {
369 	int irq;
370 	struct intrhand *ih;
371 	int i;
372 
373 	/* disable all openpic interrupts */
374 	openpic_set_priority(0, 15);
375 
376 	for (irq = 0; irq < ICU_LEN; irq++) {
377 		int max = IPL_NONE;
378 		int min = IPL_HIGH;
379 		int reg;
380 		if (o_virq[irq] != 0) {
381 			for (ih = o_intrhand[o_virq[irq]]; ih;
382 			    ih = ih->ih_next) {
383 				if (ih->ih_level > max)
384 					max = ih->ih_level;
385 				if (ih->ih_level < min)
386 					min = ih->ih_level;
387 			}
388 		}
389 
390 		o_intrmaxlvl[irq] = max;
391 
392 		/* adjust priority if it changes */
393 		reg = openpic_read(OPENPIC_SRC_VECTOR(irq));
394 		if (max != ((reg >> OPENPIC_PRIORITY_SHIFT) & 0xf)) {
395 			openpic_write(OPENPIC_SRC_VECTOR(irq),
396 				(reg & ~(0xf << OPENPIC_PRIORITY_SHIFT)) |
397 				(max << OPENPIC_PRIORITY_SHIFT) );
398 		}
399 
400 		if (max == IPL_NONE)
401 			min = IPL_NONE; /* Interrupt not enabled */
402 
403 		if (o_virq[irq] != 0) {
404 			/* Enable (dont mask) interrupts at lower levels */
405 			for (i = IPL_NONE; i < min; i++)
406 				imask[i] &= ~(1 << o_virq[irq]);
407 			for (; i <= IPL_HIGH; i++)
408 				imask[i] |= (1 << o_virq[irq]);
409 		}
410 	}
411 
412 	/* restore interrupts */
413 	openpic_set_priority(0, 0);
414 
415 	for (i = IPL_NONE; i <= IPL_HIGH; i++) {
416 		if (i > IPL_NONE)
417 			imask[i] |= SINT_ALLMASK;
418 		if (i >= IPL_CLOCK)
419 			imask[i] |= SPL_CLOCKMASK;
420 	}
421 	imask[IPL_HIGH] = 0xffffffff;
422 }
423 
424 /*
425  * Map 64 irqs into 32 (bits).
426  */
427 static int
428 mapirq(int irq)
429 {
430 	int v;
431 
432 	/* irq in table already? */
433 	if (o_virq[irq] != 0)
434 		return o_virq[irq];
435 
436 	if (irq < 0 || irq >= ICU_LEN)
437 		panic("invalid irq %d", irq);
438 
439 	o_virq_max++;
440 	v = o_virq_max;
441 	if (v > HWIRQ_MAX)
442 		panic("virq overflow");
443 
444 	o_hwirq[v] = irq;
445 	o_virq[irq] = v;
446 #if 0
447 printf("\nmapirq %x to %x\n", irq, v);
448 #endif
449 
450 	return v;
451 }
452 
453 /*
454  * Count leading zeros.
455  */
456 static __inline int
457 cntlzw(int x)
458 {
459 	int a;
460 
461 	__asm __volatile ("cntlzw %0,%1" : "=r"(a) : "r"(x));
462 
463 	return a;
464 }
465 
466 void openpic_do_pending_softint(int pcpl);
467 
468 void
469 openpic_do_pending_int()
470 {
471 	struct cpu_info *ci = curcpu();
472 	struct intrhand *ih;
473 	int irq;
474 	int pcpl;
475 	int hwpend;
476 	int pri, pripending;
477 	int s;
478 
479 	if (ci->ci_iactive & CI_IACTIVE_PROCESSING_HARD)
480 		return;
481 
482 	atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_HARD);
483 	s = ppc_intr_disable();
484 	pcpl = ci->ci_cpl;
485 
486 	hwpend = ci->ci_ipending & ~pcpl;	/* Do now unmasked pendings */
487 	hwpend &= HWIRQ_MASK;
488 	while (hwpend) {
489 		/* this still doesn't handle the interrupts in priority order */
490 		for (pri = IPL_HIGH; pri >= IPL_NONE; pri--) {
491 			pripending = hwpend & ~imask[pri];
492 			if (pripending == 0)
493 				continue;
494 			irq = 31 - cntlzw(pripending);
495 			ci->ci_ipending &= ~(1 << irq);
496 			ci->ci_cpl = imask[o_intrmaxlvl[o_hwirq[irq]]];
497 			openpic_enable_irq_mask(~ci->ci_cpl);
498 			ih = o_intrhand[irq];
499 			while(ih) {
500 				ppc_intr_enable(1);
501 
502 				KERNEL_LOCK();
503 				if ((*ih->ih_fun)(ih->ih_arg))
504 					ih->ih_count.ec_count++;
505 				KERNEL_UNLOCK();
506 
507 				(void)ppc_intr_disable();
508 
509 				ih = ih->ih_next;
510 			}
511 		}
512 		hwpend = ci->ci_ipending & ~pcpl;/* Catch new pendings */
513 		hwpend &= HWIRQ_MASK;
514 	}
515 	ci->ci_cpl = pcpl | SINT_ALLMASK;
516 	openpic_enable_irq_mask(~ci->ci_cpl);
517 	atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_HARD);
518 
519 	openpic_do_pending_softint(pcpl);
520 
521 	ppc_intr_enable(s);
522 }
523 
524 void
525 openpic_do_pending_softint(int pcpl)
526 {
527 	struct cpu_info *ci = curcpu();
528 
529 	if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT)
530 		return;
531 
532 	atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
533 
534 	do {
535 		if((ci->ci_ipending & SINT_CLOCK) & ~pcpl) {
536 			ci->ci_ipending &= ~SINT_CLOCK;
537 			ci->ci_cpl = SINT_CLOCK|SINT_NET|SINT_TTY;
538 			ppc_intr_enable(1);
539 			KERNEL_LOCK();
540 			softintr_dispatch(SI_SOFTCLOCK);
541 			KERNEL_UNLOCK();
542 			ppc_intr_disable();
543 			continue;
544 		}
545 		if((ci->ci_ipending & SINT_NET) & ~pcpl) {
546 			ci->ci_ipending &= ~SINT_NET;
547 			ci->ci_cpl = SINT_NET|SINT_TTY;
548 			ppc_intr_enable(1);
549 			KERNEL_LOCK();
550 			softintr_dispatch(SI_SOFTNET);
551 			KERNEL_UNLOCK();
552 			ppc_intr_disable();
553 			continue;
554 		}
555 		if((ci->ci_ipending & SINT_TTY) & ~pcpl) {
556 			ci->ci_ipending &= ~SINT_TTY;
557 			ci->ci_cpl = SINT_TTY;
558 			ppc_intr_enable(1);
559 			KERNEL_LOCK();
560 			softintr_dispatch(SI_SOFTTTY);
561 			KERNEL_UNLOCK();
562 			ppc_intr_disable();
563 			continue;
564 		}
565 	} while ((ci->ci_ipending & SINT_ALLMASK) & ~pcpl);
566 	ci->ci_cpl = pcpl;	/* Don't use splx... we are here already! */
567 
568 	atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
569 }
570 
571 u_int
572 openpic_read(int reg)
573 {
574 	char *addr = (void *)(openpic_base + reg);
575 
576 	if (openpic_big_endian)
577 		return in32(addr);
578 	else
579 		return in32rb(addr);
580 }
581 
582 void
583 openpic_write(int reg, u_int val)
584 {
585 	char *addr = (void *)(openpic_base + reg);
586 
587 	if (openpic_big_endian)
588 		out32(addr, val);
589 	else
590 		out32rb(addr, val);
591 }
592 
593 void
594 openpic_enable_irq_mask(int irq_mask)
595 {
596 	int irq;
597 	for ( irq = 0; irq <= o_virq_max; irq++) {
598 		if (irq_mask & (1 << irq))
599 			openpic_enable_irq(o_hwirq[irq]);
600 		else
601 			openpic_disable_irq(o_hwirq[irq]);
602 	}
603 }
604 
605 void
606 openpic_set_enable_irq(int irq, int type)
607 {
608 	u_int x;
609 
610 	x = openpic_read(OPENPIC_SRC_VECTOR(irq));
611 	x &= ~(OPENPIC_IMASK|OPENPIC_SENSE_LEVEL|OPENPIC_SENSE_EDGE);
612 	if (type == IST_LEVEL)
613 		x |= OPENPIC_SENSE_LEVEL;
614 	else
615 		x |= OPENPIC_SENSE_EDGE;
616 	openpic_write(OPENPIC_SRC_VECTOR(irq), x);
617 }
618 void
619 openpic_enable_irq(int irq)
620 {
621 	u_int x;
622 
623 	x = openpic_read(OPENPIC_SRC_VECTOR(irq));
624 	x &= ~(OPENPIC_IMASK|OPENPIC_SENSE_LEVEL|OPENPIC_SENSE_EDGE);
625 	if (o_intrtype[o_virq[irq]] == IST_LEVEL)
626 		x |= OPENPIC_SENSE_LEVEL;
627 	else
628 		x |= OPENPIC_SENSE_EDGE;
629 	openpic_write(OPENPIC_SRC_VECTOR(irq), x);
630 }
631 
632 void
633 openpic_disable_irq(int irq)
634 {
635 	u_int x;
636 
637 	x = openpic_read(OPENPIC_SRC_VECTOR(irq));
638 	x |= OPENPIC_IMASK;
639 	openpic_write(OPENPIC_SRC_VECTOR(irq), x);
640 }
641 
642 void
643 openpic_set_priority(int cpu, int pri)
644 {
645 	u_int x;
646 
647 	x = openpic_read(OPENPIC_CPU_PRIORITY(cpu));
648 	x &= ~OPENPIC_CPU_PRIORITY_MASK;
649 	x |= pri;
650 	openpic_write(OPENPIC_CPU_PRIORITY(cpu), x);
651 }
652 
653 int
654 openpic_read_irq(int cpu)
655 {
656 	return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
657 }
658 
659 void
660 openpic_eoi(int cpu)
661 {
662 	openpic_write(OPENPIC_EOI(cpu), 0);
663 	openpic_read(OPENPIC_EOI(cpu));
664 }
665 
666 #ifdef MULTIPROCESSOR
667 
668 void
669 openpic_send_ipi(struct cpu_info *ci, int id)
670 {
671 	switch (id) {
672 	case PPC_IPI_NOP:
673 		id = 0;
674 		break;
675 	case PPC_IPI_DDB:
676 		id = 1;
677 		break;
678 	default:
679 		panic("invalid ipi send to cpu %d %d\n", ci->ci_cpuid, id);
680 	}
681 
682 
683 	openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid);
684 }
685 
686 #endif
687 
688 void
689 ext_intr_openpic()
690 {
691 	struct cpu_info *ci = curcpu();
692 	int irq, realirq;
693 	int r_imen;
694 	int pcpl, ocpl;
695 	struct intrhand *ih;
696 
697 	pcpl = ci->ci_cpl;
698 
699 	realirq = openpic_read_irq(ci->ci_cpuid);
700 
701 	while (realirq != 255) {
702 #ifdef MULTIPROCESSOR
703 		if (realirq == IPI_VECTOR_NOP) {
704 			ipi_nop[ci->ci_cpuid].ec_count++;
705 			openpic_eoi(ci->ci_cpuid);
706 			realirq = openpic_read_irq(ci->ci_cpuid);
707 			continue;
708 		}
709 		if (realirq == IPI_VECTOR_DDB) {
710 			ipi_ddb[ci->ci_cpuid].ec_count++;
711 			openpic_eoi(ci->ci_cpuid);
712 			openpic_ipi_ddb();
713 			realirq = openpic_read_irq(ci->ci_cpuid);
714 			continue;
715 		}
716 #endif
717 
718 		irq = o_virq[realirq];
719 
720 		/* XXX check range */
721 
722 		r_imen = 1 << irq;
723 
724 		if ((pcpl & r_imen) != 0) {
725 			/* Masked! Mark this as pending. */
726 			ci->ci_ipending |= r_imen;
727 			openpic_enable_irq_mask(~imask[o_intrmaxlvl[realirq]]);
728 			openpic_eoi(ci->ci_cpuid);
729 		} else {
730 			openpic_enable_irq_mask(~imask[o_intrmaxlvl[realirq]]);
731 			openpic_eoi(ci->ci_cpuid);
732 			ocpl = splraise(imask[o_intrmaxlvl[realirq]]);
733 
734 			ih = o_intrhand[irq];
735 			while (ih) {
736 				ppc_intr_enable(1);
737 
738 				KERNEL_LOCK();
739 				if ((*ih->ih_fun)(ih->ih_arg))
740 					ih->ih_count.ec_count++;
741 				KERNEL_UNLOCK();
742 
743 				(void)ppc_intr_disable();
744 				ih = ih->ih_next;
745 			}
746 
747 			uvmexp.intrs++;
748 			__asm__ volatile("":::"memory"); /* don't reorder.... */
749 			ci->ci_cpl = ocpl;
750 			__asm__ volatile("":::"memory"); /* don't reorder.... */
751 			openpic_enable_irq_mask(~pcpl);
752 		}
753 
754 		realirq = openpic_read_irq(ci->ci_cpuid);
755 	}
756 	ppc_intr_enable(1);
757 
758 	splx(pcpl);	/* Process pendings. */
759 }
760 
761 void
762 openpic_init()
763 {
764 	int irq;
765 	u_int x;
766 
767 	/* disable all interrupts */
768 	for (irq = 0; irq < 255; irq++)
769 		openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK);
770 	openpic_set_priority(0, 15);
771 
772 	/* we don't need 8259 pass through mode */
773 	x = openpic_read(OPENPIC_CONFIG);
774 	x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
775 	openpic_write(OPENPIC_CONFIG, x);
776 
777 	/* send all interrupts to cpu 0 */
778 	for (irq = 0; irq < ICU_LEN; irq++)
779 		openpic_write(OPENPIC_IDEST(irq), 1 << 0);
780 	for (irq = 0; irq < ICU_LEN; irq++) {
781 		x = irq;
782 		x |= OPENPIC_IMASK;
783 		x |= OPENPIC_POLARITY_POSITIVE;
784 		x |= OPENPIC_SENSE_LEVEL;
785 		x |= 8 << OPENPIC_PRIORITY_SHIFT;
786 		openpic_write(OPENPIC_SRC_VECTOR(irq), x);
787 	}
788 
789 #ifdef MULTIPROCESSOR
790 	/* Set up inter-processor interrupts. */
791 	/* IPI0 - NOP */
792 	x = openpic_read(OPENPIC_IPI_VECTOR(0));
793 	x &= ~(OPENPIC_IMASK | OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK);
794 	x |= (15 << OPENPIC_PRIORITY_SHIFT) | IPI_VECTOR_NOP;
795 	openpic_write(OPENPIC_IPI_VECTOR(0), x);
796 	/* IPI1 - DDB */
797 	x = openpic_read(OPENPIC_IPI_VECTOR(1));
798 	x &= ~(OPENPIC_IMASK | OPENPIC_PRIORITY_MASK | OPENPIC_VECTOR_MASK);
799 	x |= (15 << OPENPIC_PRIORITY_SHIFT) | IPI_VECTOR_DDB;
800 	openpic_write(OPENPIC_IPI_VECTOR(1), x);
801 
802 	evcount_attach(&ipi_nop[0], "ipi_nop0", (void *)&ipi_nopirq,
803 	    &evcount_intr);
804 	evcount_attach(&ipi_nop[1], "ipi_nop1", (void *)&ipi_nopirq,
805 	    &evcount_intr);
806 	evcount_attach(&ipi_ddb[0], "ipi_ddb0", (void *)&ipi_ddbirq,
807 	    &evcount_intr);
808 	evcount_attach(&ipi_ddb[1], "ipi_ddb1", (void *)&ipi_ddbirq,
809 	    &evcount_intr);
810 #endif
811 
812 	/* XXX set spurious intr vector */
813 
814 	openpic_set_priority(0, 0);
815 
816 	/* clear all pending interrunts */
817 	for (irq = 0; irq < ICU_LEN; irq++) {
818 		openpic_read_irq(0);
819 		openpic_eoi(0);
820 	}
821 
822 	for (irq = 0; irq < ICU_LEN; irq++)
823 		openpic_disable_irq(irq);
824 
825 	install_extint(ext_intr_openpic);
826 }
827 /*
828  * programmer_button function to fix args to Debugger.
829  * deal with any enables/disables, if necessary.
830  */
831 int
832 openpic_prog_button (void *arg)
833 {
834 #ifdef DDB
835 	if (db_console)
836 		Debugger();
837 #else
838 	printf("programmer button pressed, debugger not available\n");
839 #endif
840 	return 1;
841 }
842 
843 
844 void
845 openpic_ipi_ddb(void)
846 {
847 	Debugger();
848 }
849 
850