Home | History | Annotate | Line # | Download | only in pic
      1 /*	$NetBSD: intr.c,v 1.41 2026/09/28 20:41:01 rkujawa 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 #define __INTR_PRIVATE
     30 
     31 #include <sys/cdefs.h>
     32 __KERNEL_RCSID(0, "$NetBSD: intr.c,v 1.41 2026/09/28 20:41:01 rkujawa Exp $");
     33 
     34 #ifdef _KERNEL_OPT
     35 #include "opt_interrupt.h"
     36 #include "opt_multiprocessor.h"
     37 #include "opt_pic.h"
     38 #include "opt_ppcarch.h"
     39 #endif
     40 
     41 #include <sys/param.h>
     42 #include <sys/cpu.h>
     43 #include <sys/kernel.h>
     44 #include <sys/kmem.h>
     45 #include <sys/interrupt.h>
     46 
     47 #include <powerpc/psl.h>
     48 #include <powerpc/pic/picvar.h>
     49 
     50 #if defined(PIC_I8259) || defined (PIC_PREPIVR)
     51 #include <machine/isa_machdep.h>
     52 #endif
     53 
     54 #ifdef MULTIPROCESSOR
     55 #include <powerpc/pic/ipivar.h>
     56 #endif
     57 
     58 #ifdef __HAVE_FAST_SOFTINTS
     59 #include <powerpc/softint.h>
     60 #endif
     61 
     62 #define MAX_PICS	8	/* 8 PICs ought to be enough for everyone */
     63 
     64 #define	PIC_VIRQ_LEGAL_P(x)	((u_int)(x) < NVIRQ)
     65 
     66 #if defined(PPC_IBM4XX) && !defined(PPC_IBM440)
     67 /* eieio is implemented as sync */
     68 #define REORDER_PROTECT() __asm volatile("sync" ::: "memory")
     69 #else
     70 #define REORDER_PROTECT() __asm volatile("sync; eieio" ::: "memory")
     71 #endif
     72 
     73 struct pic_ops *pics[MAX_PICS];
     74 int num_pics = 0;
     75 int max_base = 0;
     76 uint8_t	virq_map[NIRQ];
     77 imask_t virq_mask = HWIRQ_MASK;
     78 static imask_t imask[NIPL];
     79 int	primary_pic = 0;
     80 
     81 static int	fakeintr(void *);
     82 static int	mapirq(int);
     83 static void	intr_calculatemasks(void);
     84 static struct pic_ops *find_pic_by_hwirq(int);
     85 
     86 static struct intr_source intrsources[NVIRQ];
     87 
     88 void
     89 pic_init(void)
     90 {
     91 	/* everything is in bss, no reason to zero it. */
     92 }
     93 
     94 struct pic_ops *
     95 find_pic_by_cookie(void *c)
     96 {
     97 	int i = 0;
     98 	while (i < num_pics) {
     99 		if (pics[i]->pic_cookie == c)
    100 			return pics[i];
    101 		i++;
    102 	}
    103 	return NULL;
    104 }
    105 
    106 int
    107 pic_add(struct pic_ops *pic)
    108 {
    109 
    110 	if (num_pics >= MAX_PICS)
    111 		return -1;
    112 
    113 	pics[num_pics] = pic;
    114 	pic->pic_intrbase = max_base;
    115 	max_base += pic->pic_numintrs;
    116 	num_pics++;
    117 
    118 	return pic->pic_intrbase;
    119 }
    120 
    121 void
    122 pic_finish_setup(void)
    123 {
    124 	for (size_t i = 0; i < num_pics; i++) {
    125 		struct pic_ops * const pic = pics[i];
    126 		if (pic->pic_finish_setup != NULL)
    127 			pic->pic_finish_setup(pic);
    128 	}
    129 }
    130 
    131 static struct pic_ops *
    132 find_pic_by_hwirq(int hwirq)
    133 {
    134 	for (u_int base = 0; base < num_pics; base++) {
    135 		struct pic_ops * const pic = pics[base];
    136 		if (pic->pic_intrbase <= hwirq
    137 		    && hwirq < pic->pic_intrbase + pic->pic_numintrs) {
    138 			return pic;
    139 		}
    140 	}
    141 	return NULL;
    142 }
    143 
    144 static int
    145 fakeintr(void *arg)
    146 {
    147 
    148 	return 0;
    149 }
    150 
    151 /*
    152  * Register an interrupt handler.
    153  */
    154 void *
    155 intr_establish(int hwirq, int type, int ipl, int (*ih_fun)(void *),
    156     void *ih_arg)
    157 {
    158 	return intr_establish_xname(hwirq, type, ipl, ih_fun, ih_arg, NULL);
    159 }
    160 
    161 void *
    162 intr_establish_xname(int hwirq, int type, int ipl, int (*ih_fun)(void *),
    163     void *ih_arg, const char *xname)
    164 {
    165 	struct intrhand **p, *q, *ih;
    166 	struct pic_ops *pic;
    167 	static struct intrhand fakehand;
    168 	int maxipl = ipl;
    169 
    170 	if (maxipl == IPL_NONE)
    171 		maxipl = IPL_HIGH;
    172 
    173 	if (hwirq >= max_base) {
    174 		panic("%s: bogus IRQ %d, max is %d", __func__, hwirq,
    175 		    max_base - 1);
    176 	}
    177 
    178 	pic = find_pic_by_hwirq(hwirq);
    179 	if (pic == NULL) {
    180 		panic("%s: cannot find a pic for IRQ %d", __func__, hwirq);
    181 	}
    182 
    183 	const int virq = mapirq(hwirq);
    184 
    185 	/* no point in sleeping unless someone can free memory. */
    186 	ih = kmem_intr_alloc(sizeof(*ih), cold ? KM_NOSLEEP : KM_SLEEP);
    187 	if (ih == NULL)
    188 		panic("intr_establish: can't allocate handler info");
    189 
    190 	if (!PIC_VIRQ_LEGAL_P(virq) || type == IST_NONE)
    191 		panic("intr_establish: bogus irq (%d) or type (%d)",
    192 		    hwirq, type);
    193 
    194 	struct intr_source * const is = &intrsources[virq];
    195 	const bool cascaded = ih_fun == pic_handle_intr;
    196 
    197 	switch (is->is_type) {
    198 	case IST_NONE:
    199 		is->is_type = type;
    200 		is->is_cascaded = cascaded;
    201 		break;
    202 	case IST_EDGE_FALLING:
    203 	case IST_EDGE_RISING:
    204 	case IST_LEVEL_LOW:
    205 	case IST_LEVEL_HIGH:
    206 		if (type == is->is_type)
    207 			break;
    208 		/* FALLTHROUGH */
    209 	case IST_PULSE:
    210 		if (type != IST_NONE) {
    211 			panic("intr_establish: can't share %s with %s",
    212 			    intr_typename(is->is_type),
    213 			    intr_typename(type));
    214 		}
    215 		if (cascaded != is->is_cascaded) {
    216 			panic("intr_establish: can't share cascaded with "
    217 			    "non-cascaded interrupt");
    218 		}
    219 		break;
    220 	}
    221 	if (is->is_hand == NULL) {
    222 		snprintf(is->is_intrid, sizeof(is->is_intrid), "%s irq %d",
    223 		    pic->pic_name, is->is_hwirq);
    224 		snprintf(is->is_evname, sizeof(is->is_evname), "irq %d",
    225 		    is->is_hwirq);
    226 		evcnt_attach_dynamic(&is->is_ev, EVCNT_TYPE_INTR, NULL,
    227 		    pic->pic_name, is->is_evname);
    228 		snprintf(is->is_evmaskedname, sizeof(is->is_evmaskedname),
    229 		    "irq %d masked", is->is_hwirq);
    230 		evcnt_attach_dynamic(&is->is_evmasked, EVCNT_TYPE_INTR, NULL,
    231 		    pic->pic_name, is->is_evmaskedname);
    232 	}
    233 
    234 	/*
    235 	 * Figure out where to put the handler.
    236 	 * This is O(N^2), but we want to preserve the order, and N is
    237 	 * generally small.
    238 	 */
    239 	for (p = &is->is_hand; (q = *p) != NULL; p = &q->ih_next) {
    240 		maxipl = uimax(maxipl, q->ih_ipl);
    241 	}
    242 
    243 	/*
    244 	 * Actually install a fake handler momentarily, since we might be doing
    245 	 * this with interrupts enabled and don't want the real routine called
    246 	 * until masking is set up.
    247 	 */
    248 	fakehand.ih_ipl = ipl;
    249 	fakehand.ih_fun = fakeintr;
    250 	*p = &fakehand;
    251 
    252 	/*
    253 	 * Poke the real handler in now.
    254 	 */
    255 	ih->ih_fun = ih_fun;
    256 	ih->ih_arg = ih_arg;
    257 	ih->ih_next = NULL;
    258 	ih->ih_ipl = ipl;
    259 	ih->ih_virq = virq;
    260 	strlcpy(ih->ih_xname, xname != NULL ? xname : "unknown",
    261 	    sizeof(ih->ih_xname));
    262 	*p = ih;
    263 
    264 	if (pic->pic_establish_irq != NULL)
    265 		pic->pic_establish_irq(pic, hwirq - pic->pic_intrbase,
    266 		    is->is_type, maxipl);
    267 
    268 	/*
    269 	 * Remember the highest IPL used by this handler.
    270 	 */
    271 	is->is_ipl = maxipl;
    272 
    273 	/*
    274 	 * now that the handler is established we're actually ready to
    275 	 * calculate the masks
    276 	 */
    277 	intr_calculatemasks();
    278 
    279 	return ih;
    280 }
    281 
    282 void
    283 dummy_pic_establish_intr(struct pic_ops *pic, int irq, int type, int pri)
    284 {
    285 }
    286 
    287 /*
    288  * Deregister an interrupt handler.
    289  */
    290 void
    291 intr_disestablish(void *arg)
    292 {
    293 	struct intrhand * const ih = arg;
    294 	const int virq = ih->ih_virq;
    295 	struct intr_source * const is = &intrsources[virq];
    296 	struct intrhand **p, **q;
    297 	int maxipl = IPL_NONE;
    298 
    299 	if (!PIC_VIRQ_LEGAL_P(virq))
    300 		panic("intr_disestablish: bogus virq %d", virq);
    301 
    302 	/*
    303 	 * Remove the handler from the chain.
    304 	 * This is O(n^2), too.
    305 	 */
    306 	for (p = &is->is_hand, q = NULL; (*p) != NULL; p = &(*p)->ih_next) {
    307 		struct intrhand * const tmp_ih = *p;
    308 		if (tmp_ih == ih) {
    309 			q = p;
    310 		} else {
    311 			maxipl = uimax(maxipl, tmp_ih->ih_ipl);
    312 		}
    313 	}
    314 	if (q)
    315 		*q = ih->ih_next;
    316 	else
    317 		panic("intr_disestablish: handler not registered");
    318 	kmem_intr_free((void *)ih, sizeof(*ih));
    319 
    320 	/*
    321 	 * Reset the IPL for this source now that we've removed a handler.
    322 	 */
    323 	is->is_ipl = maxipl;
    324 
    325 	intr_calculatemasks();
    326 
    327 	if (is->is_hand == NULL) {
    328 		is->is_type = IST_NONE;
    329 		evcnt_detach(&is->is_ev);
    330 		evcnt_detach(&is->is_evmasked);
    331 		/*
    332 		 * Make the virtual IRQ available again.
    333 		 */
    334 		virq_map[virq] = 0;
    335 		virq_mask |= PIC_VIRQ_TO_MASK(virq);
    336 	}
    337 }
    338 
    339 /*
    340  * Map max_base irqs into 32 (bits).
    341  */
    342 static int
    343 mapirq(int hwirq)
    344 {
    345 	struct pic_ops *pic;
    346 
    347 	if (hwirq >= max_base)
    348 		panic("invalid irq %d", hwirq);
    349 
    350 	if ((pic = find_pic_by_hwirq(hwirq)) == NULL)
    351 		panic("%s: cannot find PIC for HWIRQ %d", __func__, hwirq);
    352 
    353 	if (virq_map[hwirq])
    354 		return virq_map[hwirq];
    355 
    356 	if (virq_mask == 0)
    357 		panic("virq overflow");
    358 
    359 	const int virq = PIC_VIRQ_MS_PENDING(virq_mask);
    360 	struct intr_source * const is = intrsources + virq;
    361 
    362 	virq_mask &= ~PIC_VIRQ_TO_MASK(virq);
    363 
    364 	is->is_hwirq = hwirq;
    365 	is->is_pic = pic;
    366 	virq_map[hwirq] = virq;
    367 #ifdef PIC_DEBUG
    368 	printf("mapping hwirq %d to virq %d\n", hwirq, virq);
    369 #endif
    370 	return virq;
    371 }
    372 
    373 static const char * const intr_typenames[] = {
    374    [IST_NONE]  = "none",
    375    [IST_PULSE] = "pulsed",
    376    [IST_EDGE_FALLING]  = "falling edge triggered",
    377    [IST_EDGE_RISING]  = "rising edge triggered",
    378    [IST_LEVEL_LOW] = "low level triggered",
    379    [IST_LEVEL_HIGH] = "high level triggered",
    380 };
    381 
    382 const char *
    383 intr_typename(int type)
    384 {
    385 	KASSERT((unsigned int) type < __arraycount(intr_typenames));
    386 	KASSERT(intr_typenames[type] != NULL);
    387 	return intr_typenames[type];
    388 }
    389 
    390 /*
    391  * Recalculate the interrupt masks from scratch.
    392  * We could code special registry and deregistry versions of this function that
    393  * would be faster, but the code would be nastier, and we don't expect this to
    394  * happen very much anyway.
    395  */
    396 static void
    397 intr_calculatemasks(void)
    398 {
    399 	imask_t newmask[NIPL];
    400 	struct intr_source *is;
    401 	struct intrhand *ih;
    402 	int irq;
    403 
    404 	for (u_int ipl = IPL_NONE; ipl < NIPL; ipl++) {
    405 		newmask[ipl] = 0;
    406 	}
    407 
    408 	/* First, figure out which ipl each IRQ uses. */
    409 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
    410 		for (ih = is->is_hand; ih != NULL; ih = ih->ih_next) {
    411 			newmask[ih->ih_ipl] |= PIC_VIRQ_TO_MASK(irq);
    412 		}
    413 	}
    414 
    415 	/*
    416 	 * IPL_NONE is used for hardware interrupts that are never blocked,
    417 	 * and do not block anything else.
    418 	 */
    419 	newmask[IPL_NONE] = 0;
    420 
    421 	/*
    422 	 * strict hierarchy - all IPLs block everything blocked by any lower
    423 	 * IPL
    424 	 */
    425 	for (u_int ipl = 1; ipl < NIPL; ipl++) {
    426 		newmask[ipl] |= newmask[ipl - 1];
    427 	}
    428 
    429 #ifdef PIC_DEBUG
    430 	for (u_int ipl = 0; ipl < NIPL; ipl++) {
    431 		printf("%u: %08x -> %08x\n", ipl, imask[ipl], newmask[ipl]);
    432 	}
    433 #endif
    434 
    435 	/*
    436 	 * Disable all interrupts.
    437 	 */
    438 	for (u_int base = 0; base < num_pics; base++) {
    439 		struct pic_ops * const pic = pics[base];
    440 		for (u_int i = 0; i < pic->pic_numintrs; i++) {
    441 			pic->pic_disable_irq(pic, i);
    442 		}
    443 	}
    444 
    445 	/*
    446 	 * Now that all interrupts are disabled, update the ipl masks.
    447 	 */
    448 	for (u_int ipl = 0; ipl < NIPL; ipl++) {
    449 		imask[ipl] = newmask[ipl];
    450 	}
    451 
    452 	/*
    453 	 * Lastly, enable IRQs actually in use.
    454 	 */
    455 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
    456 		if (is->is_hand)
    457 			pic_enable_irq(is->is_hwirq);
    458 	}
    459 }
    460 
    461 void
    462 pic_enable_irq(int hwirq)
    463 {
    464 	struct pic_ops * const pic = find_pic_by_hwirq(hwirq);
    465 	if (pic == NULL)
    466 		panic("%s: bogus IRQ %d", __func__, hwirq);
    467 	const int type = intrsources[virq_map[hwirq]].is_type;
    468 	(*pic->pic_enable_irq)(pic, hwirq - pic->pic_intrbase, type);
    469 }
    470 
    471 void
    472 pic_mark_pending(int hwirq)
    473 {
    474 	struct cpu_info * const ci = curcpu();
    475 
    476 	const int virq = virq_map[hwirq];
    477 	if (virq == 0)
    478 		printf("IRQ %d maps to 0\n", hwirq);
    479 
    480 	const register_t msr = mfmsr();
    481 	mtmsr(msr & ~PSL_EE);
    482 	ci->ci_ipending |= PIC_VIRQ_TO_MASK(virq);
    483 	mtmsr(msr);
    484 }
    485 
    486 static void
    487 intr_deliver(struct intr_source *is, int virq)
    488 {
    489 	bool locked = false;
    490 	for (struct intrhand *ih = is->is_hand; ih != NULL; ih = ih->ih_next) {
    491 		KASSERTMSG(ih->ih_fun != NULL,
    492 		    "%s: irq %d, hwirq %d, is %p ih %p: "
    493 		     "NULL interrupt handler!\n", __func__,
    494 		     virq, is->is_hwirq, is, ih);
    495 		if (ih->ih_ipl == IPL_VM) {
    496 			if (!locked) {
    497 				KERNEL_LOCK(1, NULL);
    498 				locked = true;
    499 			}
    500 		} else if (locked) {
    501 			KERNEL_UNLOCK_ONE(NULL);
    502 			locked = false;
    503 		}
    504 		(*ih->ih_fun)(ih->ih_arg);
    505 	}
    506 	if (locked) {
    507 		KERNEL_UNLOCK_ONE(NULL);
    508 	}
    509 	is->is_cpuindex = cpu_index(curcpu());
    510 	is->is_ev.ev_count++;
    511 }
    512 
    513 static inline bool
    514 pic_level_mask_p(const struct pic_ops *pic, const struct intr_source *is)
    515 {
    516 
    517 	return !is->is_cascaded &&
    518 	    (pic->pic_flags & PIC_FLAG_LEVEL_MASK) != 0 &&
    519 	    (is->is_type == IST_LEVEL || is->is_type == IST_LEVEL_HIGH);
    520 }
    521 
    522 void
    523 pic_do_pending_int(void)
    524 {
    525 	struct cpu_info * const ci = curcpu();
    526 	imask_t vpend;
    527 
    528 	if (ci->ci_iactive)
    529 		return;
    530 
    531 	ci->ci_iactive = 1;
    532 
    533 	const register_t emsr = mfmsr();
    534 	const register_t dmsr = emsr & ~PSL_EE;
    535 
    536 	KASSERT(emsr & PSL_EE);
    537 	mtmsr(dmsr);
    538 
    539 	const int pcpl = ci->ci_cpl;
    540 #ifdef __HAVE_FAST_SOFTINTS
    541 again:
    542 #endif
    543 
    544 	/* Do now unmasked pendings */
    545 	while ((vpend = (ci->ci_ipending & ~imask[pcpl])) != 0) {
    546 		ci->ci_idepth++;
    547 		KASSERT((PIC_VIRQ_TO_MASK(0) & ci->ci_ipending) == 0);
    548 
    549 		/* Get most significant pending bit */
    550 		const int virq = PIC_VIRQ_MS_PENDING(vpend);
    551 		ci->ci_ipending &= ~PIC_VIRQ_TO_MASK(virq);
    552 
    553 		struct intr_source * const is = &intrsources[virq];
    554 		struct pic_ops * const pic = is->is_pic;
    555 
    556 		if (!is->is_cascaded) {
    557 			splraise(is->is_ipl);
    558 			mtmsr(emsr);
    559 		}
    560 		intr_deliver(is, virq);
    561 		if (!is->is_cascaded) {
    562 			mtmsr(dmsr);
    563 			ci->ci_cpl = pcpl; /* Don't use splx... we are here already! */
    564 		}
    565 
    566 		const int picirq = is->is_hwirq - pic->pic_intrbase;
    567 		/*
    568 		 * Was acked while still asserted: ack now!
    569 		 */
    570 		if (pic_level_mask_p(pic, is))
    571 			pic->pic_ack_irq(pic, picirq);
    572 		pic->pic_reenable_irq(pic, picirq, is->is_type);
    573 		ci->ci_idepth--;
    574 	}
    575 
    576 #ifdef __HAVE_FAST_SOFTINTS
    577 	const u_int softints = ci->ci_data.cpu_softints &
    578 				 (IPL_SOFTMASK << pcpl);
    579 
    580 	/* make sure there are no bits to screw with the line above */
    581 	KASSERT((ci->ci_data.cpu_softints & ~IPL_SOFTMASK) == 0);
    582 
    583 	if (__predict_false(softints != 0)) {
    584 		ci->ci_cpl = IPL_HIGH;
    585 		mtmsr(emsr);
    586 		powerpc_softint(ci, pcpl,
    587 		    (vaddr_t)__builtin_return_address(0));
    588 		mtmsr(dmsr);
    589 		ci->ci_cpl = pcpl;
    590 		if (__predict_false(ci->ci_ipending & ~imask[pcpl]))
    591 			goto again;
    592 	}
    593 #endif
    594 
    595 	ci->ci_iactive = 0;
    596 	mtmsr(emsr);
    597 }
    598 
    599 int
    600 pic_handle_intr(void *cookie)
    601 {
    602 	struct pic_ops *pic = cookie;
    603 	struct cpu_info *ci = curcpu();
    604 	int picirq;
    605 
    606 	const register_t msr = mfmsr();
    607 	const int pcpl = ci->ci_cpl;
    608 
    609 	mtmsr(msr & ~PSL_EE);
    610 
    611 	picirq = pic->pic_get_irq(pic, PIC_GET_IRQ);
    612 	if (picirq == 255) {
    613 		mtmsr(msr);
    614 		return 0;
    615 	}
    616 
    617 	do {
    618 		const int virq = virq_map[picirq + pic->pic_intrbase];
    619 
    620 		KASSERT(virq != 0);
    621 		KASSERT(picirq < pic->pic_numintrs);
    622 		imask_t v_imen = PIC_VIRQ_TO_MASK(virq);
    623 		struct intr_source * const is = &intrsources[virq];
    624 		bool level_masked = false;
    625 
    626 		if ((imask[pcpl] & v_imen) != 0) {
    627 			ci->ci_ipending |= v_imen; /* Masked! Mark this as pending */
    628 			is->is_evmasked.ev_count++;
    629 			pic->pic_disable_irq(pic, picirq);
    630 		} else {
    631 			/* this interrupt is no longer pending */
    632 			ci->ci_ipending &= ~v_imen;
    633 			ci->ci_idepth++;
    634 
    635 			if (!is->is_cascaded) {
    636 				/*
    637 				 * Asserted until handler executes.
    638 				 */
    639 				if (pic_level_mask_p(pic, is)) {
    640 					pic->pic_disable_irq(pic, picirq);
    641 					level_masked = true;
    642 				}
    643 				splraise(is->is_ipl);
    644 				mtmsr(msr | PSL_EE);
    645 			}
    646 			intr_deliver(is, virq);
    647 			if (!is->is_cascaded) {
    648 				mtmsr(msr & ~PSL_EE);
    649 				ci->ci_cpl = pcpl;
    650 			}
    651 
    652 			ci->ci_data.cpu_nintr++;
    653 			ci->ci_idepth--;
    654 		}
    655 		pic->pic_ack_irq(pic, picirq);
    656 		if (level_masked)
    657 			pic->pic_reenable_irq(pic, picirq, is->is_type);
    658 	} while ((picirq = pic->pic_get_irq(pic, PIC_GET_RECHECK)) != 255);
    659 
    660 	mtmsr(msr | PSL_EE);
    661 	splx(pcpl);	/* Process pendings. */
    662 	mtmsr(msr);
    663 
    664 	return 0;
    665 }
    666 
    667 void
    668 pic_ext_intr(void)
    669 {
    670 
    671 	KASSERT(pics[primary_pic] != NULL);
    672 	pic_handle_intr(pics[primary_pic]);
    673 
    674 	return;
    675 
    676 }
    677 
    678 int
    679 splraise(int ncpl)
    680 {
    681 	struct cpu_info *ci = curcpu();
    682 	int ocpl;
    683 
    684 	if (ncpl == ci->ci_cpl)
    685 		return ncpl;
    686 	REORDER_PROTECT();
    687 	ocpl = ci->ci_cpl;
    688 	KASSERT(ncpl < NIPL);
    689 	ci->ci_cpl = uimax(ncpl, ocpl);
    690 	REORDER_PROTECT();
    691 	__insn_barrier();
    692 	return ocpl;
    693 }
    694 
    695 static inline bool
    696 have_pending_intr_p(struct cpu_info *ci, int ncpl)
    697 {
    698 	if (ci->ci_ipending & ~imask[ncpl])
    699 		return true;
    700 #ifdef __HAVE_FAST_SOFTINTS
    701 	if (ci->ci_data.cpu_softints & (IPL_SOFTMASK << ncpl))
    702 		return true;
    703 #endif
    704 	return false;
    705 }
    706 
    707 void
    708 splx(int ncpl)
    709 {
    710 	struct cpu_info *ci = curcpu();
    711 
    712 	__insn_barrier();
    713 	REORDER_PROTECT();
    714 	ci->ci_cpl = ncpl;
    715 	if (have_pending_intr_p(ci, ncpl))
    716 		pic_do_pending_int();
    717 
    718 	REORDER_PROTECT();
    719 }
    720 
    721 int
    722 spllower(int ncpl)
    723 {
    724 	struct cpu_info *ci = curcpu();
    725 	int ocpl;
    726 
    727 	__insn_barrier();
    728 	REORDER_PROTECT();
    729 	ocpl = ci->ci_cpl;
    730 	ci->ci_cpl = ncpl;
    731 	if (have_pending_intr_p(ci, ncpl))
    732 		pic_do_pending_int();
    733 	REORDER_PROTECT();
    734 	return ocpl;
    735 }
    736 
    737 void
    738 genppc_cpu_configure(void)
    739 {
    740 	aprint_normal("vmmask %x schedmask %x highmask %x\n",
    741 	    (u_int)imask[IPL_VM] & 0x7fffffff,
    742 	    (u_int)imask[IPL_SCHED] & 0x7fffffff,
    743 	    (u_int)imask[IPL_HIGH] & 0x7fffffff);
    744 
    745 	spl0();
    746 }
    747 
    748 #if defined(PIC_PREPIVR) || defined(PIC_I8259)
    749 /*
    750  * isa_intr_alloc needs to be done here, because it needs direct access to
    751  * the various interrupt handler structures.
    752  */
    753 
    754 int
    755 genppc_isa_intr_alloc(isa_chipset_tag_t ic, struct pic_ops *pic,
    756     int mask, int type, int *irq_p)
    757 {
    758 	int irq, vi;
    759 	int maybe_irq = -1;
    760 	int shared_depth = 0;
    761 	struct intr_source *is;
    762 
    763 	if (pic == NULL)
    764 		return 1;
    765 
    766 	for (irq = 0; (mask != 0 && irq < pic->pic_numintrs);
    767 	     mask >>= 1, irq++) {
    768 		if ((mask & 1) == 0)
    769 			continue;
    770 		vi = virq_map[irq + pic->pic_intrbase];
    771 		if (!vi) {
    772 			*irq_p = irq;
    773 			return 0;
    774 		}
    775 		is = &intrsources[vi];
    776 		if (is->is_type == IST_NONE) {
    777 			*irq_p = irq;
    778 			return 0;
    779 		}
    780 		/* Level interrupts can be shared */
    781 		if (type == IST_LEVEL && is->is_type == IST_LEVEL) {
    782 			struct intrhand *ih = is->is_hand;
    783 			int depth;
    784 
    785 			if (maybe_irq == -1) {
    786 				maybe_irq = irq;
    787 				continue;
    788 			}
    789 			for (depth = 0; ih != NULL; ih = ih->ih_next)
    790 				depth++;
    791 			if (depth < shared_depth) {
    792 				maybe_irq = irq;
    793 				shared_depth = depth;
    794 			}
    795 		}
    796 	}
    797 	if (maybe_irq != -1) {
    798 		*irq_p = maybe_irq;
    799 		return 0;
    800 	}
    801 	return 1;
    802 }
    803 #endif
    804 
    805 static struct intr_source *
    806 intr_get_source(const char *intrid)
    807 {
    808 	struct intr_source *is;
    809 	int irq;
    810 
    811 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
    812 		if (strcmp(intrid, is->is_intrid) == 0)
    813 			return is;
    814 	}
    815 	return NULL;
    816 }
    817 
    818 static struct intrhand *
    819 intr_get_handler(const char *intrid)
    820 {
    821 	struct intr_source *is;
    822 
    823 	is = intr_get_source(intrid);
    824 	if (is != NULL)
    825 		return is->is_hand;
    826 	return NULL;
    827 }
    828 
    829 uint64_t
    830 interrupt_get_count(const char *intrid, u_int cpu_idx)
    831 {
    832 	struct intr_source *is;
    833 
    834 	is = intr_get_source(intrid);
    835 	if (is != NULL && is->is_cpuindex == cpu_idx) {
    836 		return is->is_ev.ev_count;
    837 	}
    838 
    839 	return 0;
    840 }
    841 
    842 void
    843 interrupt_get_assigned(const char *intrid, kcpuset_t *cpuset)
    844 {
    845 	struct intr_source *is;
    846 
    847 	kcpuset_zero(cpuset);
    848 
    849 	is = intr_get_source(intrid);
    850 	if (is != NULL)
    851 		kcpuset_set(cpuset, is->is_cpuindex);
    852 }
    853 
    854 void
    855 interrupt_get_available(kcpuset_t *cpuset)
    856 {
    857 	CPU_INFO_ITERATOR cii;
    858 	struct cpu_info *ci;
    859 
    860 	kcpuset_zero(cpuset);
    861 
    862 	mutex_enter(&cpu_lock);
    863 	for (CPU_INFO_FOREACH(cii, ci)) {
    864 		if ((ci->ci_schedstate.spc_flags & SPCF_NOINTR) == 0)
    865 			kcpuset_set(cpuset, cpu_index(ci));
    866 	}
    867 	mutex_exit(&cpu_lock);
    868 }
    869 
    870 void
    871 interrupt_get_devname(const char *intrid, char *buf, size_t len)
    872 {
    873 	struct intrhand *ih;
    874 
    875 	if (len == 0)
    876 		return;
    877 
    878 	buf[0] = '\0';
    879 
    880 	for (ih = intr_get_handler(intrid); ih != NULL; ih = ih->ih_next) {
    881 		if (buf[0] != '\0')
    882 			strlcat(buf, ", ", len);
    883 		strlcat(buf, ih->ih_xname, len);
    884 	}
    885 }
    886 
    887 struct intrids_handler *
    888 interrupt_construct_intrids(const kcpuset_t *cpuset)
    889 {
    890 	struct intr_source *is;
    891 	struct intrids_handler *ii_handler;
    892 	intrid_t *ids;
    893 	int i, irq, count;
    894 
    895 	if (kcpuset_iszero(cpuset))
    896 		return NULL;
    897 	if (!kcpuset_isset(cpuset, 0))	/* XXX */
    898 		return NULL;
    899 
    900 	count = 0;
    901 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
    902 		if (is->is_hand != NULL)
    903 			count++;
    904 	}
    905 
    906 	ii_handler = kmem_zalloc(sizeof(int) + sizeof(intrid_t) * count,
    907 	    KM_SLEEP);
    908 	if (ii_handler == NULL)
    909 		return NULL;
    910 	ii_handler->iih_nids = count;
    911 	if (count == 0)
    912 		return ii_handler;
    913 
    914 	ids = ii_handler->iih_intrids;
    915 	i = 0;
    916 	for (irq = 0, is = intrsources; irq < NVIRQ; irq++, is++) {
    917 		/* Ignore devices attached after counting "count". */
    918 		if (i >= count)
    919 			break;
    920 
    921 		if (is->is_hand == NULL)
    922 			continue;
    923 
    924 		strncpy(ids[i], is->is_intrid, sizeof(intrid_t));
    925 		i++;
    926 	}
    927 
    928 	return ii_handler;
    929 }
    930 
    931 void
    932 interrupt_destruct_intrids(struct intrids_handler *ii_handler)
    933 {
    934 	size_t iih_size;
    935 
    936 	if (ii_handler == NULL)
    937 		return;
    938 
    939 	iih_size = sizeof(int) + sizeof(intrid_t) * ii_handler->iih_nids;
    940 	kmem_free(ii_handler, iih_size);
    941 }
    942 
    943 int
    944 interrupt_distribute(void *ich, const kcpuset_t *newset, kcpuset_t *oldset)
    945 {
    946 	return EOPNOTSUPP;
    947 }
    948 
    949 int
    950 interrupt_distribute_handler(const char *intrid, const kcpuset_t *newset,
    951     kcpuset_t *oldset)
    952 {
    953 	return EOPNOTSUPP;
    954 }
    955 
    956 #undef REORDER_PROTECT
    957