xref: /netbsd-src/sys/arch/powerpc/pic/intr.c (revision b1c86f5f087524e68db12794ee9c3e3da1ab17a0)
1 /*	$NetBSD: intr.c,v 1.9 2010/05/12 06:11:31 macallan Exp $ */
2 
3 /*-
4  * Copyright (c) 2007 Michael Lorenz
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  *
16  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
17  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
18  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
19  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
20  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
21  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
22  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
23  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
24  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
25  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
26  * POSSIBILITY OF SUCH DAMAGE.
27  */
28 
29 #include <sys/cdefs.h>
30 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.9 2010/05/12 06:11:31 macallan Exp $");
31 
32 #include "opt_multiprocessor.h"
33 
34 #include <sys/param.h>
35 #include <sys/malloc.h>
36 #include <sys/kernel.h>
37 #include <sys/cpu.h>
38 
39 #include <uvm/uvm_extern.h>
40 
41 #include <arch/powerpc/pic/picvar.h>
42 #include "opt_pic.h"
43 #include "opt_interrupt.h"
44 #if defined(PIC_I8259) || defined (PIC_PREPIVR)
45 #include <machine/isa_machdep.h>
46 #endif
47 
48 #ifdef MULTIPROCESSOR
49 #include <arch/powerpc/pic/ipivar.h>
50 #endif
51 
52 #define MAX_PICS	8	/* 8 PICs ought to be enough for everyone */
53 
54 #define	LEGAL_VIRQ(x)	((x) >= 0 && (x) < NVIRQ)
55 
56 struct pic_ops *pics[MAX_PICS];
57 int num_pics = 0;
58 int max_base = 0;
59 uint8_t	virq[NIRQ];
60 int	virq_max = 0;
61 imask_t	imask[NIPL];
62 int	primary_pic = 0;
63 
64 static int	fakeintr(void *);
65 static int	mapirq(uint32_t);
66 static void	intr_calculatemasks(void);
67 static struct pic_ops *find_pic_by_irq(int);
68 
69 static struct intr_source intrsources[NVIRQ];
70 
71 void
72 pic_init(void)
73 {
74 	int i;
75 
76 	for (i = 0; i < NIRQ; i++)
77 		virq[i] = 0;
78 	memset(intrsources, 0, sizeof(intrsources));
79 }
80 
81 int
82 pic_add(struct pic_ops *pic)
83 {
84 
85 	if (num_pics >= MAX_PICS)
86 		return -1;
87 
88 	pics[num_pics] = pic;
89 	pic->pic_intrbase = max_base;
90 	max_base += pic->pic_numintrs;
91 	num_pics++;
92 
93 	return pic->pic_intrbase;
94 }
95 
96 void
97 pic_finish_setup(void)
98 {
99 	struct pic_ops *pic;
100 	int i;
101 
102 	for (i = 0; i < num_pics; i++) {
103 		pic = pics[i];
104 		if (pic->pic_finish_setup != NULL)
105 			pic->pic_finish_setup(pic);
106 	}
107 }
108 
109 static struct pic_ops *
110 find_pic_by_irq(int irq)
111 {
112 	struct pic_ops *current;
113 	int base = 0;
114 
115 	while (base < num_pics) {
116 
117 		current = pics[base];
118 		if ((irq >= current->pic_intrbase) &&
119 		    (irq < (current->pic_intrbase + current->pic_numintrs))) {
120 
121 			return current;
122 		}
123 		base++;
124 	}
125 	return NULL;
126 }
127 
128 static int
129 fakeintr(void *arg)
130 {
131 
132 	return 0;
133 }
134 
135 /*
136  * Register an interrupt handler.
137  */
138 void *
139 intr_establish(int hwirq, int type, int level, int (*ih_fun)(void *),
140     void *ih_arg)
141 {
142 	struct intrhand **p, *q, *ih;
143 	struct intr_source *is;
144 	struct pic_ops *pic;
145 	static struct intrhand fakehand;
146 	int irq, maxlevel = level;
147 
148 	if (maxlevel == IPL_NONE)
149 		maxlevel = IPL_HIGH;
150 
151 	if (hwirq >= max_base) {
152 
153 		panic("%s: bogus IRQ %d, max is %d", __func__, hwirq,
154 		    max_base - 1);
155 	}
156 
157 	pic = find_pic_by_irq(hwirq);
158 	if (pic == NULL) {
159 
160 		panic("%s: cannot find a pic for IRQ %d", __func__, hwirq);
161 	}
162 
163 	irq = mapirq(hwirq);
164 
165 	/* no point in sleeping unless someone can free memory. */
166 	ih = malloc(sizeof *ih, M_DEVBUF, cold ? M_NOWAIT : M_WAITOK);
167 	if (ih == NULL)
168 		panic("intr_establish: can't malloc handler info");
169 
170 	if (!LEGAL_VIRQ(irq) || type == IST_NONE)
171 		panic("intr_establish: bogus irq (%d) or type (%d)", irq, type);
172 
173 	is = &intrsources[irq];
174 
175 	switch (is->is_type) {
176 	case IST_NONE:
177 		is->is_type = type;
178 		break;
179 	case IST_EDGE:
180 	case IST_LEVEL:
181 		if (type == is->is_type)
182 			break;
183 	case IST_PULSE:
184 		if (type != IST_NONE)
185 			panic("intr_establish: can't share %s with %s",
186 			    intr_typename(is->is_type),
187 			    intr_typename(type));
188 		break;
189 	}
190 	if (is->is_hand == NULL) {
191 		snprintf(is->is_source, sizeof(is->is_source), "irq %d",
192 		    is->is_hwirq);
193 		evcnt_attach_dynamic(&is->is_ev, EVCNT_TYPE_INTR, NULL,
194 		    pic->pic_name, is->is_source);
195 	}
196 
197 	/*
198 	 * Figure out where to put the handler.
199 	 * This is O(N^2), but we want to preserve the order, and N is
200 	 * generally small.
201 	 */
202 	for (p = &is->is_hand; (q = *p) != NULL; p = &q->ih_next) {
203 
204 		maxlevel = max(maxlevel, q->ih_level);
205 	}
206 
207 	/*
208 	 * Actually install a fake handler momentarily, since we might be doing
209 	 * this with interrupts enabled and don't want the real routine called
210 	 * until masking is set up.
211 	 */
212 	fakehand.ih_level = level;
213 	fakehand.ih_fun = fakeintr;
214 	*p = &fakehand;
215 
216 	/*
217 	 * Poke the real handler in now.
218 	 */
219 	ih->ih_fun = ih_fun;
220 	ih->ih_arg = ih_arg;
221 	ih->ih_next = NULL;
222 	ih->ih_level = level;
223 	ih->ih_irq = irq;
224 	*p = ih;
225 
226 	if (pic->pic_establish_irq != NULL)
227 		pic->pic_establish_irq(pic, hwirq - pic->pic_intrbase,
228 		    is->is_type, maxlevel);
229 
230 	/*
231 	 * now that the handler is established we're actually ready to
232 	 * calculate the masks
233 	 */
234 	intr_calculatemasks();
235 
236 
237 	return ih;
238 }
239 
240 void
241 dummy_pic_establish_intr(struct pic_ops *pic, int irq, int type, int pri)
242 {
243 }
244 
245 /*
246  * Deregister an interrupt handler.
247  */
248 void
249 intr_disestablish(void *arg)
250 {
251 	struct intrhand *ih = arg;
252 	int irq = ih->ih_irq;
253 	struct intr_source *is = &intrsources[irq];
254 	struct intrhand **p, *q;
255 
256 	if (!LEGAL_VIRQ(irq))
257 		panic("intr_disestablish: bogus irq %d", irq);
258 
259 	/*
260 	 * Remove the handler from the chain.
261 	 * This is O(n^2), too.
262 	 */
263 	for (p = &is->is_hand; (q = *p) != NULL && q != ih; p = &q->ih_next)
264 		;
265 	if (q)
266 		*p = q->ih_next;
267 	else
268 		panic("intr_disestablish: handler not registered");
269 	free((void *)ih, M_DEVBUF);
270 
271 	intr_calculatemasks();
272 
273 	if (is->is_hand == NULL) {
274 		is->is_type = IST_NONE;
275 		evcnt_detach(&is->is_ev);
276 	}
277 }
278 
279 /*
280  * Map max_base irqs into 32 (bits).
281  */
282 static int
283 mapirq(uint32_t irq)
284 {
285 	struct pic_ops *pic;
286 	int v;
287 
288 	if (irq >= max_base)
289 		panic("invalid irq %d", irq);
290 
291 	if ((pic = find_pic_by_irq(irq)) == NULL)
292 		panic("%s: cannot find PIC for IRQ %d", __func__, irq);
293 
294 	if (virq[irq])
295 		return virq[irq];
296 
297 	virq_max++;
298 	v = virq_max;
299 	if (v > HWIRQ_MAX)
300 		panic("virq overflow");
301 
302 	intrsources[v].is_hwirq = irq;
303 	intrsources[v].is_pic = pic;
304 	virq[irq] = v;
305 #ifdef PIC_DEBUG
306 	printf("mapping irq %d to virq %d\n", irq, v);
307 #endif
308 	return v;
309 }
310 
311 static const char * const intr_typenames[] = {
312    [IST_NONE]  = "none",
313    [IST_PULSE] = "pulsed",
314    [IST_EDGE]  = "edge-triggered",
315    [IST_LEVEL] = "level-triggered",
316 };
317 
318 const char *
319 intr_typename(int type)
320 {
321 	KASSERT((unsigned int) type < __arraycount(intr_typenames));
322 	KASSERT(intr_typenames[type] != NULL);
323 	return intr_typenames[type];
324 }
325 
326 /*
327  * Recalculate the interrupt masks from scratch.
328  * We could code special registry and deregistry versions of this function that
329  * would be faster, but the code would be nastier, and we don't expect this to
330  * happen very much anyway.
331  */
332 static void
333 intr_calculatemasks(void)
334 {
335 	struct intr_source *is;
336 	struct intrhand *q;
337 	struct pic_ops *current;
338 	int irq, level, i, base;
339 
340 	/* First, figure out which levels each IRQ uses. */
341 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
342 		register int levels = 0;
343 		for (q = is->is_hand; q; q = q->ih_next)
344 			levels |= 1 << q->ih_level;
345 		is->is_level = levels;
346 	}
347 
348 	/* Then figure out which IRQs use each level. */
349 	for (level = 0; level < NIPL; level++) {
350 		register imask_t irqs = 0;
351 		for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++)
352 			if (is->is_level & (1 << level))
353 				irqs |= 1ULL << irq;
354 		imask[level] = irqs;
355 	}
356 
357 	/*
358 	 * IPL_CLOCK should mask clock interrupt even if interrupt handler
359 	 * is not registered.
360 	 */
361 	imask[IPL_CLOCK] |= 1ULL << SPL_CLOCK;
362 
363 	/*
364 	 * Initialize soft interrupt masks to block themselves.
365 	 */
366 	imask[IPL_SOFTCLOCK] = 1ULL << SIR_CLOCK;
367 	imask[IPL_SOFTNET] = 1ULL << SIR_NET;
368 	imask[IPL_SOFTSERIAL] = 1ULL << SIR_SERIAL;
369 
370 	/*
371 	 * IPL_NONE is used for hardware interrupts that are never blocked,
372 	 * and do not block anything else.
373 	 */
374 	imask[IPL_NONE] = 0;
375 
376 #ifdef SLOPPY_IPLS
377 	/*
378 	 * Enforce a sloppy hierarchy as in spl(9)
379 	 */
380 	/* everything above softclock must block softclock */
381 	for (i = IPL_SOFTCLOCK; i < NIPL; i++)
382 		imask[i] |= imask[IPL_SOFTCLOCK];
383 
384 	/* everything above softnet must block softnet */
385 	for (i = IPL_SOFTNET; i < NIPL; i++)
386 		imask[i] |= imask[IPL_SOFTNET];
387 
388 	/* IPL_TTY must block softserial */
389 	imask[IPL_TTY] |= imask[IPL_SOFTSERIAL];
390 
391 	/* IPL_VM must block net, block IO and tty */
392 	imask[IPL_VM] |= (imask[IPL_NET] | imask[IPL_BIO] | imask[IPL_TTY]);
393 
394 	/* IPL_SERIAL must block IPL_TTY */
395 	imask[IPL_SERIAL] |= imask[IPL_TTY];
396 
397 	/* IPL_HIGH must block all other priority levels */
398 	for (i = IPL_NONE; i < IPL_HIGH; i++)
399 		imask[IPL_HIGH] |= imask[i];
400 #else	/* !SLOPPY_IPLS */
401 	/*
402 	 * strict hierarchy - all IPLs block everything blocked by any lower
403 	 * IPL
404 	 */
405 	for (i = 1; i < NIPL; i++)
406 		imask[i] |= imask[i - 1];
407 #endif	/* !SLOPPY_IPLS */
408 
409 #ifdef DEBUG_IPL
410 	for (i = 0; i < NIPL; i++) {
411 		printf("%2d: %08x\n", i, imask[i]);
412 	}
413 #endif
414 
415 	/* And eventually calculate the complete masks. */
416 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
417 		register imask_t irqs = 1ULL << irq;
418 		for (q = is->is_hand; q; q = q->ih_next)
419 			irqs |= imask[q->ih_level];
420 		is->is_mask = irqs;
421 	}
422 
423 	/* Lastly, enable IRQs actually in use. */
424 	for (base = 0; base < num_pics; base++) {
425 		current = pics[base];
426 		for (i = 0; i < current->pic_numintrs; i++)
427 			current->pic_disable_irq(current, i);
428 	}
429 
430 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
431 		if (is->is_hand)
432 			pic_enable_irq(is->is_hwirq);
433 	}
434 }
435 
436 void
437 pic_enable_irq(int num)
438 {
439 	struct pic_ops *current;
440 	int type;
441 
442 	current = find_pic_by_irq(num);
443 	if (current == NULL)
444 		panic("%s: bogus IRQ %d", __func__, num);
445 	type = intrsources[virq[num]].is_type;
446 	current->pic_enable_irq(current, num - current->pic_intrbase, type);
447 }
448 
449 void
450 pic_mark_pending(int irq)
451 {
452 	struct cpu_info * const ci = curcpu();
453 	int v, msr;
454 
455 	v = virq[irq];
456 	if (v == 0)
457 		printf("IRQ %d maps to 0\n", irq);
458 
459 	msr = mfmsr();
460 	mtmsr(msr & ~PSL_EE);
461 	ci->ci_ipending |= 1ULL << v;
462 	mtmsr(msr);
463 }
464 
465 void
466 pic_do_pending_int(void)
467 {
468 	struct cpu_info * const ci = curcpu();
469 	struct intr_source *is;
470 	struct intrhand *ih;
471 	struct pic_ops *pic;
472 	int irq;
473 	int pcpl;
474 	imask_t hwpend;
475 	int emsr, dmsr;
476 
477 	if (ci->ci_iactive)
478 		return;
479 
480 	ci->ci_iactive = 1;
481 	emsr = mfmsr();
482 	KASSERT(emsr & PSL_EE);
483 	dmsr = emsr & ~PSL_EE;
484 	mtmsr(dmsr);
485 
486 	pcpl = ci->ci_cpl;
487 #ifdef __HAVE_FAST_SOFTINTS
488 again:
489 #endif
490 
491 	/* Do now unmasked pendings */
492 	ci->ci_idepth++;
493 	while ((hwpend = (ci->ci_ipending & ~pcpl & HWIRQ_MASK)) != 0) {
494 		/* Get most significant pending bit */
495 		irq = MS_PENDING(hwpend);
496 		KASSERT(irq <= virq_max);
497 		ci->ci_ipending &= ~(1ULL << irq);
498 		if (irq == 0) {
499 			printf("VIRQ0");
500 			continue;
501 		}
502 		is = &intrsources[irq];
503 		pic = is->is_pic;
504 
505 		splraise(is->is_mask);
506 		mtmsr(emsr);
507 		ih = is->is_hand;
508 		while (ih) {
509 #ifdef DIAGNOSTIC
510 			if (!ih->ih_fun) {
511 				printf("NULL interrupt handler!\n");
512 				panic("irq %02d, hwirq %02d, is %p\n",
513 					irq, is->is_hwirq, is);
514 			}
515 #endif
516 			if (ih->ih_level == IPL_VM) {
517 				KERNEL_LOCK(1, NULL);
518 			}
519 			(*ih->ih_fun)(ih->ih_arg);
520 			if (ih->ih_level == IPL_VM) {
521 				KERNEL_UNLOCK_ONE(NULL);
522 			}
523 			ih = ih->ih_next;
524 		}
525 		mtmsr(dmsr);
526 		ci->ci_cpl = pcpl;
527 
528 		is->is_ev.ev_count++;
529 		pic->pic_reenable_irq(pic, is->is_hwirq - pic->pic_intrbase,
530 		    is->is_type);
531 	}
532 	ci->ci_idepth--;
533 
534 #ifdef __HAVE_FAST_SOFTINTS
535 	if ((ci->ci_ipending & ~pcpl) & (1ULL << SIR_SERIAL)) {
536 		ci->ci_ipending &= ~(1ULL << SIR_SERIAL);
537 		splsoftserial();
538 		mtmsr(emsr);
539 		softintr__run(IPL_SOFTSERIAL);
540 		mtmsr(dmsr);
541 		ci->ci_cpl = pcpl;
542 		ci->ci_ev_softserial.ev_count++;
543 		goto again;
544 	}
545 	if ((ci->ci_ipending & ~pcpl) & (1ULL << SIR_NET)) {
546 		ci->ci_ipending &= ~(1ULL << SIR_NET);
547 		splsoftnet();
548 		mtmsr(emsr);
549 		softintr__run(IPL_SOFTNET);
550 		mtmsr(dmsr);
551 		ci->ci_cpl = pcpl;
552 		ci->ci_ev_softnet.ev_count++;
553 		goto again;
554 	}
555 	if ((ci->ci_ipending & ~pcpl) & (1ULL << SIR_CLOCK)) {
556 		ci->ci_ipending &= ~(1ULL << SIR_CLOCK);
557 		splsoftclock();
558 		mtmsr(emsr);
559 		softintr__run(IPL_SOFTCLOCK);
560 		mtmsr(dmsr);
561 		ci->ci_cpl = pcpl;
562 		ci->ci_ev_softclock.ev_count++;
563 		goto again;
564 	}
565 #endif
566 
567 	ci->ci_cpl = pcpl;	/* Don't use splx... we are here already! */
568 	ci->ci_iactive = 0;
569 	mtmsr(emsr);
570 }
571 
572 int
573 pic_handle_intr(void *cookie)
574 {
575 	struct pic_ops *pic = cookie;
576 	struct cpu_info *ci = curcpu();
577 	struct intr_source *is;
578 	struct intrhand *ih;
579 	int irq, realirq;
580 	int pcpl, msr, bail;
581 	imask_t r_imen;
582 
583 	realirq = pic->pic_get_irq(pic, PIC_GET_IRQ);
584 	if (realirq == 255)
585 		return 0;
586 
587 	msr = mfmsr();
588 	pcpl = ci->ci_cpl;
589 
590 start:
591 
592 #ifdef MULTIPROCESSOR
593 	/* THIS IS WRONG XXX */
594 	while (realirq == ipiops.ppc_ipi_vector) {
595 		ppcipi_intr(NULL);
596 		pic->pic_ack_irq(pic, realirq);
597 		realirq = pic->pic_get_irq(pic, PIC_GET_RECHECK);
598 	}
599 	if (realirq == 255) {
600 		return 0;
601 	}
602 #endif
603 
604 	irq = virq[realirq + pic->pic_intrbase];
605 #ifdef PIC_DEBUG
606 	if (irq == 0) {
607 		printf("%s: %d virq 0\n", pic->pic_name, realirq);
608 		goto boo;
609 	}
610 #endif /* PIC_DEBUG */
611 	KASSERT(realirq < pic->pic_numintrs);
612 	r_imen = 1ULL << irq;
613 	is = &intrsources[irq];
614 
615 	if ((pcpl & r_imen) != 0) {
616 
617 		ci->ci_ipending |= r_imen; /* Masked! Mark this as pending */
618 		pic->pic_disable_irq(pic, realirq);
619 	} else {
620 
621 		/* this interrupt is no longer pending */
622 		ci->ci_ipending &= ~r_imen;
623 		ci->ci_idepth++;
624 
625 		splraise(is->is_mask);
626 		mtmsr(msr | PSL_EE);
627 		ih = is->is_hand;
628 		bail = 0;
629 		while ((ih != NULL) && (bail < 10)) {
630 			if (ih->ih_fun == NULL)
631 				panic("bogus handler for IRQ %s %d",
632 				    pic->pic_name, realirq);
633 			if (ih->ih_level == IPL_VM) {
634 				KERNEL_LOCK(1, NULL);
635 			}
636 			(*ih->ih_fun)(ih->ih_arg);
637 			if (ih->ih_level == IPL_VM) {
638 				KERNEL_UNLOCK_ONE(NULL);
639 			}
640 			ih = ih->ih_next;
641 			bail++;
642 		}
643 		mtmsr(msr);
644 		ci->ci_cpl = pcpl;
645 
646 		uvmexp.intrs++;
647 		is->is_ev.ev_count++;
648 		ci->ci_idepth--;
649 	}
650 #ifdef PIC_DEBUG
651 boo:
652 #endif /* PIC_DEBUG */
653 	pic->pic_ack_irq(pic, realirq);
654 	realirq = pic->pic_get_irq(pic, PIC_GET_RECHECK);
655 	if (realirq != 255)
656 		goto start;
657 
658 	mtmsr(msr | PSL_EE);
659 	splx(pcpl);	/* Process pendings. */
660 	mtmsr(msr);
661 
662 	return 0;
663 }
664 
665 void
666 pic_ext_intr(void)
667 {
668 
669 	KASSERT(pics[primary_pic] != NULL);
670 	pic_handle_intr(pics[primary_pic]);
671 
672 	return;
673 
674 }
675 
676 int
677 splraise(int ncpl)
678 {
679 	struct cpu_info *ci = curcpu();
680 	int ocpl;
681 
682 	__asm volatile("sync; eieio");	/* don't reorder.... */
683 
684 	ocpl = ci->ci_cpl;
685 	ci->ci_cpl = ocpl | ncpl;
686 	__asm volatile("sync; eieio");	/* reorder protect */
687 	return ocpl;
688 }
689 
690 void
691 splx(int ncpl)
692 {
693 	struct cpu_info *ci = curcpu();
694 
695 	__asm volatile("sync; eieio");	/* reorder protect */
696 	ci->ci_cpl = ncpl;
697 	if (ci->ci_ipending & ~ncpl)
698 		pic_do_pending_int();
699 	__asm volatile("sync; eieio");	/* reorder protect */
700 }
701 
702 int
703 spllower(int ncpl)
704 {
705 	struct cpu_info *ci = curcpu();
706 	int ocpl;
707 
708 	__asm volatile("sync; eieio");	/* reorder protect */
709 	ocpl = ci->ci_cpl;
710 	ci->ci_cpl = ncpl;
711 	if (ci->ci_ipending & ~ncpl)
712 		pic_do_pending_int();
713 	__asm volatile("sync; eieio");	/* reorder protect */
714 	return ocpl;
715 }
716 
717 /* Following code should be implemented with lwarx/stwcx to avoid
718  * the disable/enable. i need to read the manual once more.... */
719 void
720 softintr(int ipl)
721 {
722 	int msrsave;
723 
724 	msrsave = mfmsr();
725 	mtmsr(msrsave & ~PSL_EE);
726 	curcpu()->ci_ipending |= 1ULL << ipl;
727 	mtmsr(msrsave);
728 }
729 
730 void
731 genppc_cpu_configure(void)
732 {
733 	aprint_normal("biomask %x netmask %x ttymask %x\n",
734 	    (u_int)imask[IPL_BIO] & 0x1fffffff,
735 	    (u_int)imask[IPL_NET] & 0x1fffffff,
736 	    (u_int)imask[IPL_TTY] & 0x1fffffff);
737 
738 	spl0();
739 }
740 
741 #if defined(PIC_PREPIVR) || defined(PIC_I8259)
742 /*
743  * isa_intr_alloc needs to be done here, because it needs direct access to
744  * the various interrupt handler structures.
745  */
746 
747 int
748 genppc_isa_intr_alloc(isa_chipset_tag_t ic, struct pic_ops *pic,
749     int mask, int type, int *irq_p)
750 {
751 	int irq, vi;
752 	int maybe_irq = -1;
753 	int shared_depth = 0;
754 	struct intr_source *is;
755 
756 	if (pic == NULL)
757 		return 1;
758 
759 	for (irq = 0; (mask != 0 && irq < pic->pic_numintrs);
760 	     mask >>= 1, irq++) {
761 		if ((mask & 1) == 0)
762 			continue;
763 		vi = virq[irq + pic->pic_intrbase];
764 		if (!vi) {
765 			*irq_p = irq;
766 			return 0;
767 		}
768 		is = &intrsources[vi];
769 		if (is->is_type == IST_NONE) {
770 			*irq_p = irq;
771 			return 0;
772 		}
773 		/* Level interrupts can be shared */
774 		if (type == IST_LEVEL && is->is_type == IST_LEVEL) {
775 			struct intrhand *ih = is->is_hand;
776 			int depth;
777 
778 			if (maybe_irq == -1) {
779 				maybe_irq = irq;
780 				continue;
781 			}
782 			for (depth = 0; ih != NULL; ih = ih->ih_next)
783 				depth++;
784 			if (depth < shared_depth) {
785 				maybe_irq = irq;
786 				shared_depth = depth;
787 			}
788 		}
789 	}
790 	if (maybe_irq != -1) {
791 		*irq_p = maybe_irq;
792 		return 0;
793 	}
794 	return 1;
795 }
796 #endif
797