1 /*- 2 * Copyright (c) 2012-2014 Jakub Wojciech Klama <jceel@FreeBSD.org>. 3 * Copyright (c) 2015 Svatopluk Kraus 4 * Copyright (c) 2015 Michal Meloun 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 AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 * 28 * $FreeBSD$ 29 */ 30 31 #include <sys/cdefs.h> 32 __FBSDID("$FreeBSD$"); 33 34 /* 35 * New-style Interrupt Framework 36 * 37 * TODO: - to support IPI (PPI) enabling on other CPUs if already started 38 * - to complete things for removable PICs 39 */ 40 41 #include "opt_ddb.h" 42 #include "opt_platform.h" 43 44 #include <sys/param.h> 45 #include <sys/systm.h> 46 #include <sys/kernel.h> 47 #include <sys/syslog.h> 48 #include <sys/malloc.h> 49 #include <sys/proc.h> 50 #include <sys/queue.h> 51 #include <sys/bus.h> 52 #include <sys/interrupt.h> 53 #include <sys/conf.h> 54 #include <sys/cpuset.h> 55 #include <sys/sched.h> 56 #include <sys/smp.h> 57 #include <machine/atomic.h> 58 #include <machine/intr.h> 59 #include <machine/cpu.h> 60 #include <machine/smp.h> 61 #include <machine/stdarg.h> 62 63 #ifdef FDT 64 #include <dev/ofw/openfirm.h> 65 #include <dev/ofw/ofw_bus.h> 66 #include <dev/ofw/ofw_bus_subr.h> 67 #endif 68 69 #ifdef DDB 70 #include <ddb/ddb.h> 71 #endif 72 73 #include "pic_if.h" 74 75 #define INTRNAME_LEN (2*MAXCOMLEN + 1) 76 77 #ifdef DEBUG 78 #define debugf(fmt, args...) do { printf("%s(): ", __func__); \ 79 printf(fmt,##args); } while (0) 80 #else 81 #define debugf(fmt, args...) 82 #endif 83 84 MALLOC_DECLARE(M_INTRNG); 85 MALLOC_DEFINE(M_INTRNG, "intr", "intr interrupt handling"); 86 87 /* Main interrupt handler called from assembler -> 'hidden' for C code. */ 88 void intr_irq_handler(struct trapframe *tf); 89 90 /* Root interrupt controller stuff. */ 91 static struct intr_irqsrc *irq_root_isrc; 92 device_t intr_irq_root_dev; 93 static intr_irq_filter_t *irq_root_filter; 94 static void *irq_root_arg; 95 static u_int irq_root_ipicount; 96 97 /* Interrupt controller definition. */ 98 struct intr_pic { 99 SLIST_ENTRY(intr_pic) pic_next; 100 intptr_t pic_xref; /* hardware identification */ 101 device_t pic_dev; 102 }; 103 104 static struct mtx pic_list_lock; 105 static SLIST_HEAD(, intr_pic) pic_list; 106 107 static struct intr_pic *pic_lookup(device_t dev, intptr_t xref); 108 109 /* Interrupt source definition. */ 110 static struct mtx isrc_table_lock; 111 static struct intr_irqsrc *irq_sources[NIRQ]; 112 u_int irq_next_free; 113 114 #define IRQ_INVALID nitems(irq_sources) 115 116 #ifdef SMP 117 static boolean_t irq_assign_cpu = FALSE; 118 #endif 119 120 /* 121 * - 2 counters for each I/O interrupt. 122 * - MAXCPU counters for each IPI counters for SMP. 123 */ 124 #ifdef SMP 125 #define INTRCNT_COUNT (NIRQ * 2 + INTR_IPI_COUNT * MAXCPU) 126 #else 127 #define INTRCNT_COUNT (NIRQ * 2) 128 #endif 129 130 /* Data for MI statistics reporting. */ 131 u_long intrcnt[INTRCNT_COUNT]; 132 char intrnames[INTRCNT_COUNT * INTRNAME_LEN]; 133 size_t sintrcnt = sizeof(intrcnt); 134 size_t sintrnames = sizeof(intrnames); 135 static u_int intrcnt_index; 136 137 /* 138 * Interrupt framework initialization routine. 139 */ 140 static void 141 intr_irq_init(void *dummy __unused) 142 { 143 144 SLIST_INIT(&pic_list); 145 mtx_init(&pic_list_lock, "intr pic list", NULL, MTX_DEF); 146 mtx_init(&isrc_table_lock, "intr isrc table", NULL, MTX_DEF); 147 } 148 SYSINIT(intr_irq_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_irq_init, NULL); 149 150 static void 151 intrcnt_setname(const char *name, int index) 152 { 153 154 snprintf(intrnames + INTRNAME_LEN * index, INTRNAME_LEN, "%-*s", 155 INTRNAME_LEN - 1, name); 156 } 157 158 /* 159 * Update name for interrupt source with interrupt event. 160 */ 161 static void 162 intrcnt_updatename(struct intr_irqsrc *isrc) 163 { 164 165 /* QQQ: What about stray counter name? */ 166 mtx_assert(&isrc_table_lock, MA_OWNED); 167 intrcnt_setname(isrc->isrc_event->ie_fullname, isrc->isrc_index); 168 } 169 170 /* 171 * Virtualization for interrupt source interrupt counter increment. 172 */ 173 static inline void 174 isrc_increment_count(struct intr_irqsrc *isrc) 175 { 176 177 /* 178 * XXX - It should be atomic for PPI interrupts. It was proven that 179 * the lost is measurable easily for timer PPI interrupts. 180 */ 181 isrc->isrc_count[0]++; 182 /*atomic_add_long(&isrc->isrc_count[0], 1);*/ 183 } 184 185 /* 186 * Virtualization for interrupt source interrupt stray counter increment. 187 */ 188 static inline void 189 isrc_increment_straycount(struct intr_irqsrc *isrc) 190 { 191 192 isrc->isrc_count[1]++; 193 } 194 195 /* 196 * Virtualization for interrupt source interrupt name update. 197 */ 198 static void 199 isrc_update_name(struct intr_irqsrc *isrc, const char *name) 200 { 201 char str[INTRNAME_LEN]; 202 203 mtx_assert(&isrc_table_lock, MA_OWNED); 204 205 if (name != NULL) { 206 snprintf(str, INTRNAME_LEN, "%s: %s", isrc->isrc_name, name); 207 intrcnt_setname(str, isrc->isrc_index); 208 snprintf(str, INTRNAME_LEN, "stray %s: %s", isrc->isrc_name, 209 name); 210 intrcnt_setname(str, isrc->isrc_index + 1); 211 } else { 212 snprintf(str, INTRNAME_LEN, "%s:", isrc->isrc_name); 213 intrcnt_setname(str, isrc->isrc_index); 214 snprintf(str, INTRNAME_LEN, "stray %s:", isrc->isrc_name); 215 intrcnt_setname(str, isrc->isrc_index + 1); 216 } 217 } 218 219 /* 220 * Virtualization for interrupt source interrupt counters setup. 221 */ 222 static void 223 isrc_setup_counters(struct intr_irqsrc *isrc) 224 { 225 u_int index; 226 227 /* 228 * XXX - it does not work well with removable controllers and 229 * interrupt sources !!! 230 */ 231 index = atomic_fetchadd_int(&intrcnt_index, 2); 232 isrc->isrc_index = index; 233 isrc->isrc_count = &intrcnt[index]; 234 isrc_update_name(isrc, NULL); 235 } 236 237 #ifdef SMP 238 /* 239 * Virtualization for interrupt source IPI counters setup. 240 */ 241 u_long * 242 intr_ipi_setup_counters(const char *name) 243 { 244 u_int index, i; 245 char str[INTRNAME_LEN]; 246 247 index = atomic_fetchadd_int(&intrcnt_index, MAXCPU); 248 for (i = 0; i < MAXCPU; i++) { 249 snprintf(str, INTRNAME_LEN, "cpu%d:%s", i, name); 250 intrcnt_setname(str, index + i); 251 } 252 return (&intrcnt[index]); 253 } 254 #endif 255 256 /* 257 * Main interrupt dispatch handler. It's called straight 258 * from the assembler, where CPU interrupt is served. 259 */ 260 void 261 intr_irq_handler(struct trapframe *tf) 262 { 263 struct trapframe * oldframe; 264 struct thread * td; 265 266 KASSERT(irq_root_filter != NULL, ("%s: no filter", __func__)); 267 268 PCPU_INC(cnt.v_intr); 269 critical_enter(); 270 td = curthread; 271 oldframe = td->td_intr_frame; 272 td->td_intr_frame = tf; 273 irq_root_filter(irq_root_arg); 274 td->td_intr_frame = oldframe; 275 critical_exit(); 276 } 277 278 /* 279 * interrupt controller dispatch function for interrupts. It should 280 * be called straight from the interrupt controller, when associated interrupt 281 * source is learned. 282 */ 283 void 284 intr_irq_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf) 285 { 286 287 KASSERT(isrc != NULL, ("%s: no source", __func__)); 288 289 isrc_increment_count(isrc); 290 291 #ifdef INTR_SOLO 292 if (isrc->isrc_filter != NULL) { 293 int error; 294 error = isrc->isrc_filter(isrc->isrc_arg, tf); 295 PIC_POST_FILTER(isrc->isrc_dev, isrc); 296 if (error == FILTER_HANDLED) 297 return; 298 } else 299 #endif 300 if (isrc->isrc_event != NULL) { 301 if (intr_event_handle(isrc->isrc_event, tf) == 0) 302 return; 303 } 304 305 isrc_increment_straycount(isrc); 306 PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc); 307 308 device_printf(isrc->isrc_dev, "stray irq <%s> disabled", 309 isrc->isrc_name); 310 } 311 312 /* 313 * Allocate interrupt source. 314 */ 315 static struct intr_irqsrc * 316 isrc_alloc(u_int type, u_int extsize) 317 { 318 struct intr_irqsrc *isrc; 319 320 isrc = malloc(sizeof(*isrc) + extsize, M_INTRNG, M_WAITOK | M_ZERO); 321 isrc->isrc_irq = IRQ_INVALID; /* just to be safe */ 322 isrc->isrc_type = type; 323 isrc->isrc_nspc_type = INTR_IRQ_NSPC_NONE; 324 isrc->isrc_trig = INTR_TRIGGER_CONFORM; 325 isrc->isrc_pol = INTR_POLARITY_CONFORM; 326 CPU_ZERO(&isrc->isrc_cpu); 327 return (isrc); 328 } 329 330 /* 331 * Free interrupt source. 332 */ 333 static void 334 isrc_free(struct intr_irqsrc *isrc) 335 { 336 337 free(isrc, M_INTRNG); 338 } 339 340 void 341 intr_irq_set_name(struct intr_irqsrc *isrc, const char *fmt, ...) 342 { 343 va_list ap; 344 345 va_start(ap, fmt); 346 vsnprintf(isrc->isrc_name, INTR_ISRC_NAMELEN, fmt, ap); 347 va_end(ap); 348 } 349 350 /* 351 * Alloc unique interrupt number (resource handle) for interrupt source. 352 * 353 * There could be various strategies how to allocate free interrupt number 354 * (resource handle) for new interrupt source. 355 * 356 * 1. Handles are always allocated forward, so handles are not recycled 357 * immediately. However, if only one free handle left which is reused 358 * constantly... 359 */ 360 static int 361 isrc_alloc_irq_locked(struct intr_irqsrc *isrc) 362 { 363 u_int maxirqs, irq; 364 365 mtx_assert(&isrc_table_lock, MA_OWNED); 366 367 maxirqs = nitems(irq_sources); 368 if (irq_next_free >= maxirqs) 369 return (ENOSPC); 370 371 for (irq = irq_next_free; irq < maxirqs; irq++) { 372 if (irq_sources[irq] == NULL) 373 goto found; 374 } 375 for (irq = 0; irq < irq_next_free; irq++) { 376 if (irq_sources[irq] == NULL) 377 goto found; 378 } 379 380 irq_next_free = maxirqs; 381 return (ENOSPC); 382 383 found: 384 isrc->isrc_irq = irq; 385 irq_sources[irq] = isrc; 386 387 intr_irq_set_name(isrc, "irq%u", irq); 388 isrc_setup_counters(isrc); 389 390 irq_next_free = irq + 1; 391 if (irq_next_free >= maxirqs) 392 irq_next_free = 0; 393 return (0); 394 } 395 #ifdef notyet 396 /* 397 * Free unique interrupt number (resource handle) from interrupt source. 398 */ 399 static int 400 isrc_free_irq(struct intr_irqsrc *isrc) 401 { 402 u_int maxirqs; 403 404 mtx_assert(&isrc_table_lock, MA_NOTOWNED); 405 406 maxirqs = nitems(irq_sources); 407 if (isrc->isrc_irq >= maxirqs) 408 return (EINVAL); 409 410 mtx_lock(&isrc_table_lock); 411 if (irq_sources[isrc->isrc_irq] != isrc) { 412 mtx_unlock(&isrc_table_lock); 413 return (EINVAL); 414 } 415 416 irq_sources[isrc->isrc_irq] = NULL; 417 isrc->isrc_irq = IRQ_INVALID; /* just to be safe */ 418 mtx_unlock(&isrc_table_lock); 419 420 return (0); 421 } 422 #endif 423 /* 424 * Lookup interrupt source by interrupt number (resource handle). 425 */ 426 static struct intr_irqsrc * 427 isrc_lookup(u_int irq) 428 { 429 430 if (irq < nitems(irq_sources)) 431 return (irq_sources[irq]); 432 return (NULL); 433 } 434 435 /* 436 * Lookup interrupt source by namespace description. 437 */ 438 static struct intr_irqsrc * 439 isrc_namespace_lookup(device_t dev, uint16_t type, uint16_t num) 440 { 441 u_int irq; 442 struct intr_irqsrc *isrc; 443 444 mtx_assert(&isrc_table_lock, MA_OWNED); 445 446 for (irq = 0; irq < nitems(irq_sources); irq++) { 447 isrc = irq_sources[irq]; 448 if (isrc != NULL && isrc->isrc_dev == dev && 449 isrc->isrc_nspc_type == type && isrc->isrc_nspc_num == num) 450 return (isrc); 451 } 452 return (NULL); 453 } 454 455 /* 456 * Map interrupt source according to namespace into framework. If such mapping 457 * does not exist, create it. Return unique interrupt number (resource handle) 458 * associated with mapped interrupt source. 459 */ 460 u_int 461 intr_namespace_map_irq(device_t dev, uint16_t type, uint16_t num) 462 { 463 struct intr_irqsrc *isrc, *new_isrc; 464 int error; 465 466 new_isrc = isrc_alloc(INTR_ISRCT_NAMESPACE, 0); 467 468 mtx_lock(&isrc_table_lock); 469 isrc = isrc_namespace_lookup(dev, type, num); 470 if (isrc != NULL) { 471 mtx_unlock(&isrc_table_lock); 472 isrc_free(new_isrc); 473 return (isrc->isrc_irq); /* already mapped */ 474 } 475 476 error = isrc_alloc_irq_locked(new_isrc); 477 if (error != 0) { 478 mtx_unlock(&isrc_table_lock); 479 isrc_free(new_isrc); 480 return (IRQ_INVALID); /* no space left */ 481 } 482 483 new_isrc->isrc_dev = dev; 484 new_isrc->isrc_nspc_type = type; 485 new_isrc->isrc_nspc_num = num; 486 mtx_unlock(&isrc_table_lock); 487 488 return (new_isrc->isrc_irq); 489 } 490 491 #ifdef FDT 492 /* 493 * Lookup interrupt source by FDT description. 494 */ 495 static struct intr_irqsrc * 496 isrc_fdt_lookup(intptr_t xref, pcell_t *cells, u_int ncells) 497 { 498 u_int irq, cellsize; 499 struct intr_irqsrc *isrc; 500 501 mtx_assert(&isrc_table_lock, MA_OWNED); 502 503 cellsize = ncells * sizeof(*cells); 504 for (irq = 0; irq < nitems(irq_sources); irq++) { 505 isrc = irq_sources[irq]; 506 if (isrc != NULL && isrc->isrc_type == INTR_ISRCT_FDT && 507 isrc->isrc_xref == xref && isrc->isrc_ncells == ncells && 508 memcmp(isrc->isrc_cells, cells, cellsize) == 0) 509 return (isrc); 510 } 511 return (NULL); 512 } 513 514 /* 515 * Map interrupt source according to FDT data into framework. If such mapping 516 * does not exist, create it. Return unique interrupt number (resource handle) 517 * associated with mapped interrupt source. 518 */ 519 u_int 520 intr_fdt_map_irq(phandle_t node, pcell_t *cells, u_int ncells) 521 { 522 struct intr_irqsrc *isrc, *new_isrc; 523 u_int cellsize; 524 intptr_t xref; 525 int error; 526 527 xref = (intptr_t)node; /* It's so simple for now. */ 528 529 cellsize = ncells * sizeof(*cells); 530 new_isrc = isrc_alloc(INTR_ISRCT_FDT, cellsize); 531 532 mtx_lock(&isrc_table_lock); 533 isrc = isrc_fdt_lookup(xref, cells, ncells); 534 if (isrc != NULL) { 535 mtx_unlock(&isrc_table_lock); 536 isrc_free(new_isrc); 537 return (isrc->isrc_irq); /* already mapped */ 538 } 539 540 error = isrc_alloc_irq_locked(new_isrc); 541 if (error != 0) { 542 mtx_unlock(&isrc_table_lock); 543 isrc_free(new_isrc); 544 return (IRQ_INVALID); /* no space left */ 545 } 546 547 new_isrc->isrc_xref = xref; 548 new_isrc->isrc_ncells = ncells; 549 memcpy(new_isrc->isrc_cells, cells, cellsize); 550 mtx_unlock(&isrc_table_lock); 551 552 return (new_isrc->isrc_irq); 553 } 554 #endif 555 556 /* 557 * Register interrupt source into interrupt controller. 558 */ 559 static int 560 isrc_register(struct intr_irqsrc *isrc) 561 { 562 struct intr_pic *pic; 563 boolean_t is_percpu; 564 int error; 565 566 if (isrc->isrc_flags & INTR_ISRCF_REGISTERED) 567 return (0); 568 569 if (isrc->isrc_dev == NULL) { 570 pic = pic_lookup(NULL, isrc->isrc_xref); 571 if (pic == NULL || pic->pic_dev == NULL) 572 return (ESRCH); 573 isrc->isrc_dev = pic->pic_dev; 574 } 575 576 error = PIC_REGISTER(isrc->isrc_dev, isrc, &is_percpu); 577 if (error != 0) 578 return (error); 579 580 mtx_lock(&isrc_table_lock); 581 isrc->isrc_flags |= INTR_ISRCF_REGISTERED; 582 if (is_percpu) 583 isrc->isrc_flags |= INTR_ISRCF_PERCPU; 584 isrc_update_name(isrc, NULL); 585 mtx_unlock(&isrc_table_lock); 586 return (0); 587 } 588 589 #ifdef INTR_SOLO 590 /* 591 * Setup filter into interrupt source. 592 */ 593 static int 594 iscr_setup_filter(struct intr_irqsrc *isrc, const char *name, 595 intr_irq_filter_t *filter, void *arg, void **cookiep) 596 { 597 598 if (filter == NULL) 599 return (EINVAL); 600 601 mtx_lock(&isrc_table_lock); 602 /* 603 * Make sure that we do not mix the two ways 604 * how we handle interrupt sources. 605 */ 606 if (isrc->isrc_filter != NULL || isrc->isrc_event != NULL) { 607 mtx_unlock(&isrc_table_lock); 608 return (EBUSY); 609 } 610 isrc->isrc_filter = filter; 611 isrc->isrc_arg = arg; 612 isrc_update_name(isrc, name); 613 mtx_unlock(&isrc_table_lock); 614 615 *cookiep = isrc; 616 return (0); 617 } 618 #endif 619 620 /* 621 * Interrupt source pre_ithread method for MI interrupt framework. 622 */ 623 static void 624 intr_isrc_pre_ithread(void *arg) 625 { 626 struct intr_irqsrc *isrc = arg; 627 628 PIC_PRE_ITHREAD(isrc->isrc_dev, isrc); 629 } 630 631 /* 632 * Interrupt source post_ithread method for MI interrupt framework. 633 */ 634 static void 635 intr_isrc_post_ithread(void *arg) 636 { 637 struct intr_irqsrc *isrc = arg; 638 639 PIC_POST_ITHREAD(isrc->isrc_dev, isrc); 640 } 641 642 /* 643 * Interrupt source post_filter method for MI interrupt framework. 644 */ 645 static void 646 intr_isrc_post_filter(void *arg) 647 { 648 struct intr_irqsrc *isrc = arg; 649 650 PIC_POST_FILTER(isrc->isrc_dev, isrc); 651 } 652 653 /* 654 * Interrupt source assign_cpu method for MI interrupt framework. 655 */ 656 static int 657 intr_isrc_assign_cpu(void *arg, int cpu) 658 { 659 #ifdef SMP 660 struct intr_irqsrc *isrc = arg; 661 int error; 662 663 if (isrc->isrc_dev != intr_irq_root_dev) 664 return (EINVAL); 665 666 mtx_lock(&isrc_table_lock); 667 if (cpu == NOCPU) { 668 CPU_ZERO(&isrc->isrc_cpu); 669 isrc->isrc_flags &= ~INTR_ISRCF_BOUND; 670 } else { 671 CPU_SETOF(cpu, &isrc->isrc_cpu); 672 isrc->isrc_flags |= INTR_ISRCF_BOUND; 673 } 674 675 /* 676 * In NOCPU case, it's up to PIC to either leave ISRC on same CPU or 677 * re-balance it to another CPU or enable it on more CPUs. However, 678 * PIC is expected to change isrc_cpu appropriately to keep us well 679 * informed if the call is successfull. 680 */ 681 if (irq_assign_cpu) { 682 error = PIC_BIND(isrc->isrc_dev, isrc); 683 if (error) { 684 CPU_ZERO(&isrc->isrc_cpu); 685 mtx_unlock(&isrc_table_lock); 686 return (error); 687 } 688 } 689 mtx_unlock(&isrc_table_lock); 690 return (0); 691 #else 692 return (EOPNOTSUPP); 693 #endif 694 } 695 696 /* 697 * Create interrupt event for interrupt source. 698 */ 699 static int 700 isrc_event_create(struct intr_irqsrc *isrc) 701 { 702 struct intr_event *ie; 703 int error; 704 705 error = intr_event_create(&ie, isrc, 0, isrc->isrc_irq, 706 intr_isrc_pre_ithread, intr_isrc_post_ithread, intr_isrc_post_filter, 707 intr_isrc_assign_cpu, "%s:", isrc->isrc_name); 708 if (error) 709 return (error); 710 711 mtx_lock(&isrc_table_lock); 712 /* 713 * Make sure that we do not mix the two ways 714 * how we handle interrupt sources. Let contested event wins. 715 */ 716 if (isrc->isrc_filter != NULL || isrc->isrc_event != NULL) { 717 mtx_unlock(&isrc_table_lock); 718 intr_event_destroy(ie); 719 return (isrc->isrc_event != NULL ? EBUSY : 0); 720 } 721 isrc->isrc_event = ie; 722 mtx_unlock(&isrc_table_lock); 723 724 return (0); 725 } 726 #ifdef notyet 727 /* 728 * Destroy interrupt event for interrupt source. 729 */ 730 static void 731 isrc_event_destroy(struct intr_irqsrc *isrc) 732 { 733 struct intr_event *ie; 734 735 mtx_lock(&isrc_table_lock); 736 ie = isrc->isrc_event; 737 isrc->isrc_event = NULL; 738 mtx_unlock(&isrc_table_lock); 739 740 if (ie != NULL) 741 intr_event_destroy(ie); 742 } 743 #endif 744 /* 745 * Add handler to interrupt source. 746 */ 747 static int 748 isrc_add_handler(struct intr_irqsrc *isrc, const char *name, 749 driver_filter_t filter, driver_intr_t handler, void *arg, 750 enum intr_type flags, void **cookiep) 751 { 752 int error; 753 754 if (isrc->isrc_event == NULL) { 755 error = isrc_event_create(isrc); 756 if (error) 757 return (error); 758 } 759 760 error = intr_event_add_handler(isrc->isrc_event, name, filter, handler, 761 arg, intr_priority(flags), flags, cookiep); 762 if (error == 0) { 763 mtx_lock(&isrc_table_lock); 764 intrcnt_updatename(isrc); 765 mtx_unlock(&isrc_table_lock); 766 } 767 768 return (error); 769 } 770 771 /* 772 * Lookup interrupt controller locked. 773 */ 774 static struct intr_pic * 775 pic_lookup_locked(device_t dev, intptr_t xref) 776 { 777 struct intr_pic *pic; 778 779 mtx_assert(&pic_list_lock, MA_OWNED); 780 781 SLIST_FOREACH(pic, &pic_list, pic_next) { 782 if (pic->pic_xref != xref) 783 continue; 784 if (pic->pic_xref != 0 || pic->pic_dev == dev) 785 return (pic); 786 } 787 return (NULL); 788 } 789 790 /* 791 * Lookup interrupt controller. 792 */ 793 static struct intr_pic * 794 pic_lookup(device_t dev, intptr_t xref) 795 { 796 struct intr_pic *pic; 797 798 mtx_lock(&pic_list_lock); 799 pic = pic_lookup_locked(dev, xref); 800 mtx_unlock(&pic_list_lock); 801 802 return (pic); 803 } 804 805 /* 806 * Create interrupt controller. 807 */ 808 static struct intr_pic * 809 pic_create(device_t dev, intptr_t xref) 810 { 811 struct intr_pic *pic; 812 813 mtx_lock(&pic_list_lock); 814 pic = pic_lookup_locked(dev, xref); 815 if (pic != NULL) { 816 mtx_unlock(&pic_list_lock); 817 return (pic); 818 } 819 pic = malloc(sizeof(*pic), M_INTRNG, M_NOWAIT | M_ZERO); 820 pic->pic_xref = xref; 821 pic->pic_dev = dev; 822 SLIST_INSERT_HEAD(&pic_list, pic, pic_next); 823 mtx_unlock(&pic_list_lock); 824 825 return (pic); 826 } 827 #ifdef notyet 828 /* 829 * Destroy interrupt controller. 830 */ 831 static void 832 pic_destroy(device_t dev, intptr_t xref) 833 { 834 struct intr_pic *pic; 835 836 mtx_lock(&pic_list_lock); 837 pic = pic_lookup_locked(dev, xref); 838 if (pic == NULL) { 839 mtx_unlock(&pic_list_lock); 840 return; 841 } 842 SLIST_REMOVE(&pic_list, pic, intr_pic, pic_next); 843 mtx_unlock(&pic_list_lock); 844 845 free(pic, M_INTRNG); 846 } 847 #endif 848 /* 849 * Register interrupt controller. 850 */ 851 int 852 intr_pic_register(device_t dev, intptr_t xref) 853 { 854 struct intr_pic *pic; 855 856 pic = pic_create(dev, xref); 857 if (pic == NULL) 858 return (ENOMEM); 859 if (pic->pic_dev != dev) 860 return (EINVAL); /* XXX it could be many things. */ 861 862 debugf("PIC %p registered for %s <xref %x>\n", pic, 863 device_get_nameunit(dev), xref); 864 return (0); 865 } 866 867 /* 868 * Unregister interrupt controller. 869 */ 870 int 871 intr_pic_unregister(device_t dev, intptr_t xref) 872 { 873 874 panic("%s: not implemented", __func__); 875 } 876 877 /* 878 * Mark interrupt controller (itself) as a root one. 879 * 880 * Note that only an interrupt controller can really know its position 881 * in interrupt controller's tree. So root PIC must claim itself as a root. 882 * 883 * In FDT case, according to ePAPR approved version 1.1 from 08 April 2011, 884 * page 30: 885 * "The root of the interrupt tree is determined when traversal 886 * of the interrupt tree reaches an interrupt controller node without 887 * an interrupts property and thus no explicit interrupt parent." 888 */ 889 int 890 intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter, 891 void *arg, u_int ipicount) 892 { 893 int error; 894 u_int rootirq; 895 896 if (pic_lookup(dev, xref) == NULL) { 897 device_printf(dev, "not registered\n"); 898 return (EINVAL); 899 } 900 if (filter == NULL) { 901 device_printf(dev, "filter missing\n"); 902 return (EINVAL); 903 } 904 905 /* 906 * Only one interrupt controllers could be on the root for now. 907 * Note that we further suppose that there is not threaded interrupt 908 * routine (handler) on the root. See intr_irq_handler(). 909 */ 910 if (intr_irq_root_dev != NULL) { 911 device_printf(dev, "another root already set\n"); 912 return (EBUSY); 913 } 914 915 rootirq = intr_namespace_map_irq(device_get_parent(dev), 0, 0); 916 if (rootirq == IRQ_INVALID) { 917 device_printf(dev, "failed to map an irq for the root pic\n"); 918 return (ENOMEM); 919 } 920 921 /* Create the isrc. */ 922 irq_root_isrc = isrc_lookup(rootirq); 923 924 /* XXX "register" with the PIC. We are the "pic" here, so fake it. */ 925 irq_root_isrc->isrc_flags |= INTR_ISRCF_REGISTERED; 926 927 error = intr_irq_add_handler(device_get_parent(dev), 928 (void*)filter, NULL, arg, rootirq, INTR_TYPE_CLK, NULL); 929 if (error != 0) { 930 device_printf(dev, "failed to install root pic handler\n"); 931 return (error); 932 } 933 intr_irq_root_dev = dev; 934 irq_root_filter = filter; 935 irq_root_arg = arg; 936 irq_root_ipicount = ipicount; 937 938 debugf("irq root set to %s\n", device_get_nameunit(dev)); 939 return (0); 940 } 941 942 int 943 intr_irq_add_handler(device_t dev, driver_filter_t filt, driver_intr_t hand, 944 void *arg, u_int irq, int flags, void **cookiep) 945 { 946 const char *name; 947 struct intr_irqsrc *isrc; 948 int error; 949 950 name = device_get_nameunit(dev); 951 952 #ifdef INTR_SOLO 953 /* 954 * Standard handling is done thru MI interrupt framework. However, 955 * some interrupts could request solely own special handling. This 956 * non standard handling can be used for interrupt controllers without 957 * handler (filter only), so in case that interrupt controllers are 958 * chained, MI interrupt framework is called only in leaf controller. 959 * 960 * Note that root interrupt controller routine is served as well, 961 * however in intr_irq_handler(), i.e. main system dispatch routine. 962 */ 963 if (flags & INTR_SOLO && hand != NULL) { 964 debugf("irq %u cannot solo on %s\n", irq, name); 965 return (EINVAL); 966 } 967 #endif 968 969 isrc = isrc_lookup(irq); 970 if (isrc == NULL) { 971 debugf("irq %u without source on %s\n", irq, name); 972 return (EINVAL); 973 } 974 975 error = isrc_register(isrc); 976 if (error != 0) { 977 debugf("irq %u map error %d on %s\n", irq, error, name); 978 return (error); 979 } 980 981 #ifdef INTR_SOLO 982 if (flags & INTR_SOLO) { 983 error = iscr_setup_filter(isrc, name, (intr_irq_filter_t *)filt, 984 arg, cookiep); 985 debugf("irq %u setup filter error %d on %s\n", irq, error, 986 name); 987 } else 988 #endif 989 { 990 error = isrc_add_handler(isrc, name, filt, hand, arg, flags, 991 cookiep); 992 debugf("irq %u add handler error %d on %s\n", irq, error, name); 993 } 994 if (error != 0) 995 return (error); 996 997 mtx_lock(&isrc_table_lock); 998 isrc->isrc_handlers++; 999 if (isrc->isrc_handlers == 1) { 1000 PIC_ENABLE_INTR(isrc->isrc_dev, isrc); 1001 PIC_ENABLE_SOURCE(isrc->isrc_dev, isrc); 1002 } 1003 mtx_unlock(&isrc_table_lock); 1004 return (0); 1005 } 1006 1007 int 1008 intr_irq_remove_handler(device_t dev, u_int irq, void *cookie) 1009 { 1010 struct intr_irqsrc *isrc; 1011 int error; 1012 1013 isrc = isrc_lookup(irq); 1014 if (isrc == NULL || isrc->isrc_handlers == 0) 1015 return (EINVAL); 1016 1017 if (isrc->isrc_filter != NULL) { 1018 if (isrc != cookie) 1019 return (EINVAL); 1020 1021 mtx_lock(&isrc_table_lock); 1022 isrc->isrc_filter = NULL; 1023 isrc->isrc_arg = NULL; 1024 isrc->isrc_handlers = 0; 1025 PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc); 1026 PIC_DISABLE_INTR(isrc->isrc_dev, isrc); 1027 isrc_update_name(isrc, NULL); 1028 mtx_unlock(&isrc_table_lock); 1029 return (0); 1030 } 1031 1032 if (isrc != intr_handler_source(cookie)) 1033 return (EINVAL); 1034 1035 error = intr_event_remove_handler(cookie); 1036 if (error == 0) { 1037 mtx_lock(&isrc_table_lock); 1038 isrc->isrc_handlers--; 1039 if (isrc->isrc_handlers == 0) { 1040 PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc); 1041 PIC_DISABLE_INTR(isrc->isrc_dev, isrc); 1042 } 1043 intrcnt_updatename(isrc); 1044 mtx_unlock(&isrc_table_lock); 1045 } 1046 return (error); 1047 } 1048 1049 int 1050 intr_irq_config(u_int irq, enum intr_trigger trig, enum intr_polarity pol) 1051 { 1052 struct intr_irqsrc *isrc; 1053 1054 isrc = isrc_lookup(irq); 1055 if (isrc == NULL) 1056 return (EINVAL); 1057 1058 if (isrc->isrc_handlers != 0) 1059 return (EBUSY); /* interrrupt is enabled (active) */ 1060 1061 /* 1062 * Once an interrupt is enabled, we do not change its configuration. 1063 * A controller PIC_ENABLE_INTR() method is called when an interrupt 1064 * is going to be enabled. In this method, a controller should setup 1065 * the interrupt according to saved configuration parameters. 1066 */ 1067 isrc->isrc_trig = trig; 1068 isrc->isrc_pol = pol; 1069 1070 return (0); 1071 } 1072 1073 int 1074 intr_irq_describe(u_int irq, void *cookie, const char *descr) 1075 { 1076 struct intr_irqsrc *isrc; 1077 int error; 1078 1079 isrc = isrc_lookup(irq); 1080 if (isrc == NULL || isrc->isrc_handlers == 0) 1081 return (EINVAL); 1082 1083 if (isrc->isrc_filter != NULL) { 1084 if (isrc != cookie) 1085 return (EINVAL); 1086 1087 mtx_lock(&isrc_table_lock); 1088 isrc_update_name(isrc, descr); 1089 mtx_unlock(&isrc_table_lock); 1090 return (0); 1091 } 1092 1093 error = intr_event_describe_handler(isrc->isrc_event, cookie, descr); 1094 if (error == 0) { 1095 mtx_lock(&isrc_table_lock); 1096 intrcnt_updatename(isrc); 1097 mtx_unlock(&isrc_table_lock); 1098 } 1099 return (error); 1100 } 1101 1102 #ifdef SMP 1103 int 1104 intr_irq_bind(u_int irq, int cpu) 1105 { 1106 struct intr_irqsrc *isrc; 1107 1108 isrc = isrc_lookup(irq); 1109 if (isrc == NULL || isrc->isrc_handlers == 0) 1110 return (EINVAL); 1111 1112 if (isrc->isrc_filter != NULL) 1113 return (intr_isrc_assign_cpu(isrc, cpu)); 1114 1115 return (intr_event_bind(isrc->isrc_event, cpu)); 1116 } 1117 1118 /* 1119 * Return the CPU that the next interrupt source should use. 1120 * For now just returns the next CPU according to round-robin. 1121 */ 1122 u_int 1123 intr_irq_next_cpu(u_int last_cpu, cpuset_t *cpumask) 1124 { 1125 1126 if (!irq_assign_cpu || mp_ncpus == 1) 1127 return (PCPU_GET(cpuid)); 1128 1129 do { 1130 last_cpu++; 1131 if (last_cpu > mp_maxid) 1132 last_cpu = 0; 1133 } while (!CPU_ISSET(last_cpu, cpumask)); 1134 return (last_cpu); 1135 } 1136 1137 /* 1138 * Distribute all the interrupt sources among the available 1139 * CPUs once the AP's have been launched. 1140 */ 1141 static void 1142 intr_irq_shuffle(void *arg __unused) 1143 { 1144 struct intr_irqsrc *isrc; 1145 u_int i; 1146 1147 if (mp_ncpus == 1) 1148 return; 1149 1150 mtx_lock(&isrc_table_lock); 1151 irq_assign_cpu = TRUE; 1152 for (i = 0; i < NIRQ; i++) { 1153 isrc = irq_sources[i]; 1154 if (isrc == NULL || isrc->isrc_handlers == 0 || 1155 isrc->isrc_flags & INTR_ISRCF_PERCPU) 1156 continue; 1157 1158 if (isrc->isrc_event != NULL && 1159 isrc->isrc_flags & INTR_ISRCF_BOUND && 1160 isrc->isrc_event->ie_cpu != CPU_FFS(&isrc->isrc_cpu) - 1) 1161 panic("%s: CPU inconsistency", __func__); 1162 1163 if ((isrc->isrc_flags & INTR_ISRCF_BOUND) == 0) 1164 CPU_ZERO(&isrc->isrc_cpu); /* start again */ 1165 1166 /* 1167 * We are in wicked position here if the following call fails 1168 * for bound ISRC. The best thing we can do is to clear 1169 * isrc_cpu so inconsistency with ie_cpu will be detectable. 1170 */ 1171 if (PIC_BIND(isrc->isrc_dev, isrc) != 0) 1172 CPU_ZERO(&isrc->isrc_cpu); 1173 } 1174 mtx_unlock(&isrc_table_lock); 1175 } 1176 SYSINIT(intr_irq_shuffle, SI_SUB_SMP, SI_ORDER_SECOND, intr_irq_shuffle, NULL); 1177 1178 #else 1179 u_int 1180 intr_irq_next_cpu(u_int current_cpu, cpuset_t *cpumask) 1181 { 1182 1183 return (PCPU_GET(cpuid)); 1184 } 1185 #endif 1186 1187 void dosoftints(void); 1188 void 1189 dosoftints(void) 1190 { 1191 } 1192 1193 #ifdef SMP 1194 /* 1195 * Init interrupt controller on another CPU. 1196 */ 1197 void 1198 intr_pic_init_secondary(void) 1199 { 1200 1201 /* 1202 * QQQ: Only root PIC is aware of other CPUs ??? 1203 */ 1204 KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__)); 1205 1206 //mtx_lock(&isrc_table_lock); 1207 PIC_INIT_SECONDARY(intr_irq_root_dev); 1208 //mtx_unlock(&isrc_table_lock); 1209 } 1210 #endif 1211 1212 #ifdef DDB 1213 DB_SHOW_COMMAND(irqs, db_show_irqs) 1214 { 1215 u_int i, irqsum; 1216 struct intr_irqsrc *isrc; 1217 1218 for (irqsum = 0, i = 0; i < NIRQ; i++) { 1219 isrc = irq_sources[i]; 1220 if (isrc == NULL) 1221 continue; 1222 1223 db_printf("irq%-3u <%s>: cpu %02lx%s cnt %lu\n", i, 1224 isrc->isrc_name, isrc->isrc_cpu.__bits[0], 1225 isrc->isrc_flags & INTR_ISRCF_BOUND ? " (bound)" : "", 1226 isrc->isrc_count[0]); 1227 irqsum += isrc->isrc_count[0]; 1228 } 1229 db_printf("irq total %u\n", irqsum); 1230 } 1231 #endif 1232