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