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