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