Home | History | Annotate | Line # | Download | only in pic
intr.c revision 1.10
      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