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