Home | History | Annotate | Line # | Download | only in pic
intr.c revision 1.23
      1 /*	$NetBSD: intr.c,v 1.23 2012/08/31 13:12:52 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.23 2012/08/31 13:12:52 macallan Exp $");
     31 
     32 #include "opt_interrupt.h"
     33 #include "opt_multiprocessor.h"
     34 #include "opt_pic.h"
     35 
     36 #define __INTR_PRIVATE
     37 
     38 #include <sys/param.h>
     39 #include <sys/cpu.h>
     40 #include <sys/kernel.h>
     41 #include <sys/kmem.h>
     42 
     43 #include <powerpc/psl.h>
     44 #include <powerpc/pic/picvar.h>
     45 
     46 #if defined(PIC_I8259) || defined (PIC_PREPIVR)
     47 #include <machine/isa_machdep.h>
     48 #endif
     49 
     50 #ifdef MULTIPROCESSOR
     51 #include <powerpc/pic/ipivar.h>
     52 #endif
     53 
     54 #ifdef __HAVE_FAST_SOFTINTS
     55 #include <powerpc/softint.h>
     56 #endif
     57 
     58 #define MAX_PICS	8	/* 8 PICs ought to be enough for everyone */
     59 
     60 #define	PIC_VIRQ_LEGAL_P(x)	((u_int)(x) < NVIRQ)
     61 
     62 struct pic_ops *pics[MAX_PICS];
     63 int num_pics = 0;
     64 int max_base = 0;
     65 uint8_t	virq_map[NIRQ];
     66 imask_t virq_mask = HWIRQ_MASK;
     67 imask_t	imask[NIPL];
     68 int	primary_pic = 0;
     69 
     70 static int	fakeintr(void *);
     71 static int	mapirq(int);
     72 static void	intr_calculatemasks(void);
     73 static struct pic_ops *find_pic_by_hwirq(int);
     74 
     75 static struct intr_source intrsources[NVIRQ];
     76 
     77 void
     78 pic_init(void)
     79 {
     80 	/* everything is in bss, no reason to zero it. */
     81 }
     82 
     83 int
     84 pic_add(struct pic_ops *pic)
     85 {
     86 
     87 	if (num_pics >= MAX_PICS)
     88 		return -1;
     89 
     90 	pics[num_pics] = pic;
     91 	pic->pic_intrbase = max_base;
     92 	max_base += pic->pic_numintrs;
     93 	num_pics++;
     94 
     95 	return pic->pic_intrbase;
     96 }
     97 
     98 void
     99 pic_finish_setup(void)
    100 {
    101 	for (size_t i = 0; i < num_pics; i++) {
    102 		struct pic_ops * const pic = pics[i];
    103 		if (pic->pic_finish_setup != NULL)
    104 			pic->pic_finish_setup(pic);
    105 	}
    106 }
    107 
    108 static struct pic_ops *
    109 find_pic_by_hwirq(int hwirq)
    110 {
    111 	for (u_int base = 0; base < num_pics; base++) {
    112 		struct pic_ops * const pic = pics[base];
    113 		if (pic->pic_intrbase <= hwirq
    114 		    && hwirq < pic->pic_intrbase + pic->pic_numintrs) {
    115 			return pic;
    116 		}
    117 	}
    118 	return NULL;
    119 }
    120 
    121 static int
    122 fakeintr(void *arg)
    123 {
    124 
    125 	return 0;
    126 }
    127 
    128 /*
    129  * Register an interrupt handler.
    130  */
    131 void *
    132 intr_establish(int hwirq, int type, int ipl, int (*ih_fun)(void *),
    133     void *ih_arg)
    134 {
    135 	struct intrhand **p, *q, *ih;
    136 	struct pic_ops *pic;
    137 	static struct intrhand fakehand;
    138 	int maxipl = ipl;
    139 
    140 	if (maxipl == IPL_NONE)
    141 		maxipl = IPL_HIGH;
    142 
    143 	if (hwirq >= max_base) {
    144 		panic("%s: bogus IRQ %d, max is %d", __func__, hwirq,
    145 		    max_base - 1);
    146 	}
    147 
    148 	pic = find_pic_by_hwirq(hwirq);
    149 	if (pic == NULL) {
    150 
    151 		panic("%s: cannot find a pic for IRQ %d", __func__, hwirq);
    152 	}
    153 
    154 	const int virq = mapirq(hwirq);
    155 
    156 	/* no point in sleeping unless someone can free memory. */
    157 	ih = kmem_intr_alloc(sizeof(*ih), cold ? KM_NOSLEEP : KM_SLEEP);
    158 	if (ih == NULL)
    159 		panic("intr_establish: can't allocate handler info");
    160 
    161 	if (!PIC_VIRQ_LEGAL_P(virq) || type == IST_NONE)
    162 		panic("intr_establish: bogus irq (%d) or type (%d)",
    163 		    hwirq, type);
    164 
    165 	struct intr_source * const is = &intrsources[virq];
    166 
    167 	switch (is->is_type) {
    168 	case IST_NONE:
    169 		is->is_type = type;
    170 		break;
    171 	case IST_EDGE_FALLING:
    172 	case IST_EDGE_RISING:
    173 	case IST_LEVEL_LOW:
    174 	case IST_LEVEL_HIGH:
    175 		if (type == is->is_type)
    176 			break;
    177 		/* FALLTHROUGH */
    178 	case IST_PULSE:
    179 		if (type != IST_NONE)
    180 			panic("intr_establish: can't share %s with %s",
    181 			    intr_typename(is->is_type),
    182 			    intr_typename(type));
    183 		break;
    184 	}
    185 	if (is->is_hand == NULL) {
    186 		snprintf(is->is_source, sizeof(is->is_source), "irq %d",
    187 		    is->is_hwirq);
    188 		evcnt_attach_dynamic(&is->is_ev, EVCNT_TYPE_INTR, NULL,
    189 		    pic->pic_name, is->is_source);
    190 	}
    191 
    192 	/*
    193 	 * Figure out where to put the handler.
    194 	 * This is O(N^2), but we want to preserve the order, and N is
    195 	 * generally small.
    196 	 */
    197 	for (p = &is->is_hand; (q = *p) != NULL; p = &q->ih_next) {
    198 		maxipl = max(maxipl, q->ih_ipl);
    199 	}
    200 
    201 	/*
    202 	 * Actually install a fake handler momentarily, since we might be doing
    203 	 * this with interrupts enabled and don't want the real routine called
    204 	 * until masking is set up.
    205 	 */
    206 	fakehand.ih_ipl = ipl;
    207 	fakehand.ih_fun = fakeintr;
    208 	*p = &fakehand;
    209 
    210 	/*
    211 	 * Poke the real handler in now.
    212 	 */
    213 	ih->ih_fun = ih_fun;
    214 	ih->ih_arg = ih_arg;
    215 	ih->ih_next = NULL;
    216 	ih->ih_ipl = ipl;
    217 	ih->ih_virq = virq;
    218 	*p = ih;
    219 
    220 	if (pic->pic_establish_irq != NULL)
    221 		pic->pic_establish_irq(pic, hwirq - pic->pic_intrbase,
    222 		    is->is_type, maxipl);
    223 
    224 	/*
    225 	 * Remember the highest IPL used by this handler.
    226 	 */
    227 	is->is_ipl = maxipl;
    228 
    229 	/*
    230 	 * now that the handler is established we're actually ready to
    231 	 * calculate the masks
    232 	 */
    233 	intr_calculatemasks();
    234 
    235 
    236 	return ih;
    237 }
    238 
    239 void
    240 dummy_pic_establish_intr(struct pic_ops *pic, int irq, int type, int pri)
    241 {
    242 }
    243 
    244 /*
    245  * Deregister an interrupt handler.
    246  */
    247 void
    248 intr_disestablish(void *arg)
    249 {
    250 	struct intrhand * const ih = arg;
    251 	const int virq = ih->ih_virq;
    252 	struct intr_source * const is = &intrsources[virq];
    253 	struct intrhand **p, **q;
    254 	int maxipl = IPL_NONE;
    255 
    256 	if (!PIC_VIRQ_LEGAL_P(virq))
    257 		panic("intr_disestablish: bogus virq %d", virq);
    258 
    259 	/*
    260 	 * Remove the handler from the chain.
    261 	 * This is O(n^2), too.
    262 	 */
    263 	for (p = &is->is_hand, q = NULL; (*p) != NULL; p = &(*p)->ih_next) {
    264 		struct intrhand * const tmp_ih = *p;
    265 		if (tmp_ih == ih) {
    266 			q = p;
    267 		} else {
    268 			maxipl = max(maxipl, tmp_ih->ih_ipl);
    269 		}
    270 	}
    271 	if (q)
    272 		*q = ih->ih_next;
    273 	else
    274 		panic("intr_disestablish: handler not registered");
    275 	kmem_intr_free((void *)ih, sizeof(*ih));
    276 
    277 	/*
    278 	 * Reset the IPL for this source now that we've removed a handler.
    279 	 */
    280 	is->is_ipl = maxipl;
    281 
    282 	intr_calculatemasks();
    283 
    284 	if (is->is_hand == NULL) {
    285 		is->is_type = IST_NONE;
    286 		evcnt_detach(&is->is_ev);
    287 		/*
    288 		 * Make the virutal IRQ available again.
    289 		 */
    290 		virq_map[virq] = 0;
    291 		virq_mask |= PIC_VIRQ_TO_MASK(virq);
    292 	}
    293 }
    294 
    295 /*
    296  * Map max_base irqs into 32 (bits).
    297  */
    298 static int
    299 mapirq(int hwirq)
    300 {
    301 	struct pic_ops *pic;
    302 
    303 	if (hwirq >= max_base)
    304 		panic("invalid irq %d", hwirq);
    305 
    306 	if ((pic = find_pic_by_hwirq(hwirq)) == NULL)
    307 		panic("%s: cannot find PIC for HWIRQ %d", __func__, hwirq);
    308 
    309 	if (virq_map[hwirq])
    310 		return virq_map[hwirq];
    311 
    312 	if (virq_mask == 0)
    313 		panic("virq overflow");
    314 
    315 	const int virq = PIC_VIRQ_MS_PENDING(virq_mask);
    316 	struct intr_source * const is = intrsources + virq;
    317 
    318 	virq_mask &= ~PIC_VIRQ_TO_MASK(virq);
    319 
    320 	is->is_hwirq = hwirq;
    321 	is->is_pic = pic;
    322 	virq_map[hwirq] = virq;
    323 #ifdef PIC_DEBUG
    324 	printf("mapping hwirq %d to virq %d\n", hwirq, virq);
    325 #endif
    326 	return virq;
    327 }
    328 
    329 static const char * const intr_typenames[] = {
    330    [IST_NONE]  = "none",
    331    [IST_PULSE] = "pulsed",
    332    [IST_EDGE_FALLING]  = "falling edge triggered",
    333    [IST_EDGE_RISING]  = "rising edge triggered",
    334    [IST_LEVEL_LOW] = "low level triggered",
    335    [IST_LEVEL_HIGH] = "high level triggered",
    336 };
    337 
    338 const char *
    339 intr_typename(int type)
    340 {
    341 	KASSERT((unsigned int) type < __arraycount(intr_typenames));
    342 	KASSERT(intr_typenames[type] != NULL);
    343 	return intr_typenames[type];
    344 }
    345 
    346 /*
    347  * Recalculate the interrupt masks from scratch.
    348  * We could code special registry and deregistry versions of this function that
    349  * would be faster, but the code would be nastier, and we don't expect this to
    350  * happen very much anyway.
    351  */
    352 static void
    353 intr_calculatemasks(void)
    354 {
    355 	imask_t newmask[NIPL];
    356 	struct intr_source *is;
    357 	struct intrhand *ih;
    358 	int irq;
    359 
    360 	for (u_int ipl = IPL_NONE; ipl < NIPL; ipl++) {
    361 		newmask[ipl] = 0;
    362 	}
    363 
    364 	/* First, figure out which ipl each IRQ uses. */
    365 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
    366 		for (ih = is->is_hand; ih != NULL; ih = ih->ih_next) {
    367 			newmask[ih->ih_ipl] |= PIC_VIRQ_TO_MASK(irq);
    368 		}
    369 	}
    370 
    371 	/*
    372 	 * IPL_NONE is used for hardware interrupts that are never blocked,
    373 	 * and do not block anything else.
    374 	 */
    375 	newmask[IPL_NONE] = 0;
    376 
    377 	/*
    378 	 * strict hierarchy - all IPLs block everything blocked by any lower
    379 	 * IPL
    380 	 */
    381 	for (u_int ipl = 1; ipl < NIPL; ipl++) {
    382 		newmask[ipl] |= newmask[ipl - 1];
    383 	}
    384 
    385 #ifdef PIC_DEBUG
    386 	for (u_int ipl = 0; ipl < NIPL; ipl++) {
    387 		printf("%u: %08x -> %08x\n", ipl, imask[ipl], newmask[ipl]);
    388 	}
    389 #endif
    390 
    391 	/*
    392 	 * Disable all interrupts.
    393 	 */
    394 	for (u_int base = 0; base < num_pics; base++) {
    395 		struct pic_ops * const pic = pics[base];
    396 		for (u_int i = 0; i < pic->pic_numintrs; i++) {
    397 			pic->pic_disable_irq(pic, i);
    398 		}
    399 	}
    400 
    401 	/*
    402 	 * Now that all interrupts are disabled, update the ipl masks.
    403 	 */
    404 	for (u_int ipl = 0; ipl < NIPL; ipl++) {
    405 		imask[ipl] = newmask[ipl];
    406 	}
    407 
    408 	/*
    409 	 * Lastly, enable IRQs actually in use.
    410 	 */
    411 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
    412 		if (is->is_hand)
    413 			pic_enable_irq(is->is_hwirq);
    414 	}
    415 }
    416 
    417 void
    418 pic_enable_irq(int hwirq)
    419 {
    420 	struct pic_ops * const pic = find_pic_by_hwirq(hwirq);
    421 	if (pic == NULL)
    422 		panic("%s: bogus IRQ %d", __func__, hwirq);
    423 	const int type = intrsources[virq_map[hwirq]].is_type;
    424 	(*pic->pic_enable_irq)(pic, hwirq - pic->pic_intrbase, type);
    425 }
    426 
    427 void
    428 pic_mark_pending(int hwirq)
    429 {
    430 	struct cpu_info * const ci = curcpu();
    431 
    432 	const int virq = virq_map[hwirq];
    433 	if (virq == 0)
    434 		printf("IRQ %d maps to 0\n", hwirq);
    435 
    436 	const register_t msr = mfmsr();
    437 	mtmsr(msr & ~PSL_EE);
    438 	ci->ci_ipending |= PIC_VIRQ_TO_MASK(virq);
    439 	mtmsr(msr);
    440 }
    441 
    442 static void
    443 intr_deliver(struct intr_source *is, int virq)
    444 {
    445 	bool locked = false;
    446 	for (struct intrhand *ih = is->is_hand; ih != NULL; ih = ih->ih_next) {
    447 		KASSERTMSG(ih->ih_fun != NULL,
    448 		    "%s: irq %d, hwirq %d, is %p ih %p: "
    449 		     "NULL interrupt handler!\n", __func__,
    450 		     virq, is->is_hwirq, is, ih);
    451 		if (ih->ih_ipl == IPL_VM) {
    452 			if (!locked) {
    453 				KERNEL_LOCK(1, NULL);
    454 				locked = true;
    455 			}
    456 		} else if (locked) {
    457 			KERNEL_UNLOCK_ONE(NULL);
    458 			locked = false;
    459 		}
    460 		(*ih->ih_fun)(ih->ih_arg);
    461 	}
    462 	if (locked) {
    463 		KERNEL_UNLOCK_ONE(NULL);
    464 	}
    465 	is->is_ev.ev_count++;
    466 }
    467 
    468 void
    469 pic_do_pending_int(void)
    470 {
    471 	struct cpu_info * const ci = curcpu();
    472 	imask_t vpend;
    473 
    474 	if (ci->ci_iactive)
    475 		return;
    476 
    477 	ci->ci_iactive = 1;
    478 
    479 	const register_t emsr = mfmsr();
    480 	const register_t dmsr = emsr & ~PSL_EE;
    481 
    482 	KASSERT(emsr & PSL_EE);
    483 	mtmsr(dmsr);
    484 
    485 	const int pcpl = ci->ci_cpl;
    486 #ifdef __HAVE_FAST_SOFTINTS
    487 again:
    488 #endif
    489 
    490 	/* Do now unmasked pendings */
    491 	while ((vpend = (ci->ci_ipending & ~imask[pcpl])) != 0) {
    492 		ci->ci_idepth++;
    493 		KASSERT((PIC_VIRQ_TO_MASK(0) & ci->ci_ipending) == 0);
    494 
    495 		/* Get most significant pending bit */
    496 		const int virq = PIC_VIRQ_MS_PENDING(vpend);
    497 		ci->ci_ipending &= ~PIC_VIRQ_TO_MASK(virq);
    498 
    499 		struct intr_source * const is = &intrsources[virq];
    500 		struct pic_ops * const pic = is->is_pic;
    501 
    502 		splraise(is->is_ipl);
    503 		mtmsr(emsr);
    504 		intr_deliver(is, virq);
    505 		mtmsr(dmsr);
    506 		ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
    507 
    508 		pic->pic_reenable_irq(pic, is->is_hwirq - pic->pic_intrbase,
    509 		    is->is_type);
    510 		ci->ci_idepth--;
    511 	}
    512 
    513 #ifdef __HAVE_FAST_SOFTINTS
    514 	const u_int softints = ci->ci_data.cpu_softints &
    515 				 (IPL_SOFTMASK << pcpl);
    516 
    517 	/* make sure there are no bits to screw with the line above */
    518 	KASSERT((ci->ci_data.cpu_softints & ~IPL_SOFTMASK) == 0);
    519 
    520 	if (__predict_false(softints != 0)) {
    521 		ci->ci_cpl = IPL_HIGH;
    522 		mtmsr(emsr);
    523 		powerpc_softint(ci, pcpl,
    524 		    (vaddr_t)__builtin_return_address(0));
    525 		mtmsr(dmsr);
    526 		ci->ci_cpl = pcpl;
    527 		if (__predict_false(ci->ci_ipending & ~imask[pcpl]))
    528 			goto again;
    529 	}
    530 #endif
    531 
    532 	ci->ci_iactive = 0;
    533 	mtmsr(emsr);
    534 }
    535 
    536 int
    537 pic_handle_intr(void *cookie)
    538 {
    539 	struct pic_ops *pic = cookie;
    540 	struct cpu_info *ci = curcpu();
    541 	int picirq;
    542 
    543 	picirq = pic->pic_get_irq(pic, PIC_GET_IRQ);
    544 	if (picirq == 255)
    545 		return 0;
    546 
    547 	const register_t msr = mfmsr();
    548 	const int pcpl = ci->ci_cpl;
    549 
    550 	do {
    551 #ifdef MULTIPROCESSOR
    552 		/* THIS IS WRONG XXX */
    553 		if (picirq == ipiops.ppc_ipi_vector) {
    554 			ci->ci_cpl = IPL_HIGH;
    555 			ipi_intr(NULL);
    556 			ci->ci_cpl = pcpl;
    557 			pic->pic_ack_irq(pic, picirq);
    558 			continue;
    559 		}
    560 #endif
    561 
    562 		const int virq = virq_map[picirq + pic->pic_intrbase];
    563 		KASSERT(virq != 0);
    564 		KASSERT(picirq < pic->pic_numintrs);
    565 		imask_t v_imen = PIC_VIRQ_TO_MASK(virq);
    566 		struct intr_source * const is = &intrsources[virq];
    567 
    568 		if ((imask[pcpl] & v_imen) != 0) {
    569 			ci->ci_ipending |= v_imen; /* Masked! Mark this as pending */
    570 			pic->pic_disable_irq(pic, picirq);
    571 		} else {
    572 			/* this interrupt is no longer pending */
    573 			ci->ci_ipending &= ~v_imen;
    574 			ci->ci_idepth++;
    575 
    576 			splraise(is->is_ipl);
    577 			mtmsr(msr | PSL_EE);
    578 			intr_deliver(is, virq);
    579 			mtmsr(msr);
    580 			ci->ci_cpl = pcpl;
    581 
    582 			ci->ci_data.cpu_nintr++;
    583 			ci->ci_idepth--;
    584 		}
    585 		pic->pic_ack_irq(pic, picirq);
    586 	} while ((picirq = pic->pic_get_irq(pic, PIC_GET_RECHECK)) != 255);
    587 
    588 	mtmsr(msr | PSL_EE);
    589 	splx(pcpl);	/* Process pendings. */
    590 	mtmsr(msr);
    591 
    592 	return 0;
    593 }
    594 
    595 void
    596 pic_ext_intr(void)
    597 {
    598 
    599 	KASSERT(pics[primary_pic] != NULL);
    600 	pic_handle_intr(pics[primary_pic]);
    601 
    602 	return;
    603 
    604 }
    605 
    606 int
    607 splraise(int ncpl)
    608 {
    609 	struct cpu_info *ci = curcpu();
    610 	int ocpl;
    611 
    612 	if (ncpl == ci->ci_cpl) return ncpl;
    613 	__asm volatile("sync; eieio");	/* don't reorder.... */
    614 	ocpl = ci->ci_cpl;
    615 	KASSERT(ncpl < NIPL);
    616 	ci->ci_cpl = max(ncpl, ocpl);
    617 	__asm volatile("sync; eieio");	/* reorder protect */
    618 	__insn_barrier();
    619 	return ocpl;
    620 }
    621 
    622 static inline bool
    623 have_pending_intr_p(struct cpu_info *ci, int ncpl)
    624 {
    625 	if (ci->ci_ipending & ~imask[ncpl])
    626 		return true;
    627 #ifdef __HAVE_FAST_SOFTINTS
    628 	if (ci->ci_data.cpu_softints & (IPL_SOFTMASK << ncpl))
    629 		return true;
    630 #endif
    631 	return false;
    632 }
    633 
    634 void
    635 splx(int ncpl)
    636 {
    637 	struct cpu_info *ci = curcpu();
    638 
    639 	__insn_barrier();
    640 	__asm volatile("sync; eieio");	/* reorder protect */
    641 	ci->ci_cpl = ncpl;
    642 	if (have_pending_intr_p(ci, ncpl))
    643 		pic_do_pending_int();
    644 
    645 	__asm volatile("sync; eieio");	/* reorder protect */
    646 }
    647 
    648 int
    649 spllower(int ncpl)
    650 {
    651 	struct cpu_info *ci = curcpu();
    652 	int ocpl;
    653 
    654 	__insn_barrier();
    655 	__asm volatile("sync; eieio");	/* reorder protect */
    656 	ocpl = ci->ci_cpl;
    657 	ci->ci_cpl = ncpl;
    658 	if (have_pending_intr_p(ci, ncpl))
    659 		pic_do_pending_int();
    660 	__asm volatile("sync; eieio");	/* reorder protect */
    661 	return ocpl;
    662 }
    663 
    664 void
    665 genppc_cpu_configure(void)
    666 {
    667 	aprint_normal("vmmask %x schedmask %x highmask %x\n",
    668 	    (u_int)imask[IPL_VM] & 0x7fffffff,
    669 	    (u_int)imask[IPL_SCHED] & 0x7fffffff,
    670 	    (u_int)imask[IPL_HIGH] & 0x7fffffff);
    671 
    672 	spl0();
    673 }
    674 
    675 #if defined(PIC_PREPIVR) || defined(PIC_I8259)
    676 /*
    677  * isa_intr_alloc needs to be done here, because it needs direct access to
    678  * the various interrupt handler structures.
    679  */
    680 
    681 int
    682 genppc_isa_intr_alloc(isa_chipset_tag_t ic, struct pic_ops *pic,
    683     int mask, int type, int *irq_p)
    684 {
    685 	int irq, vi;
    686 	int maybe_irq = -1;
    687 	int shared_depth = 0;
    688 	struct intr_source *is;
    689 
    690 	if (pic == NULL)
    691 		return 1;
    692 
    693 	for (irq = 0; (mask != 0 && irq < pic->pic_numintrs);
    694 	     mask >>= 1, irq++) {
    695 		if ((mask & 1) == 0)
    696 			continue;
    697 		vi = virq_map[irq + pic->pic_intrbase];
    698 		if (!vi) {
    699 			*irq_p = irq;
    700 			return 0;
    701 		}
    702 		is = &intrsources[vi];
    703 		if (is->is_type == IST_NONE) {
    704 			*irq_p = irq;
    705 			return 0;
    706 		}
    707 		/* Level interrupts can be shared */
    708 		if (type == IST_LEVEL && is->is_type == IST_LEVEL) {
    709 			struct intrhand *ih = is->is_hand;
    710 			int depth;
    711 
    712 			if (maybe_irq == -1) {
    713 				maybe_irq = irq;
    714 				continue;
    715 			}
    716 			for (depth = 0; ih != NULL; ih = ih->ih_next)
    717 				depth++;
    718 			if (depth < shared_depth) {
    719 				maybe_irq = irq;
    720 				shared_depth = depth;
    721 			}
    722 		}
    723 	}
    724 	if (maybe_irq != -1) {
    725 		*irq_p = maybe_irq;
    726 		return 0;
    727 	}
    728 	return 1;
    729 }
    730 #endif
    731