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