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