xref: /openbsd-src/sys/arch/macppc/dev/openpic.c (revision 4c1e55dc91edd6e69ccc60ce855900fbc12cf34f)
1 /*	$OpenBSD: openpic.c,v 1.68 2011/10/28 15:18:51 drahn 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 <sys/param.h>
41 #include <sys/device.h>
42 #include <sys/ioctl.h>
43 #include <sys/mbuf.h>
44 #include <sys/socket.h>
45 #include <sys/systm.h>
46 
47 #include <uvm/uvm.h>
48 #include <ddb/db_var.h>
49 
50 #include <machine/atomic.h>
51 #include <machine/autoconf.h>
52 #include <machine/intr.h>
53 #include <machine/psl.h>
54 #include <machine/pio.h>
55 #include <machine/powerpc.h>
56 #include <macppc/dev/openpicreg.h>
57 #include <dev/ofw/openfirm.h>
58 
59 #define ICU_LEN 128
60 int openpic_numirq = ICU_LEN;
61 #define LEGAL_IRQ(x) ((x >= 0) && (x < ICU_LEN))
62 
63 int openpic_pri_share[IPL_NUM];
64 
65 struct intrq openpic_handler[ICU_LEN];
66 
67 void openpic_calc_mask(void);
68 
69 ppc_splraise_t openpic_splraise;
70 ppc_spllower_t openpic_spllower;
71 ppc_splx_t openpic_splx;
72 
73 /* IRQ vector used for inter-processor interrupts. */
74 #define IPI_VECTOR_NOP	64
75 #define IPI_VECTOR_DDB	65
76 #ifdef MULTIPROCESSOR
77 static struct evcount ipi_ddb[PPC_MAXPROCS];
78 static struct evcount ipi_nop[PPC_MAXPROCS];
79 static int ipi_nopirq = IPI_VECTOR_NOP;
80 static int ipi_ddbirq = IPI_VECTOR_DDB;
81 #endif
82 struct evcount openpic_spurious;
83 int openpic_spurious_irq = 255;
84 
85 void	openpic_enable_irq(int, int);
86 void	openpic_disable_irq(int);
87 void	openpic_init(void);
88 void	openpic_set_priority(int, int);
89 void	openpic_ipi_ddb(void);
90 void	*openpic_intr_establish(void *, int, int, int, int (*)(void *),
91     void *, const char *);
92 
93 typedef void  (void_f) (void);
94 extern void_f *pending_int_f;
95 
96 vaddr_t openpic_base;
97 void	openpic_intr_disestablish( void *lcp, void *arg);
98 void	openpic_collect_preconf_intr(void);
99 int	openpic_big_endian;
100 #ifdef MULTIPROCESSOR
101 intr_send_ipi_t openpic_send_ipi;
102 #endif
103 
104 u_int openpic_read(int reg);
105 void openpic_write(int reg, u_int val);
106 
107 struct openpic_softc {
108 	struct device sc_dev;
109 };
110 
111 int	openpic_match(struct device *parent, void *cf, void *aux);
112 void	openpic_attach(struct device *, struct device *, void *);
113 void	openpic_do_pending_int(int pcpl);
114 void	openpic_do_pending_int_dis(int pcpl, int s);
115 void	openpic_collect_preconf_intr(void);
116 void	openpic_ext_intr(void);
117 
118 struct cfattach openpic_ca = {
119 	sizeof(struct openpic_softc),
120 	openpic_match,
121 	openpic_attach
122 };
123 
124 struct cfdriver openpic_cd = {
125 	NULL, "openpic", DV_DULL
126 };
127 
128 u_int
129 openpic_read(int reg)
130 {
131 	char *addr = (void *)(openpic_base + reg);
132 
133 	asm volatile("eieio"::: "memory");
134 	if (openpic_big_endian)
135 		return in32(addr);
136 	else
137 		return in32rb(addr);
138 }
139 
140 void
141 openpic_write(int reg, u_int val)
142 {
143 	char *addr = (void *)(openpic_base + reg);
144 
145 	if (openpic_big_endian)
146 		out32(addr, val);
147 	else
148 		out32rb(addr, val);
149 	asm volatile("eieio"::: "memory");
150 }
151 
152 static inline int
153 openpic_read_irq(int cpu)
154 {
155 	return openpic_read(OPENPIC_IACK(cpu)) & OPENPIC_VECTOR_MASK;
156 }
157 
158 static inline void
159 openpic_eoi(int cpu)
160 {
161 	openpic_write(OPENPIC_EOI(cpu), 0);
162 }
163 
164 int
165 openpic_match(struct device *parent, void *cf, void *aux)
166 {
167 	char type[40];
168 	int pirq;
169 	struct confargs *ca = aux;
170 
171 	bzero (type, sizeof(type));
172 
173 	if (OF_getprop(ca->ca_node, "interrupt-parent", &pirq, sizeof(pirq))
174 	    == sizeof(pirq))
175 		return 0; /* XXX */
176 
177 	if (strcmp(ca->ca_name, "interrupt-controller") != 0 &&
178 	    strcmp(ca->ca_name, "mpic") != 0)
179 		return 0;
180 
181 	OF_getprop(ca->ca_node, "device_type", type, sizeof(type));
182 	if (strcmp(type, "open-pic") != 0)
183 		return 0;
184 
185 	if (ca->ca_nreg < 8)
186 		return 0;
187 
188 	return 1;
189 }
190 
191 void
192 openpic_attach(struct device *parent, struct device  *self, void *aux)
193 {
194 	struct cpu_info *ci = curcpu();
195 	struct confargs *ca = aux;
196 	u_int32_t reg;
197 
198 	reg = 0;
199 	if (OF_getprop(ca->ca_node, "big-endian", &reg, sizeof reg) == 0)
200 		openpic_big_endian = 1;
201 
202 	openpic_base = (vaddr_t) mapiodev (ca->ca_baseaddr +
203 			ca->ca_reg[0], 0x40000);
204 
205 	/* openpic may support more than 128 interupts but driver doesn't */
206 	openpic_numirq = ((openpic_read(OPENPIC_FEATURE) >> 16) & 0x7f)+1;
207 
208 	printf(": version 0x%x feature %x %s",
209 	    openpic_read(OPENPIC_VENDOR_ID),
210 	    openpic_read(OPENPIC_FEATURE),
211 		openpic_big_endian ? "BE" : "LE" );
212 
213 	openpic_init();
214 
215 	intr_establish_func  = openpic_intr_establish;
216 	intr_disestablish_func  = openpic_intr_disestablish;
217 	mac_intr_establish_func  = openpic_intr_establish;
218 	mac_intr_disestablish_func  = openpic_intr_disestablish;
219 #ifdef MULTIPROCESSOR
220 	intr_send_ipi_func = openpic_send_ipi;
221 #endif
222 
223 	ppc_smask_init();
224 
225 	openpic_collect_preconf_intr();
226 
227 	evcount_attach(&openpic_spurious, "spurious", &openpic_spurious_irq);
228 
229 	ppc_intr_func.raise = openpic_splraise;
230 	ppc_intr_func.lower = openpic_spllower;
231 	ppc_intr_func.x = openpic_splx;
232 
233 	openpic_set_priority(0, ci->ci_cpl);
234 
235 	ppc_intr_enable(1);
236 
237 	printf("\n");
238 }
239 
240 static inline void
241 openpic_setipl(int newcpl)
242 {
243 	struct cpu_info *ci = curcpu();
244 	int s;
245 	/* XXX - try do to this without the disable */
246 	s = ppc_intr_disable();
247 	ci->ci_cpl = newcpl;
248 	openpic_set_priority(ci->ci_cpuid, newcpl);
249 	ppc_intr_enable(s);
250 }
251 
252 int
253 openpic_splraise(int newcpl)
254 {
255 	struct cpu_info *ci = curcpu();
256 	newcpl = openpic_pri_share[newcpl];
257 	int ocpl = ci->ci_cpl;
258 	if (ocpl > newcpl)
259 		newcpl = ocpl;
260 
261 	openpic_setipl(newcpl);
262 
263 	return ocpl;
264 }
265 
266 int
267 openpic_spllower(int newcpl)
268 {
269 	struct cpu_info *ci = curcpu();
270 	int ocpl = ci->ci_cpl;
271 
272 	openpic_splx(newcpl);
273 
274 	return ocpl;
275 }
276 
277 void
278 openpic_splx(int newcpl)
279 {
280 	openpic_do_pending_int(newcpl);
281 }
282 
283 void
284 openpic_collect_preconf_intr()
285 {
286 	int i;
287 	for (i = 0; i < ppc_configed_intr_cnt; i++) {
288 #ifdef DEBUG
289 		printf("\n\t%s irq %d level %d fun %x arg %x",
290 		    ppc_configed_intr[i].ih_what, ppc_configed_intr[i].ih_irq,
291 		    ppc_configed_intr[i].ih_level, ppc_configed_intr[i].ih_fun,
292 		    ppc_configed_intr[i].ih_arg);
293 #endif
294 		openpic_intr_establish(NULL, ppc_configed_intr[i].ih_irq,
295 		    IST_LEVEL, ppc_configed_intr[i].ih_level,
296 		    ppc_configed_intr[i].ih_fun, ppc_configed_intr[i].ih_arg,
297 		    ppc_configed_intr[i].ih_what);
298 	}
299 }
300 
301 /*
302  * Register an interrupt handler.
303  */
304 void *
305 openpic_intr_establish(void *lcv, int irq, int type, int level,
306     int (*ih_fun)(void *), void *ih_arg, const char *name)
307 {
308 	struct intrhand *ih;
309 	struct intrq *iq;
310 	int s;
311 
312 	/* no point in sleeping unless someone can free memory. */
313 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
314 	if (ih == NULL)
315 		panic("intr_establish: can't malloc handler info");
316 	iq = &openpic_handler[irq];
317 
318 	if (!LEGAL_IRQ(irq) || type == IST_NONE)
319 		panic("intr_establish: bogus irq or type");
320 
321 	switch (iq->iq_ist) {
322 	case IST_NONE:
323 		iq->iq_ist = type;
324 		break;
325 	case IST_EDGE:
326 		intr_shared_edge = 1;
327 		/* FALLTHROUGH */
328 	case IST_LEVEL:
329 		if (type == iq->iq_ist)
330 			break;
331 	case IST_PULSE:
332 		if (type != IST_NONE)
333 			panic("intr_establish: can't share %s with %s",
334 			    ppc_intr_typename(iq->iq_ist),
335 			    ppc_intr_typename(type));
336 		break;
337 	}
338 
339 	ih->ih_fun = ih_fun;
340 	ih->ih_arg = ih_arg;
341 	ih->ih_level = level;
342 	ih->ih_irq = irq;
343 
344 	evcount_attach(&ih->ih_count, name, &ih->ih_irq);
345 
346 	/*
347 	 * Append handler to end of list
348 	 */
349 	s = ppc_intr_disable();
350 
351 	TAILQ_INSERT_TAIL(&iq->iq_list, ih, ih_list);
352 	openpic_calc_mask();
353 
354 	ppc_intr_enable(s);
355 
356 	return (ih);
357 }
358 
359 /*
360  * Deregister an interrupt handler.
361  */
362 void
363 openpic_intr_disestablish(void *lcp, void *arg)
364 {
365 	struct intrhand *ih = arg;
366 	int irq = ih->ih_irq;
367 	struct intrq *iq = &openpic_handler[irq];
368 	int s;
369 
370 	if (!LEGAL_IRQ(irq))
371 		panic("intr_disestablish: bogus irq");
372 
373 	/*
374 	 * Remove the handler from the chain.
375 	 */
376 	s = ppc_intr_disable();
377 
378 	TAILQ_REMOVE(&iq->iq_list, ih, ih_list);
379 	openpic_calc_mask();
380 
381 	ppc_intr_enable(s);
382 
383 	evcount_detach(&ih->ih_count);
384 	free((void *)ih, M_DEVBUF);
385 
386 	if (TAILQ_EMPTY(&iq->iq_list))
387 		iq->iq_ist = IST_NONE;
388 }
389 
390 /*
391  * Recalculate the interrupt masks from scratch.
392  * We could code special registry and deregistry versions of this function that
393  * would be faster, but the code would be nastier, and we don't expect this to
394  * happen very much anyway.
395  */
396 
397 void
398 openpic_calc_mask()
399 {
400 	struct cpu_info *ci = curcpu();
401 	int irq;
402 	struct intrhand *ih;
403 	int i;
404 
405 	/* disable all openpic interrupts */
406 	openpic_set_priority(ci->ci_cpuid, 15);
407 
408 	for (i = IPL_NONE; i < IPL_NUM; i++) {
409 		openpic_pri_share[i] = i;
410 	}
411 
412 	for (irq = 0; irq < openpic_numirq; irq++) {
413 		int maxipl = IPL_NONE;
414 		int minipl = IPL_HIGH;
415 		struct intrq *iq = &openpic_handler[irq];
416 
417 		TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
418 			if (ih->ih_level > maxipl)
419 				maxipl = ih->ih_level;
420 			if (ih->ih_level < minipl)
421 				minipl = ih->ih_level;
422 		}
423 
424 		if (maxipl == IPL_NONE) {
425 			minipl = IPL_NONE; /* Interrupt not enabled */
426 
427 			openpic_disable_irq(irq);
428 		} else {
429 			for (i = minipl; i <= maxipl; i++) {
430 				openpic_pri_share[i] = maxipl;
431 			}
432 			openpic_enable_irq(irq, maxipl);
433 		}
434 
435 		iq->iq_ipl = maxipl;
436 	}
437 
438 	/* restore interrupts */
439 	openpic_set_priority(ci->ci_cpuid, ci->ci_cpl);
440 }
441 
442 void
443 openpic_do_pending_int(int pcpl)
444 {
445 	int s;
446 	s = ppc_intr_disable();
447 	openpic_do_pending_int_dis(pcpl, s);
448 	ppc_intr_enable(s);
449 
450 }
451 
452 /*
453  * This function expect interrupts disabled on entry and exit,
454  * the s argument indicates if interrupts may be enabled during
455  * the processing of off level interrupts, s 'should' always be 1.
456  */
457 void
458 openpic_do_pending_int_dis(int pcpl, int s)
459 {
460 	struct cpu_info *ci = curcpu();
461 
462 	(void)ppc_intr_disable();
463 	if (ci->ci_iactive & CI_IACTIVE_PROCESSING_SOFT) {
464 		/* soft interrupts are being processed, just set ipl/return */
465 		openpic_setipl(pcpl);
466 		ppc_intr_enable(s);
467 		return;
468 	}
469 
470 	atomic_setbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
471 
472 	do {
473 		if ((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTCLOCK)) &&
474 		    (pcpl < IPL_SOFTCLOCK)) {
475  			ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTCLOCK);
476 			ppc_intr_enable(1);
477 			KERNEL_LOCK();
478 			softintr_dispatch(SI_SOFTCLOCK);
479 			KERNEL_UNLOCK();
480 			(void)ppc_intr_disable();
481  		}
482 		if ((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTNET)) &&
483 		    (pcpl < IPL_SOFTNET)) {
484 			ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTNET);
485 			ppc_intr_enable(1);
486 			KERNEL_LOCK();
487 			softintr_dispatch(SI_SOFTNET);
488 			KERNEL_UNLOCK();
489 			(void)ppc_intr_disable();
490 		}
491 		if ((ci->ci_ipending & SI_TO_IRQBIT(SI_SOFTTTY)) &&
492 		    (pcpl < IPL_SOFTTTY)) {
493 			ci->ci_ipending &= ~SI_TO_IRQBIT(SI_SOFTTTY);
494 			ppc_intr_enable(1);
495 			KERNEL_LOCK();
496 			softintr_dispatch(SI_SOFTTTY);
497 			KERNEL_UNLOCK();
498 			(void)ppc_intr_disable();
499 		}
500 	} while (ci->ci_ipending & ppc_smask[pcpl]);
501 	openpic_setipl(pcpl);	/* Don't use splx... we are here already! */
502 
503 	atomic_clearbits_int(&ci->ci_iactive, CI_IACTIVE_PROCESSING_SOFT);
504 	ppc_intr_enable(s);
505 }
506 
507 void
508 openpic_enable_irq(int irq, int pri)
509 {
510 	u_int x;
511 	struct intrq *iq = &openpic_handler[irq];
512 
513 	x = irq;
514 	if (iq->iq_ist == IST_LEVEL)
515 		x |= OPENPIC_SENSE_LEVEL;
516 	else
517 		x |= OPENPIC_SENSE_EDGE;
518 	x |= OPENPIC_POLARITY_NEGATIVE;
519 	x |= pri << OPENPIC_PRIORITY_SHIFT;
520 	openpic_write(OPENPIC_SRC_VECTOR(irq), x);
521 }
522 
523 void
524 openpic_disable_irq(int irq)
525 {
526 	u_int x;
527 
528 	x = openpic_read(OPENPIC_SRC_VECTOR(irq));
529 	x |= OPENPIC_IMASK;
530 	openpic_write(OPENPIC_SRC_VECTOR(irq), x);
531 }
532 
533 void
534 openpic_set_priority(int cpu, int pri)
535 {
536 	openpic_write(OPENPIC_CPU_PRIORITY(cpu), pri);
537 }
538 
539 #ifdef MULTIPROCESSOR
540 void
541 openpic_send_ipi(struct cpu_info *ci, int id)
542 {
543 	switch (id) {
544 	case PPC_IPI_NOP:
545 		id = 0;
546 		break;
547 	case PPC_IPI_DDB:
548 		id = 1;
549 		break;
550 	default:
551 		panic("invalid ipi send to cpu %d %d", ci->ci_cpuid, id);
552 	}
553 
554 	openpic_write(OPENPIC_IPI(curcpu()->ci_cpuid, id), 1 << ci->ci_cpuid);
555 }
556 
557 #endif
558 
559 int openpic_irqnest[PPC_MAXPROCS];
560 int openpic_irqloop[PPC_MAXPROCS];
561 void
562 openpic_ext_intr()
563 {
564 	struct cpu_info *ci = curcpu();
565 	int irq, pcpl, ret;
566 	int maxipl = IPL_NONE;
567 	struct intrhand *ih;
568 	struct intrq *iq;
569 	int spurious;
570 
571 	pcpl = ci->ci_cpl;
572 
573 	openpic_irqloop[ci->ci_cpuid] = 0;
574 	irq = openpic_read_irq(ci->ci_cpuid);
575 	openpic_irqnest[ci->ci_cpuid]++;
576 
577 	while (irq != 255) {
578 		openpic_irqloop[ci->ci_cpuid]++;
579 		if (openpic_irqloop[ci->ci_cpuid] > 20 ||
580 		    openpic_irqnest[ci->ci_cpuid] > 3) {
581 			printf("irqloop %d irqnest %d\n",
582 			    openpic_irqloop[ci->ci_cpuid],
583 			    openpic_irqnest[ci->ci_cpuid]);
584 		}
585 		if (openpic_irqloop[ci->ci_cpuid] > 20) {
586 			printf("irqloop %d irqnest %d: returning\n",
587 			    openpic_irqloop[ci->ci_cpuid],
588 			    openpic_irqnest[ci->ci_cpuid]);
589 			openpic_irqnest[ci->ci_cpuid]--;
590 			return;
591 		}
592 #ifdef MULTIPROCESSOR
593 		if (irq == IPI_VECTOR_NOP) {
594 			ipi_nop[ci->ci_cpuid].ec_count++;
595 			openpic_eoi(ci->ci_cpuid);
596 			irq = openpic_read_irq(ci->ci_cpuid);
597 			continue;
598 		}
599 		if (irq == IPI_VECTOR_DDB) {
600 			ipi_ddb[ci->ci_cpuid].ec_count++;
601 			openpic_eoi(ci->ci_cpuid);
602 			openpic_ipi_ddb();
603 			irq = openpic_read_irq(ci->ci_cpuid);
604 			continue;
605 		}
606 #endif
607 		iq = &openpic_handler[irq];
608 
609 		if (iq->iq_ipl <= ci->ci_cpl)
610 			printf("invalid interrupt %d lvl %d at %d hw %d\n",
611 			    irq, iq->iq_ipl, ci->ci_cpl,
612 			    openpic_read(OPENPIC_CPU_PRIORITY(ci->ci_cpuid)));
613 		if (iq->iq_ipl > maxipl)
614 			maxipl = iq->iq_ipl;
615 		splraise(iq->iq_ipl);
616 		openpic_eoi(ci->ci_cpuid);
617 
618 		spurious = 1;
619 		TAILQ_FOREACH(ih, &iq->iq_list, ih_list) {
620 			ppc_intr_enable(1);
621 			KERNEL_LOCK();
622 			ret = (*ih->ih_fun)(ih->ih_arg);
623 			if (ret) {
624 				ih->ih_count.ec_count++;
625 				spurious = 0;
626  			}
627 			KERNEL_UNLOCK();
628 
629 			(void)ppc_intr_disable();
630 			if (intr_shared_edge == 00 && ret == 1)
631 				break;
632  		}
633 		if (spurious) {
634 			openpic_spurious.ec_count++;
635 #ifdef OPENPIC_NOISY
636 			printf("spurious intr %d\n", irq);
637 #endif
638 		}
639 
640 		uvmexp.intrs++;
641 		openpic_setipl(pcpl);
642 
643 		irq = openpic_read_irq(ci->ci_cpuid);
644 	}
645 
646 	/*
647 	 * sending 0 in to openpic_do_pending_int_dis will leave
648 	 * external interrupts disabled, but since we are about
649 	 * to return from interrupt leaving them disabled until then
650 	 * prevents additional recursion.
651 	 */
652 	openpic_do_pending_int_dis(pcpl, 0);
653 
654 	openpic_irqnest[ci->ci_cpuid]--;
655 }
656 
657 void
658 openpic_init()
659 {
660 	struct cpu_info *ci = curcpu();
661 	struct intrq *iq;
662 	int irq;
663 	u_int x;
664 	int i;
665 
666 	openpic_set_priority(ci->ci_cpuid, 15);
667 
668 	/* disable all interrupts */
669 	for (irq = 0; irq < openpic_numirq; irq++)
670 		openpic_write(OPENPIC_SRC_VECTOR(irq), OPENPIC_IMASK);
671 
672 	for (i = 0; i < openpic_numirq; i++) {
673 		iq = &openpic_handler[i];
674 		TAILQ_INIT(&iq->iq_list);
675 	}
676 
677 	/* we don't need 8259 pass through mode */
678 	x = openpic_read(OPENPIC_CONFIG);
679 	x |= OPENPIC_CONFIG_8259_PASSTHRU_DISABLE;
680 	openpic_write(OPENPIC_CONFIG, x);
681 
682 	/* initialize all vectors to something sane */
683 	for (irq = 0; irq < ICU_LEN; irq++) {
684 		x = irq;
685 		x |= OPENPIC_IMASK;
686 		x |= OPENPIC_POLARITY_NEGATIVE;
687 		x |= OPENPIC_SENSE_LEVEL;
688 		x |= 8 << OPENPIC_PRIORITY_SHIFT;
689 		openpic_write(OPENPIC_SRC_VECTOR(irq), x);
690 	}
691 
692 	/* send all interrupts to cpu 0 */
693 	for (irq = 0; irq < openpic_numirq; irq++)
694 		openpic_write(OPENPIC_IDEST(irq), 1 << 0);
695 
696 	/* clear all pending interrunts */
697 	for (irq = 0; irq < ICU_LEN; irq++) {
698 		openpic_read_irq(ci->ci_cpuid);
699 		openpic_eoi(ci->ci_cpuid);
700 	}
701 
702 #ifdef MULTIPROCESSOR
703 	/* Set up inter-processor interrupts. */
704 	/* IPI0 - NOP */
705 	x = IPI_VECTOR_NOP;
706 	x |= 15 << OPENPIC_PRIORITY_SHIFT;
707 	openpic_write(OPENPIC_IPI_VECTOR(0), x);
708 	/* IPI1 - DDB */
709 	x = IPI_VECTOR_DDB;
710 	x |= 15 << OPENPIC_PRIORITY_SHIFT;
711 	openpic_write(OPENPIC_IPI_VECTOR(1), x);
712 
713 	/* XXX - ncpus */
714 	evcount_attach(&ipi_nop[0], "ipi_nop0", &ipi_nopirq);
715 	evcount_attach(&ipi_nop[1], "ipi_nop1", &ipi_nopirq);
716 	evcount_attach(&ipi_ddb[0], "ipi_ddb0", &ipi_ddbirq);
717 	evcount_attach(&ipi_ddb[1], "ipi_ddb1", &ipi_ddbirq);
718 #endif
719 
720 	/* clear all pending interrunts */
721 	for (irq = 0; irq < ICU_LEN; irq++) {
722 		openpic_read_irq(0);
723 		openpic_eoi(0);
724 	}
725 
726 #if 0
727 	openpic_write(OPENPIC_SPURIOUS_VECTOR, 255);
728 #endif
729 
730 	install_extint(openpic_ext_intr);
731 
732 	openpic_set_priority(ci->ci_cpuid, 0);
733 }
734 
735 void
736 openpic_ipi_ddb()
737 {
738 #ifdef OPENPIC_NOISY
739 	printf("ipi_ddb() called\n");
740 #endif
741 	Debugger();
742 }
743