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