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 #ifdef SMP 461 /* Install an IPI handler. */ 462 if (mp_ncpus > 1) { 463 for (n = 0; n < npics; n++) { 464 if (piclist[n].dev != root_pic) 465 continue; 466 467 KASSERT(piclist[n].ipis != 0, 468 ("%s: SMP root PIC does not supply any IPIs", 469 __func__)); 470 error = powerpc_setup_intr("IPI", 471 MAP_IRQ(piclist[n].node, piclist[n].irqs), 472 powerpc_ipi_handler, NULL, NULL, 473 INTR_TYPE_MISC | INTR_EXCL, &ipi_cookie, 474 0 /* domain XXX */); 475 if (error) { 476 printf("unable to setup IPI handler\n"); 477 return (error); 478 } 479 480 /* 481 * Some subterfuge: disable late EOI and mark this 482 * as an IPI to the dispatch layer. 483 */ 484 i = intr_lookup(MAP_IRQ(piclist[n].node, 485 piclist[n].irqs)); 486 i->event->ie_post_filter = NULL; 487 i->ipi = 1; 488 } 489 } 490 #endif 491 492 for (vector = 0; vector < nvectors; vector++) { 493 i = powerpc_intrs[vector]; 494 if (i == NULL) 495 continue; 496 497 error = powerpc_map_irq(i); 498 if (error) 499 continue; 500 501 if (i->trig == INTR_TRIGGER_INVALID) 502 PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode, 503 &i->trig, &i->pol); 504 if (i->trig != INTR_TRIGGER_CONFORM || 505 i->pol != INTR_POLARITY_CONFORM) 506 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol); 507 508 if (i->event != NULL) 509 PIC_ENABLE(i->pic, i->intline, vector, &i->priv); 510 } 511 512 return (0); 513 } 514 515 int 516 powerpc_setup_intr(const char *name, u_int irq, driver_filter_t filter, 517 driver_intr_t handler, void *arg, enum intr_type flags, void **cookiep, 518 int domain) 519 { 520 struct powerpc_intr *i; 521 int error, enable = 0; 522 523 i = intr_lookup(irq); 524 if (i == NULL) 525 return (ENOMEM); 526 527 if (i->event == NULL) { 528 error = intr_event_create(&i->event, (void *)i, 0, irq, 529 powerpc_intr_pre_ithread, powerpc_intr_post_ithread, 530 powerpc_intr_eoi, powerpc_assign_intr_cpu, "irq%u:", irq); 531 if (error) 532 return (error); 533 534 enable = 1; 535 } 536 537 error = intr_event_add_handler(i->event, name, filter, handler, arg, 538 intr_priority(flags), flags, cookiep); 539 if (error) 540 return (error); 541 i->pi_domain = domain; 542 if (strcmp(name, "IPI") != 0) { 543 CPU_ZERO(&i->pi_cpuset); 544 CPU_COPY(&cpuset_domain[domain], &i->pi_cpuset); 545 } 546 mtx_lock(&intr_table_lock); 547 intrcnt_setname(i->event->ie_fullname, i->cntindex); 548 mtx_unlock(&intr_table_lock); 549 550 if (!cold) { 551 error = powerpc_map_irq(i); 552 553 if (!error) { 554 if (i->trig == INTR_TRIGGER_INVALID) 555 PIC_TRANSLATE_CODE(i->pic, i->intline, 556 i->fwcode, &i->trig, &i->pol); 557 558 if (i->trig != INTR_TRIGGER_CONFORM || 559 i->pol != INTR_POLARITY_CONFORM) 560 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol); 561 562 if (i->pic == root_pic) 563 PIC_BIND(i->pic, i->intline, i->pi_cpuset, &i->priv); 564 565 if (enable) 566 PIC_ENABLE(i->pic, i->intline, i->vector, 567 &i->priv); 568 } 569 } 570 return (error); 571 } 572 573 int 574 powerpc_teardown_intr(void *cookie) 575 { 576 577 return (intr_event_remove_handler(cookie)); 578 } 579 580 #ifdef SMP 581 int 582 powerpc_bind_intr(u_int irq, u_char cpu) 583 { 584 struct powerpc_intr *i; 585 586 i = intr_lookup(irq); 587 if (i == NULL) 588 return (ENOMEM); 589 590 return (intr_event_bind(i->event, cpu)); 591 } 592 #endif 593 594 int 595 powerpc_fw_config_intr(int irq, int sense_code) 596 { 597 struct powerpc_intr *i; 598 599 i = intr_lookup(irq); 600 if (i == NULL) 601 return (ENOMEM); 602 603 i->trig = INTR_TRIGGER_INVALID; 604 i->pol = INTR_POLARITY_CONFORM; 605 i->fwcode = sense_code; 606 607 if (!cold && i->pic != NULL) { 608 PIC_TRANSLATE_CODE(i->pic, i->intline, i->fwcode, &i->trig, 609 &i->pol); 610 PIC_CONFIG(i->pic, i->intline, i->trig, i->pol); 611 } 612 613 return (0); 614 } 615 616 int 617 powerpc_config_intr(int irq, enum intr_trigger trig, enum intr_polarity pol) 618 { 619 struct powerpc_intr *i; 620 621 i = intr_lookup(irq); 622 if (i == NULL) 623 return (ENOMEM); 624 625 i->trig = trig; 626 i->pol = pol; 627 628 if (!cold && i->pic != NULL) 629 PIC_CONFIG(i->pic, i->intline, trig, pol); 630 631 return (0); 632 } 633 634 void 635 powerpc_dispatch_intr(u_int vector, struct trapframe *tf) 636 { 637 struct powerpc_intr *i; 638 struct intr_event *ie; 639 640 i = powerpc_intrs[vector]; 641 if (i == NULL) 642 goto stray; 643 644 (*i->cntp)++; 645 646 ie = i->event; 647 KASSERT(ie != NULL, ("%s: interrupt without an event", __func__)); 648 649 /* 650 * IPIs are magical and need to be EOI'ed before filtering. 651 * This prevents races in IPI handling. 652 */ 653 if (i->ipi) 654 PIC_EOI(i->pic, i->intline, i->priv); 655 656 if (intr_event_handle(ie, tf) != 0) { 657 goto stray; 658 } 659 return; 660 661 stray: 662 stray_count++; 663 if (stray_count <= MAX_STRAY_LOG) { 664 printf("stray irq %d\n", i ? i->irq : -1); 665 if (stray_count >= MAX_STRAY_LOG) { 666 printf("got %d stray interrupts, not logging anymore\n", 667 MAX_STRAY_LOG); 668 } 669 } 670 if (i != NULL) 671 PIC_MASK(i->pic, i->intline, i->priv); 672 } 673 674 void 675 powerpc_intr_mask(u_int irq) 676 { 677 struct powerpc_intr *i; 678 679 i = intr_lookup(irq); 680 if (i == NULL || i->pic == NULL) 681 return; 682 683 PIC_MASK(i->pic, i->intline, i->priv); 684 } 685 686 void 687 powerpc_intr_unmask(u_int irq) 688 { 689 struct powerpc_intr *i; 690 691 i = intr_lookup(irq); 692 if (i == NULL || i->pic == NULL) 693 return; 694 695 PIC_UNMASK(i->pic, i->intline, i->priv); 696 } 697