1 /*- 2 * SPDX-License-Identifier: BSD-3-Clause 3 * 4 * Copyright (c) 1991 The Regents of the University of California. 5 * All rights reserved. 6 * 7 * This code is derived from software contributed to Berkeley by 8 * William Jolitz. 9 * 10 * Redistribution and use in source and binary forms, with or without 11 * modification, are permitted provided that the following conditions 12 * are met: 13 * 1. Redistributions of source code must retain the above copyright 14 * notice, this list of conditions and the following disclaimer. 15 * 2. Redistributions in binary form must reproduce the above copyright 16 * notice, this list of conditions and the following disclaimer in the 17 * documentation and/or other materials provided with the distribution. 18 * 3. Neither the name of the University nor the names of its contributors 19 * may be used to endorse or promote products derived from this software 20 * without specific prior written permission. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 25 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 32 * SUCH DAMAGE. 33 */ 34 /*- 35 * Copyright (c) 2002 Benno Rice. 36 * All rights reserved. 37 * 38 * Redistribution and use in source and binary forms, with or without 39 * modification, are permitted provided that the following conditions 40 * are met: 41 * 1. Redistributions of source code must retain the above copyright 42 * notice, this list of conditions and the following disclaimer. 43 * 2. Redistributions in binary form must reproduce the above copyright 44 * notice, this list of conditions and the following disclaimer in the 45 * documentation and/or other materials provided with the distribution. 46 * 47 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 48 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 49 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 50 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 51 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 52 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 53 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 54 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 55 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 56 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 57 * SUCH DAMAGE. 58 * form: src/sys/i386/isa/intr_machdep.c,v 1.57 2001/07/20 59 */ 60 61 #include "opt_isa.h" 62 63 #include <sys/param.h> 64 #include <sys/systm.h> 65 #include <sys/kernel.h> 66 #include <sys/queue.h> 67 #include <sys/bus.h> 68 #include <sys/cpuset.h> 69 #include <sys/interrupt.h> 70 #include <sys/ktr.h> 71 #include <sys/lock.h> 72 #include <sys/malloc.h> 73 #include <sys/mutex.h> 74 #include <sys/pcpu.h> 75 #include <sys/smp.h> 76 #include <sys/syslog.h> 77 #include <sys/vmmeter.h> 78 #include <sys/proc.h> 79 80 #include <machine/frame.h> 81 #include <machine/intr_machdep.h> 82 #include <machine/md_var.h> 83 #include <machine/smp.h> 84 #include <machine/trap.h> 85 86 #include "pic_if.h" 87 88 static MALLOC_DEFINE(M_INTR, "intr", "interrupt handler data"); 89 90 struct powerpc_intr { 91 struct intr_event *event; 92 long *cntp; 93 void *priv; /* PIC-private data */ 94 device_t pic; 95 u_int irq; 96 u_int intline; 97 u_int vector; 98 u_int cntindex; 99 int fwcode; 100 int ipi; 101 int pi_domain; 102 enum intr_trigger trig; 103 enum intr_polarity pol; 104 cpuset_t pi_cpuset; 105 }; 106 107 struct pic { 108 device_t dev; 109 uint32_t node; 110 u_int irqs; 111 u_int ipis; 112 int base; 113 }; 114 115 static u_int intrcnt_index = 0; 116 static struct mtx intr_table_lock; 117 static struct powerpc_intr **powerpc_intrs; 118 static struct pic piclist[MAX_PICS]; 119 static u_int nvectors; /* Allocated vectors */ 120 static u_int npics; /* PICs registered */ 121 #ifdef DEV_ISA 122 static u_int nirqs = 16; /* Allocated IRQS (ISA pre-allocated). */ 123 #else 124 static u_int nirqs = 0; /* Allocated IRQs. */ 125 #endif 126 static u_int stray_count; 127 128 #define INTRNAME_LEN (MAXCOMLEN + 1) 129 u_long *intrcnt; 130 char *intrnames; 131 size_t sintrcnt = sizeof(intrcnt); 132 size_t sintrnames = sizeof(intrnames); 133 int nintrcnt; 134 135 /* 136 * Just to start 137 */ 138 #ifdef __powerpc64__ 139 u_int num_io_irqs = 768; 140 #else 141 u_int num_io_irqs = 256; 142 #endif 143 144 device_t root_pic; 145 146 #ifdef SMP 147 static void *ipi_cookie; 148 #endif 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 static void 159 intr_init(void *dummy __unused) 160 { 161 162 mtx_init(&intr_table_lock, "intr sources lock", NULL, MTX_DEF); 163 } 164 SYSINIT(intr_init, SI_SUB_INTR, SI_ORDER_FIRST, intr_init, NULL); 165 166 static void 167 intr_init_sources(void *arg __unused) 168 { 169 170 powerpc_intrs = mallocarray(num_io_irqs, sizeof(*powerpc_intrs), 171 M_INTR, M_WAITOK | M_ZERO); 172 nintrcnt = 1 + num_io_irqs * 2 + mp_ncpus * 2; 173 #ifdef COUNT_IPIS 174 if (mp_ncpus > 1) 175 nintrcnt += 8 * mp_ncpus; 176 #endif 177 intrcnt = mallocarray(nintrcnt, sizeof(u_long), M_INTR, M_WAITOK | 178 M_ZERO); 179 intrnames = mallocarray(nintrcnt, INTRNAME_LEN, M_INTR, M_WAITOK | 180 M_ZERO); 181 sintrcnt = nintrcnt * sizeof(u_long); 182 sintrnames = nintrcnt * INTRNAME_LEN; 183 184 intrcnt_setname("???", 0); 185 intrcnt_index = 1; 186 } 187 /* 188 * This needs to happen before SI_SUB_CPU 189 */ 190 SYSINIT(intr_init_sources, SI_SUB_KLD, SI_ORDER_ANY, intr_init_sources, NULL); 191 192 #ifdef SMP 193 static void 194 smp_intr_init(void *dummy __unused) 195 { 196 struct powerpc_intr *i; 197 int vector; 198 199 for (vector = 0; vector < nvectors; vector++) { 200 i = powerpc_intrs[vector]; 201 if (i != NULL && i->event != NULL && i->pic == root_pic) 202 PIC_BIND(i->pic, i->intline, i->pi_cpuset, &i->priv); 203 } 204 } 205 SYSINIT(smp_intr_init, SI_SUB_SMP, SI_ORDER_ANY, smp_intr_init, NULL); 206 #endif 207 208 void 209 intrcnt_add(const char *name, u_long **countp) 210 { 211 int idx; 212 213 idx = atomic_fetchadd_int(&intrcnt_index, 1); 214 KASSERT(idx < nintrcnt, ("intrcnt_add: Interrupt counter index %d/%d" 215 "reached nintrcnt : %d", intrcnt_index, idx, nintrcnt)); 216 *countp = &intrcnt[idx]; 217 intrcnt_setname(name, idx); 218 } 219 220 extern void kdb_backtrace(void); 221 static struct powerpc_intr * 222 intr_lookup(u_int irq) 223 { 224 char intrname[16]; 225 struct powerpc_intr *i, *iscan; 226 int vector; 227 228 mtx_lock(&intr_table_lock); 229 for (vector = 0; vector < nvectors; vector++) { 230 i = powerpc_intrs[vector]; 231 if (i != NULL && i->irq == irq) { 232 mtx_unlock(&intr_table_lock); 233 return (i); 234 } 235 } 236 237 i = malloc(sizeof(*i), M_INTR, M_NOWAIT); 238 if (i == NULL) { 239 mtx_unlock(&intr_table_lock); 240 return (NULL); 241 } 242 243 i->event = NULL; 244 i->cntp = NULL; 245 i->priv = NULL; 246 i->trig = INTR_TRIGGER_CONFORM; 247 i->pol = INTR_POLARITY_CONFORM; 248 i->irq = irq; 249 i->pic = NULL; 250 i->vector = -1; 251 i->fwcode = 0; 252 i->ipi = 0; 253 254 #ifdef SMP 255 i->pi_cpuset = all_cpus; 256 #else 257 CPU_SETOF(0, &i->pi_cpuset); 258 #endif 259 260 for (vector = 0; vector < num_io_irqs && vector <= nvectors; 261 vector++) { 262 iscan = powerpc_intrs[vector]; 263 if (iscan != NULL && iscan->irq == irq) 264 break; 265 if (iscan == NULL && i->vector == -1) 266 i->vector = vector; 267 iscan = NULL; 268 } 269 270 if (iscan == NULL && i->vector != -1) { 271 powerpc_intrs[i->vector] = i; 272 i->cntindex = atomic_fetchadd_int(&intrcnt_index, 1); 273 i->cntp = &intrcnt[i->cntindex]; 274 sprintf(intrname, "irq%u:", i->irq); 275 intrcnt_setname(intrname, i->cntindex); 276 nvectors++; 277 } 278 mtx_unlock(&intr_table_lock); 279 280 if (iscan != NULL || i->vector == -1) { 281 free(i, M_INTR); 282 i = iscan; 283 } 284 285 return (i); 286 } 287 288 static int 289 powerpc_map_irq(struct powerpc_intr *i) 290 { 291 struct pic *p; 292 u_int cnt; 293 int idx; 294 295 for (idx = 0; idx < npics; idx++) { 296 p = &piclist[idx]; 297 cnt = p->irqs + p->ipis; 298 if (i->irq >= p->base && i->irq < p->base + cnt) 299 break; 300 } 301 if (idx == npics) 302 return (EINVAL); 303 304 i->intline = i->irq - p->base; 305 i->pic = p->dev; 306 307 /* Try a best guess if that failed */ 308 if (i->pic == NULL) 309 i->pic = root_pic; 310 311 return (0); 312 } 313 314 static void 315 powerpc_intr_eoi(void *arg) 316 { 317 struct powerpc_intr *i = arg; 318 319 PIC_EOI(i->pic, i->intline, i->priv); 320 } 321 322 static void 323 powerpc_intr_pre_ithread(void *arg) 324 { 325 struct powerpc_intr *i = arg; 326 327 PIC_MASK(i->pic, i->intline, i->priv); 328 PIC_EOI(i->pic, i->intline, i->priv); 329 } 330 331 static void 332 powerpc_intr_post_ithread(void *arg) 333 { 334 struct powerpc_intr *i = arg; 335 336 PIC_UNMASK(i->pic, i->intline, i->priv); 337 } 338 339 static int 340 powerpc_assign_intr_cpu(void *arg, int cpu) 341 { 342 #ifdef SMP 343 struct powerpc_intr *i = arg; 344 345 if (cpu == NOCPU) 346 i->pi_cpuset = all_cpus; 347 else 348 CPU_SETOF(cpu, &i->pi_cpuset); 349 350 if (!cold && i->pic != NULL && i->pic == root_pic) 351 PIC_BIND(i->pic, i->intline, i->pi_cpuset, &i->priv); 352 353 return (0); 354 #else 355 return (EOPNOTSUPP); 356 #endif 357 } 358 359 u_int 360 powerpc_register_pic(device_t dev, uint32_t node, u_int irqs, u_int ipis, 361 u_int atpic) 362 { 363 struct pic *p; 364 u_int irq; 365 int idx; 366 367 mtx_lock(&intr_table_lock); 368 369 /* XXX see powerpc_get_irq(). */ 370 for (idx = 0; idx < npics; idx++) { 371 p = &piclist[idx]; 372 if (p->node != node) 373 continue; 374 if (node != 0 || p->dev == dev) 375 break; 376 } 377 p = &piclist[idx]; 378 379 p->dev = dev; 380 p->node = node; 381 p->irqs = irqs; 382 p->ipis = ipis; 383 if (idx == npics) { 384 #ifdef DEV_ISA 385 p->base = (atpic) ? 0 : nirqs; 386 #else 387 p->base = nirqs; 388 #endif 389 irq = p->base + irqs + ipis; 390 nirqs = MAX(nirqs, irq); 391 npics++; 392 } 393 394 KASSERT(npics < MAX_PICS, 395 ("Number of PICs exceeds maximum (%d)", MAX_PICS)); 396 397 mtx_unlock(&intr_table_lock); 398 399 return (p->base); 400 } 401 402 u_int 403 powerpc_get_irq(uint32_t node, u_int pin) 404 { 405 int idx; 406 407 if (node == 0) 408 return (pin); 409 410 mtx_lock(&intr_table_lock); 411 for (idx = 0; idx < npics; idx++) { 412 if (piclist[idx].node == node) { 413 mtx_unlock(&intr_table_lock); 414 return (piclist[idx].base + pin); 415 } 416 } 417 418 /* 419 * XXX we should never encounter an unregistered PIC, but that 420 * can only be done when we properly support bus enumeration 421 * using multiple passes. Until then, fake an entry and give it 422 * some adhoc maximum number of IRQs and IPIs. 423 */ 424 piclist[idx].dev = NULL; 425 piclist[idx].node = node; 426 piclist[idx].irqs = 124; 427 piclist[idx].ipis = 4; 428 piclist[idx].base = nirqs; 429 nirqs += (1 << 25); 430 npics++; 431 432 KASSERT(npics < MAX_PICS, 433 ("Number of PICs exceeds maximum (%d)", MAX_PICS)); 434 435 mtx_unlock(&intr_table_lock); 436 437 return (piclist[idx].base + pin); 438 } 439 440 int 441 powerpc_enable_intr(void) 442 { 443 struct powerpc_intr *i; 444 int error, vector; 445 #ifdef SMP 446 int n; 447 #endif 448 449 if (npics == 0) 450 panic("no PIC detected\n"); 451 452 if (root_pic == NULL) 453 root_pic = piclist[0].dev; 454 455 KASSERT(root_pic != NULL, ("no root PIC!")); 456 457 #ifdef SMP 458 /* Install an IPI handler. */ 459 if (mp_ncpus > 1) { 460 for (n = 0; n < npics; n++) { 461 if (piclist[n].dev != root_pic) 462 continue; 463 464 KASSERT(piclist[n].ipis != 0, 465 ("%s: SMP root PIC does not supply any IPIs", 466 __func__)); 467 error = powerpc_setup_intr("IPI", 468 MAP_IRQ(piclist[n].node, piclist[n].irqs), 469 powerpc_ipi_handler, NULL, NULL, 470 INTR_TYPE_MISC | INTR_EXCL, &ipi_cookie, 471 0 /* domain XXX */); 472 if (error) { 473 printf("unable to setup IPI handler\n"); 474 return (error); 475 } 476 477 /* 478 * Some subterfuge: disable late EOI and mark this 479 * as an IPI to the dispatch layer. 480 */ 481 i = intr_lookup(MAP_IRQ(piclist[n].node, 482 piclist[n].irqs)); 483 i->event->ie_post_filter = NULL; 484 i->ipi = 1; 485 } 486 } 487 #endif 488 489 for (vector = 0; vector < nvectors; vector++) { 490 i = powerpc_intrs[vector]; 491 if (i == NULL) 492 continue; 493 494 error = powerpc_map_irq(i); 495 if (error) 496 continue; 497 498 if (i->trig == INTR_TRIGGER_INVALID) 499 PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode, 500 &i->trig, &i->pol); 501 if (i->trig != INTR_TRIGGER_CONFORM || 502 i->pol != INTR_POLARITY_CONFORM) 503 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol); 504 505 if (i->event != NULL) 506 PIC_ENABLE(i->pic, i->intline, vector, &i->priv); 507 } 508 509 return (0); 510 } 511 512 int 513 powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter, 514 driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep, 515 int domain) 516 { 517 struct powerpc_intr *i; 518 int error, enable = 0; 519 520 i = intr_lookup(irq); 521 if (i == NULL) 522 return (ENOMEM); 523 524 if (i->event == NULL) { 525 error = intr_event_create(&i->event, (void *)i, 0, irq, 526 powerpc_intr_pre_ithread, powerpc_intr_post_ithread, 527 powerpc_intr_eoi, powerpc_assign_intr_cpu, "irq%u:", irq); 528 if (error) 529 return (error); 530 531 enable = 1; 532 } 533 534 error = intr_event_add_handler(i->event, name, filter, handler, arg, 535 intr_priority(flags), flags, cookiep); 536 if (error) 537 return (error); 538 i->pi_domain = domain; 539 if (strcmp(name, "IPI") != 0) { 540 CPU_ZERO(&i->pi_cpuset); 541 CPU_COPY(&cpuset_domain[domain], &i->pi_cpuset); 542 } 543 mtx_lock(&intr_table_lock); 544 intrcnt_setname(i->event->ie_fullname, i->cntindex); 545 mtx_unlock(&intr_table_lock); 546 547 if (!cold) { 548 error = powerpc_map_irq(i); 549 550 if (!error) { 551 if (i->trig == INTR_TRIGGER_INVALID) 552 PIC_TRANSLATE_CODE(i->pic, i->intline, 553 i->fwcode, &i->trig, &i->pol); 554 555 if (i->trig != INTR_TRIGGER_CONFORM || 556 i->pol != INTR_POLARITY_CONFORM) 557 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol); 558 559 if (i->pic == root_pic) 560 PIC_BIND(i->pic, i->intline, i->pi_cpuset, &i->priv); 561 562 if (enable) 563 PIC_ENABLE(i->pic, i->intline, i->vector, 564 &i->priv); 565 } 566 } 567 return (error); 568 } 569 570 int 571 powerpc_teardown_intr(void *cookie) 572 { 573 574 return (intr_event_remove_handler(cookie)); 575 } 576 577 #ifdef SMP 578 int 579 powerpc_bind_intr(u_int irq, u_char cpu) 580 { 581 struct powerpc_intr *i; 582 583 i = intr_lookup(irq); 584 if (i == NULL) 585 return (ENOMEM); 586 587 return (intr_event_bind(i->event, cpu)); 588 } 589 #endif 590 591 int 592 powerpc_fw_config_intr(int irq, int sense_code) 593 { 594 struct powerpc_intr *i; 595 596 i = intr_lookup(irq); 597 if (i == NULL) 598 return (ENOMEM); 599 600 i->trig = INTR_TRIGGER_INVALID; 601 i->pol = INTR_POLARITY_CONFORM; 602 i->fwcode = sense_code; 603 604 if (!cold && i->pic != NULL) { 605 PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode, &i->trig, 606 &i->pol); 607 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol); 608 } 609 610 return (0); 611 } 612 613 int 614 powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol) 615 { 616 struct powerpc_intr *i; 617 618 i = intr_lookup(irq); 619 if (i == NULL) 620 return (ENOMEM); 621 622 i->trig = trig; 623 i->pol = pol; 624 625 if (!cold && i->pic != NULL) 626 PIC_CONFIG(i->pic, i->intline, trig, pol); 627 628 return (0); 629 } 630 631 void 632 powerpc_dispatch_intr(u_int vector, struct trapframe *tf) 633 { 634 struct powerpc_intr *i; 635 struct intr_event *ie; 636 637 i = powerpc_intrs[vector]; 638 if (i == NULL) 639 goto stray; 640 641 (*i->cntp)++; 642 643 ie = i->event; 644 KASSERT(ie != NULL, ("%s: interrupt without an event", __func__)); 645 646 /* 647 * IPIs are magical and need to be EOI'ed before filtering. 648 * This prevents races in IPI handling. 649 */ 650 if (i->ipi) 651 PIC_EOI(i->pic, i->intline, i->priv); 652 653 if (intr_event_handle(ie, tf) != 0) { 654 goto stray; 655 } 656 return; 657 658 stray: 659 stray_count++; 660 if (stray_count <= INTR_STRAY_LOG_MAX) { 661 printf("stray irq %d\n", i ? i->irq : -1); 662 if (stray_count >= INTR_STRAY_LOG_MAX) { 663 printf("got %d stray interrupts, not logging anymore\n", 664 INTR_STRAY_LOG_MAX); 665 } 666 } 667 if (i != NULL) 668 PIC_MASK(i->pic, i->intline, i->priv); 669 } 670 671 void 672 powerpc_intr_mask(u_int irq) 673 { 674 struct powerpc_intr *i; 675 676 i = intr_lookup(irq); 677 if (i == NULL || i->pic == NULL) 678 return; 679 680 PIC_MASK(i->pic, i->intline, i->priv); 681 } 682 683 void 684 powerpc_intr_unmask(u_int irq) 685 { 686 struct powerpc_intr *i; 687 688 i = intr_lookup(irq); 689 if (i == NULL || i->pic == NULL) 690 return; 691 692 PIC_UNMASK(i->pic, i->intline, i->priv); 693 } 694