1/* $OpenBSD: ampintc.c,v 1.32 2023/09/22 01:10:43 jsg Exp $ */ 2/* 3 * Copyright (c) 2007,2009,2011 Dale Rahn <drahn@openbsd.org> 4 * 5 * Permission to use, copy, modify, and distribute this software for any 6 * purpose with or without fee is hereby granted, provided that the above 7 * copyright notice and this permission notice appear in all copies. 8 * 9 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 10 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 11 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 12 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 13 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 14 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 15 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 16 */ 17 18/* 19 * This driver implements the interrupt controller as specified in 20 * DDI0407E_cortex_a9_mpcore_r2p0_trm with the 21 * IHI0048A_gic_architecture_spec_v1_0 underlying specification 22 */ 23#include <sys/param.h> 24#include <sys/systm.h> 25#include <sys/queue.h> 26#include <sys/malloc.h> 27#include <sys/device.h> 28#include <sys/evcount.h> 29 30#include <uvm/uvm_extern.h> 31 32#include <machine/bus.h> 33#include <machine/fdt.h> 34 35#include <arm/cpufunc.h> 36 37#include <dev/ofw/fdt.h> 38#include <dev/ofw/openfirm.h> 39 40#include <machine/simplebusvar.h> 41 42/* registers */ 43#define ICD_DCR 0x000 44#define ICD_DCR_ES 0x00000001 45#define ICD_DCR_ENS 0x00000002 46 47#define ICD_ICTR 0x004 48#define ICD_ICTR_LSPI_SH 11 49#define ICD_ICTR_LSPI_M 0x1f 50#define ICD_ICTR_CPU_SH 5 51#define ICD_ICTR_CPU_M 0x07 52#define ICD_ICTR_ITL_SH 0 53#define ICD_ICTR_ITL_M 0x1f 54#define ICD_IDIR 0x008 55#define ICD_DIR_PROD_SH 24 56#define ICD_DIR_PROD_M 0xff 57#define ICD_DIR_REV_SH 12 58#define ICD_DIR_REV_M 0xfff 59#define ICD_DIR_IMP_SH 0 60#define ICD_DIR_IMP_M 0xfff 61 62#define IRQ_TO_REG32(i) (((i) >> 5) & 0x1f) 63#define IRQ_TO_REG32BIT(i) ((i) & 0x1f) 64#define IRQ_TO_REG4(i) (((i) >> 2) & 0xff) 65#define IRQ_TO_REG4BIT(i) ((i) & 0x3) 66#define IRQ_TO_REG16(i) (((i) >> 4) & 0x3f) 67#define IRQ_TO_REG16BIT(i) ((i) & 0xf) 68#define IRQ_TO_REGBIT_S(i) 8 69#define IRQ_TO_REG4BIT_M(i) 8 70 71#define ICD_ISRn(i) (0x080 + (IRQ_TO_REG32(i) * 4)) 72#define ICD_ISERn(i) (0x100 + (IRQ_TO_REG32(i) * 4)) 73#define ICD_ICERn(i) (0x180 + (IRQ_TO_REG32(i) * 4)) 74#define ICD_ISPRn(i) (0x200 + (IRQ_TO_REG32(i) * 4)) 75#define ICD_ICPRn(i) (0x280 + (IRQ_TO_REG32(i) * 4)) 76#define ICD_ABRn(i) (0x300 + (IRQ_TO_REG32(i) * 4)) 77#define ICD_IPRn(i) (0x400 + (i)) 78#define ICD_IPTRn(i) (0x800 + (i)) 79#define ICD_ICRn(i) (0xC00 + (IRQ_TO_REG16(i) * 4)) 80#define ICD_ICR_TRIG_LEVEL(i) (0x0 << (IRQ_TO_REG16BIT(i) * 2)) 81#define ICD_ICR_TRIG_EDGE(i) (0x2 << (IRQ_TO_REG16BIT(i) * 2)) 82#define ICD_ICR_TRIG_MASK(i) (0x2 << (IRQ_TO_REG16BIT(i) * 2)) 83 84/* 85 * what about (ppi|spi)_status 86 */ 87#define ICD_PPI 0xD00 88#define ICD_PPI_GTIMER (1 << 11) 89#define ICD_PPI_FIQ (1 << 12) 90#define ICD_PPI_PTIMER (1 << 13) 91#define ICD_PPI_PWDOG (1 << 14) 92#define ICD_PPI_IRQ (1 << 15) 93#define ICD_SPI_BASE 0xD04 94#define ICD_SPIn(i) (ICD_SPI_BASE + ((i) * 4)) 95 96 97#define ICD_SGIR 0xF00 98 99#define ICD_PERIPH_ID_0 0xFD0 100#define ICD_PERIPH_ID_1 0xFD4 101#define ICD_PERIPH_ID_2 0xFD8 102#define ICD_PERIPH_ID_3 0xFDC 103#define ICD_PERIPH_ID_4 0xFE0 104#define ICD_PERIPH_ID_5 0xFE4 105#define ICD_PERIPH_ID_6 0xFE8 106#define ICD_PERIPH_ID_7 0xFEC 107 108#define ICD_COMP_ID_0 0xFEC 109#define ICD_COMP_ID_1 0xFEC 110#define ICD_COMP_ID_2 0xFEC 111#define ICD_COMP_ID_3 0xFEC 112 113 114#define ICPICR 0x00 115#define ICPIPMR 0x04 116/* XXX - must left justify bits to 0 - 7 */ 117#define ICMIPMR_SH 4 118#define ICPBPR 0x08 119#define ICPIAR 0x0C 120#define ICPIAR_IRQ_SH 0 121#define ICPIAR_IRQ_M 0x3ff 122#define ICPIAR_CPUID_SH 10 123#define ICPIAR_CPUID_M 0x7 124#define ICPIAR_NO_PENDING_IRQ ICPIAR_IRQ_M 125#define ICPEOIR 0x10 126#define ICPPRP 0x14 127#define ICPHPIR 0x18 128#define ICPIIR 0xFC 129 130/* 131 * what about periph_id and component_id 132 */ 133 134#define IRQ_ENABLE 1 135#define IRQ_DISABLE 0 136 137struct ampintc_softc { 138 struct simplebus_softc sc_sbus; 139 struct intrq *sc_handler; 140 int sc_nintr; 141 bus_space_tag_t sc_iot; 142 bus_space_handle_t sc_d_ioh, sc_p_ioh; 143 uint8_t sc_cpu_mask[ICD_ICTR_CPU_M + 1]; 144 struct evcount sc_spur; 145 struct interrupt_controller sc_ic; 146 int sc_ipi_reason[ICD_ICTR_CPU_M + 1]; 147 int sc_ipi_num[2]; 148}; 149struct ampintc_softc *ampintc; 150 151 152struct intrhand { 153 TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */ 154 int (*ih_func)(void *); /* handler */ 155 void *ih_arg; /* arg for handler */ 156 int ih_ipl; /* IPL_* */ 157 int ih_flags; 158 int ih_irq; /* IRQ number */ 159 struct evcount ih_count; 160 char *ih_name; 161}; 162 163struct intrq { 164 TAILQ_HEAD(, intrhand) iq_list; /* handler list */ 165 int iq_irq_max; /* IRQ to mask while handling */ 166 int iq_irq_min; /* lowest IRQ when shared */ 167 int iq_ist; /* share type */ 168}; 169 170 171int ampintc_match(struct device *, void *, void *); 172void ampintc_attach(struct device *, struct device *, void *); 173void ampintc_cpuinit(void); 174int ampintc_spllower(int); 175void ampintc_splx(int); 176int ampintc_splraise(int); 177void ampintc_setipl(int); 178void ampintc_calc_mask(void); 179void *ampintc_intr_establish(int, int, int, struct cpu_info *, 180 int (*)(void *), void *, char *); 181void *ampintc_intr_establish_ext(int, int, struct cpu_info *, 182 int (*)(void *), void *, char *); 183void *ampintc_intr_establish_fdt(void *, int *, int, 184 struct cpu_info *, int (*)(void *), void *, char *); 185void ampintc_intr_disestablish(void *); 186void ampintc_irq_handler(void *); 187const char *ampintc_intr_string(void *); 188uint32_t ampintc_iack(void); 189void ampintc_eoi(uint32_t); 190void ampintc_set_priority(int, int); 191void ampintc_intr_enable(int); 192void ampintc_intr_disable(int); 193void ampintc_intr_config(int, int); 194void ampintc_route(int, int, struct cpu_info *); 195void ampintc_route_irq(void *, int, struct cpu_info *); 196 197int ampintc_ipi_combined(void *); 198int ampintc_ipi_nop(void *); 199int ampintc_ipi_ddb(void *); 200void ampintc_send_ipi(struct cpu_info *, int); 201 202const struct cfattach ampintc_ca = { 203 sizeof (struct ampintc_softc), ampintc_match, ampintc_attach 204}; 205 206struct cfdriver ampintc_cd = { 207 NULL, "ampintc", DV_DULL 208}; 209 210static char *ampintc_compatibles[] = { 211 "arm,cortex-a7-gic", 212 "arm,cortex-a9-gic", 213 "arm,cortex-a15-gic", 214 "arm,gic-400", 215 NULL 216}; 217 218int 219ampintc_match(struct device *parent, void *cfdata, void *aux) 220{ 221 struct fdt_attach_args *faa = aux; 222 int i; 223 224 for (i = 0; ampintc_compatibles[i]; i++) 225 if (OF_is_compatible(faa->fa_node, ampintc_compatibles[i])) 226 return (1); 227 228 return (0); 229} 230 231void 232ampintc_attach(struct device *parent, struct device *self, void *aux) 233{ 234 struct ampintc_softc *sc = (struct ampintc_softc *)self; 235 struct fdt_attach_args *faa = aux; 236 int i, nintr, ncpu; 237 uint32_t ictr; 238#ifdef MULTIPROCESSOR 239 int nipi, ipiirq[2]; 240#endif 241 242 ampintc = sc; 243 244 arm_init_smask(); 245 246 sc->sc_iot = faa->fa_iot; 247 248 /* First row: ICD */ 249 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 250 faa->fa_reg[0].size, 0, &sc->sc_d_ioh)) 251 panic("%s: ICD bus_space_map failed!", __func__); 252 253 /* Second row: ICP */ 254 if (bus_space_map(sc->sc_iot, faa->fa_reg[1].addr, 255 faa->fa_reg[1].size, 0, &sc->sc_p_ioh)) 256 panic("%s: ICP bus_space_map failed!", __func__); 257 258 evcount_attach(&sc->sc_spur, "irq1023/spur", NULL); 259 260 ictr = bus_space_read_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICTR); 261 nintr = 32 * ((ictr >> ICD_ICTR_ITL_SH) & ICD_ICTR_ITL_M); 262 nintr += 32; /* ICD_ICTR + 1, irq 0-31 is SGI, 32+ is PPI */ 263 sc->sc_nintr = nintr; 264 ncpu = ((ictr >> ICD_ICTR_CPU_SH) & ICD_ICTR_CPU_M) + 1; 265 printf(" nirq %d, ncpu %d", nintr, ncpu); 266 267 KASSERT(curcpu()->ci_cpuid <= ICD_ICTR_CPU_M); 268 sc->sc_cpu_mask[curcpu()->ci_cpuid] = 269 bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(0)); 270 271 /* Disable all interrupts, clear all pending */ 272 for (i = 0; i < nintr/32; i++) { 273 bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, 274 ICD_ICERn(i*32), ~0); 275 bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, 276 ICD_ICPRn(i*32), ~0); 277 } 278 for (i = 0; i < nintr; i++) { 279 /* lowest priority ?? */ 280 bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i), 0xff); 281 /* target no cpus */ 282 bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(i), 0); 283 } 284 for (i = 2; i < nintr/16; i++) { 285 /* irq 32 - N */ 286 bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(i*16), 0); 287 } 288 289 /* software reset of the part? */ 290 /* set protection bit (kernel only)? */ 291 292 /* XXX - check power saving bit */ 293 294 sc->sc_handler = mallocarray(nintr, sizeof(*sc->sc_handler), M_DEVBUF, 295 M_ZERO | M_NOWAIT); 296 for (i = 0; i < nintr; i++) { 297 TAILQ_INIT(&sc->sc_handler[i].iq_list); 298 } 299 300 ampintc_setipl(IPL_HIGH); /* XXX ??? */ 301 ampintc_calc_mask(); 302 303 /* insert self as interrupt handler */ 304 arm_set_intr_handler(ampintc_splraise, ampintc_spllower, ampintc_splx, 305 ampintc_setipl, ampintc_intr_establish_ext, 306 ampintc_intr_disestablish, ampintc_intr_string, ampintc_irq_handler); 307 308#ifdef MULTIPROCESSOR 309 /* setup IPI interrupts */ 310 311 /* 312 * Ideally we want two IPI interrupts, one for NOP and one for 313 * DDB, however we can survive if only one is available it is 314 * possible that most are not available to the non-secure OS. 315 */ 316 nipi = 0; 317 for (i = 0; i < 16; i++) { 318 int reg, oldreg; 319 320 oldreg = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, 321 ICD_IPRn(i)); 322 bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i), 323 oldreg ^ 0x20); 324 325 /* if this interrupt is not usable, route will be zero */ 326 reg = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i)); 327 if (reg == oldreg) 328 continue; 329 330 /* return to original value, will be set when used */ 331 bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(i), 332 oldreg); 333 334 if (nipi == 0) 335 printf(" ipi: %d", i); 336 else 337 printf(", %d", i); 338 ipiirq[nipi++] = i; 339 if (nipi == 2) 340 break; 341 } 342 343 if (nipi == 0) 344 panic ("no irq available for IPI"); 345 346 switch (nipi) { 347 case 1: 348 ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING, 349 IPL_IPI|IPL_MPSAFE, ampintc_ipi_combined, sc, "ipi"); 350 sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0]; 351 sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[0]; 352 break; 353 case 2: 354 ampintc_intr_establish(ipiirq[0], IST_EDGE_RISING, 355 IPL_IPI|IPL_MPSAFE, ampintc_ipi_nop, sc, "ipinop"); 356 sc->sc_ipi_num[ARM_IPI_NOP] = ipiirq[0]; 357 ampintc_intr_establish(ipiirq[1], IST_EDGE_RISING, 358 IPL_IPI|IPL_MPSAFE, ampintc_ipi_ddb, sc, "ipiddb"); 359 sc->sc_ipi_num[ARM_IPI_DDB] = ipiirq[1]; 360 break; 361 default: 362 panic("nipi unexpected number %d", nipi); 363 } 364 365 intr_send_ipi_func = ampintc_send_ipi; 366#endif 367 368 /* enable interrupts */ 369 bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_DCR, 3); 370 bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1); 371 enable_interrupts(PSR_I); 372 373 sc->sc_ic.ic_node = faa->fa_node; 374 sc->sc_ic.ic_cookie = self; 375 sc->sc_ic.ic_establish = ampintc_intr_establish_fdt; 376 sc->sc_ic.ic_disestablish = ampintc_intr_disestablish; 377 sc->sc_ic.ic_route = ampintc_route_irq; 378 sc->sc_ic.ic_cpu_enable = ampintc_cpuinit; 379 arm_intr_register_fdt(&sc->sc_ic); 380 381 /* attach GICv2M frame controller */ 382 simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa); 383} 384 385void 386ampintc_set_priority(int irq, int pri) 387{ 388 struct ampintc_softc *sc = ampintc; 389 uint32_t prival; 390 391 /* 392 * We only use 16 (13 really) interrupt priorities, 393 * and a CPU is only required to implement bit 4-7 of each field 394 * so shift into the top bits. 395 * also low values are higher priority thus IPL_HIGH - pri 396 */ 397 prival = (IPL_HIGH - pri) << ICMIPMR_SH; 398 bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPRn(irq), prival); 399} 400 401void 402ampintc_setipl(int new) 403{ 404 struct cpu_info *ci = curcpu(); 405 struct ampintc_softc *sc = ampintc; 406 int psw; 407 408 /* disable here is only to keep hardware in sync with ci->ci_cpl */ 409 psw = disable_interrupts(PSR_I); 410 ci->ci_cpl = new; 411 412 /* low values are higher priority thus IPL_HIGH - pri */ 413 bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPIPMR, 414 (IPL_HIGH - new) << ICMIPMR_SH); 415 restore_interrupts(psw); 416} 417 418void 419ampintc_intr_enable(int irq) 420{ 421 struct ampintc_softc *sc = ampintc; 422 423#ifdef DEBUG 424 printf("enable irq %d register %x bitmask %08x\n", 425 irq, ICD_ISERn(irq), 1 << IRQ_TO_REG32BIT(irq)); 426#endif 427 428 bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ISERn(irq), 429 1 << IRQ_TO_REG32BIT(irq)); 430} 431 432void 433ampintc_intr_disable(int irq) 434{ 435 struct ampintc_softc *sc = ampintc; 436 437 bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICERn(irq), 438 1 << IRQ_TO_REG32BIT(irq)); 439} 440 441void 442ampintc_intr_config(int irqno, int type) 443{ 444 struct ampintc_softc *sc = ampintc; 445 uint32_t ctrl; 446 447 ctrl = bus_space_read_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(irqno)); 448 449 ctrl &= ~ICD_ICR_TRIG_MASK(irqno); 450 if (type == IST_EDGE_RISING) 451 ctrl |= ICD_ICR_TRIG_EDGE(irqno); 452 else 453 ctrl |= ICD_ICR_TRIG_LEVEL(irqno); 454 455 bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(irqno), ctrl); 456} 457 458void 459ampintc_calc_mask(void) 460{ 461 struct cpu_info *ci = curcpu(); 462 struct ampintc_softc *sc = ampintc; 463 struct intrhand *ih; 464 int irq; 465 466 for (irq = 0; irq < sc->sc_nintr; irq++) { 467 int max = IPL_NONE; 468 int min = IPL_HIGH; 469 TAILQ_FOREACH(ih, &sc->sc_handler[irq].iq_list, ih_list) { 470 if (ih->ih_ipl > max) 471 max = ih->ih_ipl; 472 473 if (ih->ih_ipl < min) 474 min = ih->ih_ipl; 475 } 476 477 if (max == IPL_NONE) 478 min = IPL_NONE; 479 480 if (sc->sc_handler[irq].iq_irq_max == max && 481 sc->sc_handler[irq].iq_irq_min == min) 482 continue; 483 484 sc->sc_handler[irq].iq_irq_max = max; 485 sc->sc_handler[irq].iq_irq_min = min; 486 487 /* Enable interrupts at lower levels, clear -> enable */ 488 /* Set interrupt priority/enable */ 489 if (min != IPL_NONE) { 490 ampintc_set_priority(irq, min); 491 ampintc_intr_enable(irq); 492 ampintc_route(irq, IRQ_ENABLE, ci); 493 } else { 494 ampintc_intr_disable(irq); 495 ampintc_route(irq, IRQ_DISABLE, ci); 496 } 497 } 498 ampintc_setipl(ci->ci_cpl); 499} 500 501void 502ampintc_splx(int new) 503{ 504 struct cpu_info *ci = curcpu(); 505 506 if (ci->ci_ipending & arm_smask[new]) 507 arm_do_pending_intr(new); 508 509 ampintc_setipl(new); 510} 511 512int 513ampintc_spllower(int new) 514{ 515 struct cpu_info *ci = curcpu(); 516 int old = ci->ci_cpl; 517 ampintc_splx(new); 518 return (old); 519} 520 521int 522ampintc_splraise(int new) 523{ 524 struct cpu_info *ci = curcpu(); 525 int old; 526 old = ci->ci_cpl; 527 528 /* 529 * setipl must always be called because there is a race window 530 * where the variable is updated before the mask is set 531 * an interrupt occurs in that window without the mask always 532 * being set, the hardware might not get updated on the next 533 * splraise completely messing up spl protection. 534 */ 535 if (old > new) 536 new = old; 537 538 ampintc_setipl(new); 539 540 return (old); 541} 542 543 544uint32_t 545ampintc_iack(void) 546{ 547 uint32_t intid; 548 struct ampintc_softc *sc = ampintc; 549 550 intid = bus_space_read_4(sc->sc_iot, sc->sc_p_ioh, ICPIAR); 551 552 return (intid); 553} 554 555void 556ampintc_eoi(uint32_t eoi) 557{ 558 struct ampintc_softc *sc = ampintc; 559 560 bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPEOIR, eoi); 561} 562 563void 564ampintc_route(int irq, int enable, struct cpu_info *ci) 565{ 566 struct ampintc_softc *sc = ampintc; 567 uint8_t mask, val; 568 569 KASSERT(ci->ci_cpuid <= ICD_ICTR_CPU_M); 570 mask = sc->sc_cpu_mask[ci->ci_cpuid]; 571 572 val = bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq)); 573 if (enable == IRQ_ENABLE) 574 val |= mask; 575 else 576 val &= ~mask; 577 bus_space_write_1(sc->sc_iot, sc->sc_d_ioh, ICD_IPTRn(irq), val); 578} 579 580void 581ampintc_cpuinit(void) 582{ 583 struct ampintc_softc *sc = ampintc; 584 int i; 585 586 /* XXX - this is the only cpu specific call to set this */ 587 if (sc->sc_cpu_mask[cpu_number()] == 0) { 588 for (i = 0; i < 32; i++) { 589 int cpumask = 590 bus_space_read_1(sc->sc_iot, sc->sc_d_ioh, 591 ICD_IPTRn(i)); 592 593 if (cpumask != 0) { 594 sc->sc_cpu_mask[cpu_number()] = cpumask; 595 break; 596 } 597 } 598 } 599 600 if (sc->sc_cpu_mask[cpu_number()] == 0) 601 panic("could not determine cpu target mask"); 602} 603 604void 605ampintc_route_irq(void *v, int enable, struct cpu_info *ci) 606{ 607 struct ampintc_softc *sc = ampintc; 608 struct intrhand *ih = v; 609 610 bus_space_write_4(sc->sc_iot, sc->sc_p_ioh, ICPICR, 1); 611 bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_ICRn(ih->ih_irq), 0); 612 if (enable) { 613 ampintc_set_priority(ih->ih_irq, 614 sc->sc_handler[ih->ih_irq].iq_irq_min); 615 ampintc_intr_enable(ih->ih_irq); 616 } 617 618 ampintc_route(ih->ih_irq, enable, ci); 619} 620 621void 622ampintc_irq_handler(void *frame) 623{ 624 struct ampintc_softc *sc = ampintc; 625 struct intrhand *ih; 626 void *arg; 627 uint32_t iack_val; 628 int irq, pri, s, handled; 629 630 iack_val = ampintc_iack(); 631#ifdef DEBUG_INTC 632 if (iack_val != 27) 633 printf("irq %d fired\n", iack_val); 634 else { 635 static int cnt = 0; 636 if ((cnt++ % 100) == 0) { 637 printf("irq %d fired * _100\n", iack_val); 638#ifdef DDB 639 db_enter(); 640#endif 641 } 642 643 } 644#endif 645 646 irq = iack_val & ICPIAR_IRQ_M; 647 648 if (irq == 1023) { 649 sc->sc_spur.ec_count++; 650 return; 651 } 652 653 if (irq >= sc->sc_nintr) 654 return; 655 656 pri = sc->sc_handler[irq].iq_irq_max; 657 s = ampintc_splraise(pri); 658 TAILQ_FOREACH(ih, &sc->sc_handler[irq].iq_list, ih_list) { 659#ifdef MULTIPROCESSOR 660 int need_lock; 661 662 if (ih->ih_flags & IPL_MPSAFE) 663 need_lock = 0; 664 else 665 need_lock = s < IPL_SCHED; 666 667 if (need_lock) 668 KERNEL_LOCK(); 669#endif 670 671 if (ih->ih_arg) 672 arg = ih->ih_arg; 673 else 674 arg = frame; 675 676 enable_interrupts(PSR_I); 677 handled = ih->ih_func(arg); 678 disable_interrupts(PSR_I); 679 if (handled) 680 ih->ih_count.ec_count++; 681 682#ifdef MULTIPROCESSOR 683 if (need_lock) 684 KERNEL_UNLOCK(); 685#endif 686 } 687 ampintc_eoi(iack_val); 688 689 ampintc_splx(s); 690} 691 692void * 693ampintc_intr_establish_ext(int irqno, int level, struct cpu_info *ci, 694 int (*func)(void *), void *arg, char *name) 695{ 696 return ampintc_intr_establish(irqno+32, IST_LEVEL_HIGH, level, 697 ci, func, arg, name); 698} 699 700void * 701ampintc_intr_establish_fdt(void *cookie, int *cell, int level, 702 struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 703{ 704 struct ampintc_softc *sc = (struct ampintc_softc *)cookie; 705 int irq; 706 int type; 707 708 /* 2nd cell contains the interrupt number */ 709 irq = cell[1]; 710 711 /* 1st cell contains type: 0 SPI (32-X), 1 PPI (16-31) */ 712 if (cell[0] == 0) 713 irq += 32; 714 else if (cell[0] == 1) 715 irq += 16; 716 else 717 panic("%s: bogus interrupt type", sc->sc_sbus.sc_dev.dv_xname); 718 719 /* SPIs are only active-high level or low-to-high edge */ 720 if (cell[2] & 0x3) 721 type = IST_EDGE_RISING; 722 else 723 type = IST_LEVEL_HIGH; 724 725 return ampintc_intr_establish(irq, type, level, ci, func, arg, name); 726} 727 728void * 729ampintc_intr_establish(int irqno, int type, int level, struct cpu_info *ci, 730 int (*func)(void *), void *arg, char *name) 731{ 732 struct ampintc_softc *sc = ampintc; 733 struct intrhand *ih; 734 int psw; 735 736 if (irqno < 0 || irqno >= sc->sc_nintr) 737 panic("ampintc_intr_establish: bogus irqnumber %d: %s", 738 irqno, name); 739 740 if (ci == NULL) 741 ci = &cpu_info_primary; 742 else if (!CPU_IS_PRIMARY(ci)) 743 return NULL; 744 745 if (irqno < 16) { 746 /* SGI are only EDGE */ 747 type = IST_EDGE_RISING; 748 } else if (irqno < 32) { 749 /* PPI are only LEVEL */ 750 type = IST_LEVEL_HIGH; 751 } 752 753 ih = malloc(sizeof(*ih), M_DEVBUF, M_WAITOK); 754 ih->ih_func = func; 755 ih->ih_arg = arg; 756 ih->ih_ipl = level & IPL_IRQMASK; 757 ih->ih_flags = level & IPL_FLAGMASK; 758 ih->ih_irq = irqno; 759 ih->ih_name = name; 760 761 psw = disable_interrupts(PSR_I); 762 763 TAILQ_INSERT_TAIL(&sc->sc_handler[irqno].iq_list, ih, ih_list); 764 765 if (name != NULL) 766 evcount_attach(&ih->ih_count, name, &ih->ih_irq); 767 768#ifdef DEBUG_INTC 769 printf("ampintc_intr_establish irq %d level %d [%s]\n", irqno, level, 770 name); 771#endif 772 773 ampintc_intr_config(irqno, type); 774 ampintc_calc_mask(); 775 776 restore_interrupts(psw); 777 return (ih); 778} 779 780void 781ampintc_intr_disestablish(void *cookie) 782{ 783 struct ampintc_softc *sc = ampintc; 784 struct intrhand *ih = cookie; 785 int psw; 786 787#ifdef DEBUG_INTC 788 printf("ampintc_intr_disestablish irq %d level %d [%s]\n", 789 ih->ih_irq, ih->ih_ipl, ih->ih_name); 790#endif 791 792 psw = disable_interrupts(PSR_I); 793 794 TAILQ_REMOVE(&sc->sc_handler[ih->ih_irq].iq_list, ih, ih_list); 795 if (ih->ih_name != NULL) 796 evcount_detach(&ih->ih_count); 797 free(ih, M_DEVBUF, sizeof(*ih)); 798 799 ampintc_calc_mask(); 800 801 restore_interrupts(psw); 802} 803 804const char * 805ampintc_intr_string(void *cookie) 806{ 807 struct intrhand *ih = (struct intrhand *)cookie; 808 static char irqstr[1 + sizeof("ampintc irq ") + 4]; 809 810 snprintf(irqstr, sizeof irqstr, "ampintc irq %d", ih->ih_irq); 811 return irqstr; 812} 813 814/* 815 * GICv2m frame controller for MSI interrupts. 816 */ 817#define GICV2M_TYPER 0x008 818#define GICV2M_TYPER_SPI_BASE(x) (((x) >> 16) & 0x3ff) 819#define GICV2M_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff) 820#define GICV2M_SETSPI_NS 0x040 821 822int ampintc_msi_match(struct device *, void *, void *); 823void ampintc_msi_attach(struct device *, struct device *, void *); 824void *ampintc_intr_establish_msi(void *, uint64_t *, uint64_t *, 825 int , struct cpu_info *, int (*)(void *), void *, char *); 826void ampintc_intr_disestablish_msi(void *); 827 828struct ampintc_msi_softc { 829 struct device sc_dev; 830 bus_space_tag_t sc_iot; 831 bus_space_handle_t sc_ioh; 832 paddr_t sc_addr; 833 int sc_bspi; 834 int sc_nspi; 835 void **sc_spi; 836 struct interrupt_controller sc_ic; 837}; 838 839const struct cfattach ampintcmsi_ca = { 840 sizeof (struct ampintc_msi_softc), ampintc_msi_match, ampintc_msi_attach 841}; 842 843struct cfdriver ampintcmsi_cd = { 844 NULL, "ampintcmsi", DV_DULL 845}; 846 847int 848ampintc_msi_match(struct device *parent, void *cfdata, void *aux) 849{ 850 struct fdt_attach_args *faa = aux; 851 852 return OF_is_compatible(faa->fa_node, "arm,gic-v2m-frame"); 853} 854 855void 856ampintc_msi_attach(struct device *parent, struct device *self, void *aux) 857{ 858 struct ampintc_msi_softc *sc = (struct ampintc_msi_softc *)self; 859 struct fdt_attach_args *faa = aux; 860 uint32_t typer; 861 862 sc->sc_iot = faa->fa_iot; 863 if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr, 864 faa->fa_reg[0].size, 0, &sc->sc_ioh)) 865 panic("%s: bus_space_map failed!", __func__); 866 867 /* XXX: Hack to retrieve the physical address (from a CPU PoV). */ 868 if (!pmap_extract(pmap_kernel(), sc->sc_ioh, &sc->sc_addr)) { 869 printf(": cannot retrieve msi addr\n"); 870 return; 871 } 872 873 typer = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GICV2M_TYPER); 874 sc->sc_bspi = GICV2M_TYPER_SPI_BASE(typer); 875 sc->sc_nspi = GICV2M_TYPER_SPI_COUNT(typer); 876 877 sc->sc_bspi = OF_getpropint(faa->fa_node, 878 "arm,msi-base-spi", sc->sc_bspi); 879 sc->sc_nspi = OF_getpropint(faa->fa_node, 880 "arm,msi-num-spis", sc->sc_nspi); 881 882 printf(": nspi %d\n", sc->sc_nspi); 883 884 sc->sc_spi = mallocarray(sc->sc_nspi, sizeof(void *), M_DEVBUF, 885 M_WAITOK|M_ZERO); 886 887 sc->sc_ic.ic_node = faa->fa_node; 888 sc->sc_ic.ic_cookie = sc; 889 sc->sc_ic.ic_establish_msi = ampintc_intr_establish_msi; 890 sc->sc_ic.ic_disestablish = ampintc_intr_disestablish_msi; 891 arm_intr_register_fdt(&sc->sc_ic); 892} 893 894void * 895ampintc_intr_establish_msi(void *self, uint64_t *addr, uint64_t *data, 896 int level, struct cpu_info *ci, int (*func)(void *), void *arg, char *name) 897{ 898 struct ampintc_msi_softc *sc = (struct ampintc_msi_softc *)self; 899 void *cookie; 900 int i; 901 902 for (i = 0; i < sc->sc_nspi; i++) { 903 if (sc->sc_spi[i] != NULL) 904 continue; 905 906 cookie = ampintc_intr_establish(sc->sc_bspi + i, 907 IST_EDGE_RISING, level, ci, func, arg, name); 908 if (cookie == NULL) 909 return NULL; 910 911 *addr = sc->sc_addr + GICV2M_SETSPI_NS; 912 *data = sc->sc_bspi + i; 913 sc->sc_spi[i] = cookie; 914 return &sc->sc_spi[i]; 915 } 916 917 return NULL; 918} 919 920void 921ampintc_intr_disestablish_msi(void *cookie) 922{ 923 ampintc_intr_disestablish(*(void **)cookie); 924 *(void **)cookie = NULL; 925} 926 927#ifdef MULTIPROCESSOR 928int 929ampintc_ipi_ddb(void *v) 930{ 931 /* XXX */ 932 db_enter(); 933 return 1; 934} 935 936int 937ampintc_ipi_nop(void *v) 938{ 939 /* Nothing to do here, just enough to wake up from WFI */ 940 return 1; 941} 942 943int 944ampintc_ipi_combined(void *v) 945{ 946 struct ampintc_softc *sc = (struct ampintc_softc *)v; 947 948 if (sc->sc_ipi_reason[cpu_number()] == ARM_IPI_DDB) { 949 sc->sc_ipi_reason[cpu_number()] = ARM_IPI_NOP; 950 return ampintc_ipi_ddb(v); 951 } else { 952 return ampintc_ipi_nop(v); 953 } 954} 955 956void 957ampintc_send_ipi(struct cpu_info *ci, int id) 958{ 959 struct ampintc_softc *sc = ampintc; 960 int sendmask; 961 962 if (ci == curcpu() && id == ARM_IPI_NOP) 963 return; 964 965 /* never overwrite IPI_DDB with IPI_NOP */ 966 if (id == ARM_IPI_DDB) 967 sc->sc_ipi_reason[ci->ci_cpuid] = id; 968 969 /* currently will only send to one cpu */ 970 sendmask = 1 << (16 + ci->ci_cpuid); 971 sendmask |= sc->sc_ipi_num[id]; 972 973 bus_space_write_4(sc->sc_iot, sc->sc_d_ioh, ICD_SGIR, sendmask); 974} 975#endif 976