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