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