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