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