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