gic.c revision 289548
1/*- 2 * Copyright (c) 2011 The FreeBSD Foundation 3 * All rights reserved. 4 * 5 * Developed by Damjan Marion <damjan.marion@gmail.com> 6 * 7 * Based on OMAP4 GIC code by Ben Gray 8 * 9 * Redistribution and use in source and binary forms, with or without 10 * modification, are permitted provided that the following conditions 11 * are met: 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 3. The name of the company nor the name of the author may be used to 18 * endorse or promote products derived from this software without specific 19 * prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34#include <sys/cdefs.h> 35__FBSDID("$FreeBSD: head/sys/arm/arm/gic.c 289548 2015-10-18 20:37:10Z ian $"); 36 37#include "opt_platform.h" 38 39#include "opt_platform.h" 40 41#include <sys/param.h> 42#include <sys/systm.h> 43#include <sys/bus.h> 44#include <sys/kernel.h> 45#include <sys/ktr.h> 46#include <sys/module.h> 47#include <sys/malloc.h> 48#include <sys/rman.h> 49#include <sys/pcpu.h> 50#include <sys/proc.h> 51#include <sys/cpuset.h> 52#include <sys/lock.h> 53#include <sys/mutex.h> 54#include <sys/smp.h> 55#ifdef ARM_INTRNG 56#include <sys/sched.h> 57#endif 58#include <machine/bus.h> 59#include <machine/intr.h> 60#include <machine/smp.h> 61 62#include <dev/fdt/fdt_common.h> 63#include <dev/ofw/openfirm.h> 64#include <dev/ofw/ofw_bus.h> 65#include <dev/ofw/ofw_bus_subr.h> 66 67#ifdef ARM_INTRNG 68#include "pic_if.h" 69#endif 70 71/* We are using GICv2 register naming */ 72 73/* Distributor Registers */ 74#define GICD_CTLR 0x000 /* v1 ICDDCR */ 75#define GICD_TYPER 0x004 /* v1 ICDICTR */ 76#define GICD_IIDR 0x008 /* v1 ICDIIDR */ 77#define GICD_IGROUPR(n) (0x0080 + ((n) * 4)) /* v1 ICDISER */ 78#define GICD_ISENABLER(n) (0x0100 + ((n) * 4)) /* v1 ICDISER */ 79#define GICD_ICENABLER(n) (0x0180 + ((n) * 4)) /* v1 ICDICER */ 80#define GICD_ISPENDR(n) (0x0200 + ((n) * 4)) /* v1 ICDISPR */ 81#define GICD_ICPENDR(n) (0x0280 + ((n) * 4)) /* v1 ICDICPR */ 82#define GICD_ICACTIVER(n) (0x0380 + ((n) * 4)) /* v1 ICDABR */ 83#define GICD_IPRIORITYR(n) (0x0400 + ((n) * 4)) /* v1 ICDIPR */ 84#define GICD_ITARGETSR(n) (0x0800 + ((n) * 4)) /* v1 ICDIPTR */ 85#define GICD_ICFGR(n) (0x0C00 + ((n) * 4)) /* v1 ICDICFR */ 86#define GICD_SGIR(n) (0x0F00 + ((n) * 4)) /* v1 ICDSGIR */ 87 88/* CPU Registers */ 89#define GICC_CTLR 0x0000 /* v1 ICCICR */ 90#define GICC_PMR 0x0004 /* v1 ICCPMR */ 91#define GICC_BPR 0x0008 /* v1 ICCBPR */ 92#define GICC_IAR 0x000C /* v1 ICCIAR */ 93#define GICC_EOIR 0x0010 /* v1 ICCEOIR */ 94#define GICC_RPR 0x0014 /* v1 ICCRPR */ 95#define GICC_HPPIR 0x0018 /* v1 ICCHPIR */ 96#define GICC_ABPR 0x001C /* v1 ICCABPR */ 97#define GICC_IIDR 0x00FC /* v1 ICCIIDR*/ 98 99#define GIC_FIRST_SGI 0 /* Irqs 0-15 are SGIs/IPIs. */ 100#define GIC_LAST_SGI 15 101#define GIC_FIRST_PPI 16 /* Irqs 16-31 are private (per */ 102#define GIC_LAST_PPI 31 /* core) peripheral interrupts. */ 103#define GIC_FIRST_SPI 32 /* Irqs 32+ are shared peripherals. */ 104 105/* First bit is a polarity bit (0 - low, 1 - high) */ 106#define GICD_ICFGR_POL_LOW (0 << 0) 107#define GICD_ICFGR_POL_HIGH (1 << 0) 108#define GICD_ICFGR_POL_MASK 0x1 109/* Second bit is a trigger bit (0 - level, 1 - edge) */ 110#define GICD_ICFGR_TRIG_LVL (0 << 1) 111#define GICD_ICFGR_TRIG_EDGE (1 << 1) 112#define GICD_ICFGR_TRIG_MASK 0x2 113 114#ifndef GIC_DEFAULT_ICFGR_INIT 115#define GIC_DEFAULT_ICFGR_INIT 0x00000000 116#endif 117 118#ifdef ARM_INTRNG 119static u_int gic_irq_cpu; 120static int arm_gic_intr(void *); 121static int arm_gic_bind(device_t dev, struct arm_irqsrc *isrc); 122#endif 123 124struct arm_gic_softc { 125 device_t gic_dev; 126#ifdef ARM_INTRNG 127 void * gic_intrhand; 128 struct arm_irqsrc ** gic_irqs; 129#endif 130 struct resource * gic_res[3]; 131 bus_space_tag_t gic_c_bst; 132 bus_space_tag_t gic_d_bst; 133 bus_space_handle_t gic_c_bsh; 134 bus_space_handle_t gic_d_bsh; 135 uint8_t ver; 136 struct mtx mutex; 137 uint32_t nirqs; 138}; 139 140static struct resource_spec arm_gic_spec[] = { 141 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ 142 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ 143#ifdef ARM_INTRNG 144 { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */ 145#endif 146 { -1, 0 } 147}; 148 149static struct arm_gic_softc *gic_sc = NULL; 150 151#define gic_c_read_4(_sc, _reg) \ 152 bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg)) 153#define gic_c_write_4(_sc, _reg, _val) \ 154 bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val)) 155#define gic_d_read_4(_sc, _reg) \ 156 bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg)) 157#define gic_d_write_1(_sc, _reg, _val) \ 158 bus_space_write_1((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) 159#define gic_d_write_4(_sc, _reg, _val) \ 160 bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val)) 161 162#ifndef ARM_INTRNG 163static int gic_config_irq(int irq, enum intr_trigger trig, 164 enum intr_polarity pol); 165static void gic_post_filter(void *); 166#endif 167 168static struct ofw_compat_data compat_data[] = { 169 {"arm,gic", true}, /* Non-standard, used in FreeBSD dts. */ 170 {"arm,gic-400", true}, 171 {"arm,cortex-a15-gic", true}, 172 {"arm,cortex-a9-gic", true}, 173 {"arm,cortex-a7-gic", true}, 174 {"arm,arm11mp-gic", true}, 175 {"brcm,brahma-b15-gic", true}, 176 {NULL, false} 177}; 178 179static int 180arm_gic_probe(device_t dev) 181{ 182 183 if (!ofw_bus_status_okay(dev)) 184 return (ENXIO); 185 186 if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) 187 return (ENXIO); 188 device_set_desc(dev, "ARM Generic Interrupt Controller"); 189 return (BUS_PROBE_DEFAULT); 190} 191 192#ifdef ARM_INTRNG 193static inline void 194gic_irq_unmask(struct arm_gic_softc *sc, u_int irq) 195{ 196 197 gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F))); 198} 199 200static inline void 201gic_irq_mask(struct arm_gic_softc *sc, u_int irq) 202{ 203 204 gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F))); 205} 206#endif 207 208#ifdef SMP 209#ifdef ARM_INTRNG 210static void 211arm_gic_init_secondary(device_t dev) 212{ 213 struct arm_gic_softc *sc = device_get_softc(dev); 214 struct arm_irqsrc *isrc; 215 u_int irq; 216 217 for (irq = 0; irq < sc->nirqs; irq += 4) 218 gic_d_write_4(sc, GICD_IPRIORITYR(irq >> 2), 0); 219 220 /* Set all the interrupts to be in Group 0 (secure) */ 221 for (irq = 0; irq < sc->nirqs; irq += 32) { 222 gic_d_write_4(sc, GICD_IGROUPR(irq >> 5), 0); 223 } 224 225 /* Enable CPU interface */ 226 gic_c_write_4(sc, GICC_CTLR, 1); 227 228 /* Set priority mask register. */ 229 gic_c_write_4(sc, GICC_PMR, 0xff); 230 231 /* Enable interrupt distribution */ 232 gic_d_write_4(sc, GICD_CTLR, 0x01); 233 234 /* Unmask attached SGI interrupts. */ 235 for (irq = GIC_FIRST_SGI; irq <= GIC_LAST_SGI; irq++) { 236 isrc = sc->gic_irqs[irq]; 237 if (isrc != NULL && isrc->isrc_handlers != 0) { 238 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 239 gic_irq_unmask(sc, irq); 240 } 241 } 242 243 /* Unmask attached PPI interrupts. */ 244 for (irq = GIC_FIRST_PPI; irq <= GIC_LAST_PPI; irq++) { 245 isrc = sc->gic_irqs[irq]; 246 if (isrc == NULL || isrc->isrc_handlers == 0) 247 continue; 248 if (isrc->isrc_flags & ARM_ISRCF_BOUND) { 249 if (CPU_ISSET(PCPU_GET(cpuid), &isrc->isrc_cpu)) 250 gic_irq_unmask(sc, irq); 251 } else { 252 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 253 gic_irq_unmask(sc, irq); 254 } 255 } 256} 257#else 258static void 259arm_gic_init_secondary(device_t dev) 260{ 261 struct arm_gic_softc *sc = device_get_softc(dev); 262 int i; 263 264 for (i = 0; i < sc->nirqs; i += 4) 265 gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0); 266 267 /* Set all the interrupts to be in Group 0 (secure) */ 268 for (i = 0; i < sc->nirqs; i += 32) { 269 gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0); 270 } 271 272 /* Enable CPU interface */ 273 gic_c_write_4(sc, GICC_CTLR, 1); 274 275 /* Set priority mask register. */ 276 gic_c_write_4(sc, GICC_PMR, 0xff); 277 278 /* Enable interrupt distribution */ 279 gic_d_write_4(sc, GICD_CTLR, 0x01); 280 281 /* 282 * Activate the timer interrupts: virtual, secure, and non-secure. 283 */ 284 gic_d_write_4(sc, GICD_ISENABLER(27 >> 5), (1UL << (27 & 0x1F))); 285 gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F))); 286 gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F))); 287} 288#endif /* ARM_INTRNG */ 289#endif /* SMP */ 290 291#ifndef ARM_INTRNG 292int 293gic_decode_fdt(phandle_t iparent, pcell_t *intr, int *interrupt, 294 int *trig, int *pol) 295{ 296 static u_int num_intr_cells; 297 static phandle_t self; 298 struct ofw_compat_data *ocd; 299 300 if (self == 0) { 301 for (ocd = compat_data; ocd->ocd_str != NULL; ocd++) { 302 if (fdt_is_compatible(iparent, ocd->ocd_str)) { 303 self = iparent; 304 break; 305 } 306 } 307 } 308 if (self != iparent) 309 return (ENXIO); 310 311 if (num_intr_cells == 0) { 312 if (OF_searchencprop(OF_node_from_xref(iparent), 313 "#interrupt-cells", &num_intr_cells, 314 sizeof(num_intr_cells)) == -1) { 315 num_intr_cells = 1; 316 } 317 } 318 319 if (num_intr_cells == 1) { 320 *interrupt = fdt32_to_cpu(intr[0]); 321 *trig = INTR_TRIGGER_CONFORM; 322 *pol = INTR_POLARITY_CONFORM; 323 } else { 324 if (fdt32_to_cpu(intr[0]) == 0) 325 *interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_SPI; 326 else 327 *interrupt = fdt32_to_cpu(intr[1]) + GIC_FIRST_PPI; 328 /* 329 * In intr[2], bits[3:0] are trigger type and level flags. 330 * 1 = low-to-high edge triggered 331 * 2 = high-to-low edge triggered 332 * 4 = active high level-sensitive 333 * 8 = active low level-sensitive 334 * The hardware only supports active-high-level or rising-edge. 335 */ 336 if (fdt32_to_cpu(intr[2]) & 0x0a) { 337 printf("unsupported trigger/polarity configuration " 338 "0x%2x\n", fdt32_to_cpu(intr[2]) & 0x0f); 339 return (ENOTSUP); 340 } 341 *pol = INTR_POLARITY_CONFORM; 342 if (fdt32_to_cpu(intr[2]) & 0x01) 343 *trig = INTR_TRIGGER_EDGE; 344 else 345 *trig = INTR_TRIGGER_LEVEL; 346 } 347 return (0); 348} 349#endif 350 351#ifdef ARM_INTRNG 352static inline intptr_t 353gic_xref(device_t dev) 354{ 355#ifdef FDT 356 return (OF_xref_from_node(ofw_bus_get_node(dev))); 357#else 358 return (0); 359#endif 360} 361#endif 362 363static int 364arm_gic_attach(device_t dev) 365{ 366 struct arm_gic_softc *sc; 367 int i; 368 uint32_t icciidr; 369#ifdef ARM_INTRNG 370 intptr_t xref = gic_xref(dev); 371#endif 372 373 if (gic_sc) 374 return (ENXIO); 375 376 sc = device_get_softc(dev); 377 378 if (bus_alloc_resources(dev, arm_gic_spec, sc->gic_res)) { 379 device_printf(dev, "could not allocate resources\n"); 380 return (ENXIO); 381 } 382 383 sc->gic_dev = dev; 384 gic_sc = sc; 385 386 /* Initialize mutex */ 387 mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN); 388 389 /* Distributor Interface */ 390 sc->gic_d_bst = rman_get_bustag(sc->gic_res[0]); 391 sc->gic_d_bsh = rman_get_bushandle(sc->gic_res[0]); 392 393 /* CPU Interface */ 394 sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]); 395 sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]); 396 397 /* Disable interrupt forwarding to the CPU interface */ 398 gic_d_write_4(sc, GICD_CTLR, 0x00); 399 400 /* Get the number of interrupts */ 401 sc->nirqs = gic_d_read_4(sc, GICD_TYPER); 402 sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1); 403 404#ifdef ARM_INTRNG 405 sc->gic_irqs = malloc(sc->nirqs * sizeof (*sc->gic_irqs), M_DEVBUF, 406 M_WAITOK | M_ZERO); 407#else 408 /* Set up function pointers */ 409 arm_post_filter = gic_post_filter; 410 arm_config_irq = gic_config_irq; 411#endif 412 413 icciidr = gic_c_read_4(sc, GICC_IIDR); 414 device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n", 415 icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf, 416 (icciidr & 0xfff), sc->nirqs); 417 418 /* Set all global interrupts to be level triggered, active low. */ 419 for (i = 32; i < sc->nirqs; i += 16) { 420 gic_d_write_4(sc, GICD_ICFGR(i >> 4), GIC_DEFAULT_ICFGR_INIT); 421 } 422 423 /* Disable all interrupts. */ 424 for (i = 32; i < sc->nirqs; i += 32) { 425 gic_d_write_4(sc, GICD_ICENABLER(i >> 5), 0xFFFFFFFF); 426 } 427 428 for (i = 0; i < sc->nirqs; i += 4) { 429 gic_d_write_4(sc, GICD_IPRIORITYR(i >> 2), 0); 430 gic_d_write_4(sc, GICD_ITARGETSR(i >> 2), 431 1 << 0 | 1 << 8 | 1 << 16 | 1 << 24); 432 } 433 434 /* Set all the interrupts to be in Group 0 (secure) */ 435 for (i = 0; i < sc->nirqs; i += 32) { 436 gic_d_write_4(sc, GICD_IGROUPR(i >> 5), 0); 437 } 438 439 /* Enable CPU interface */ 440 gic_c_write_4(sc, GICC_CTLR, 1); 441 442 /* Set priority mask register. */ 443 gic_c_write_4(sc, GICC_PMR, 0xff); 444 445 /* Enable interrupt distribution */ 446 gic_d_write_4(sc, GICD_CTLR, 0x01); 447#ifndef ARM_INTRNG 448 return (0); 449#else 450 /* 451 * Now, when everything is initialized, it's right time to 452 * register interrupt controller to interrupt framefork. 453 */ 454 if (arm_pic_register(dev, xref) != 0) { 455 device_printf(dev, "could not register PIC\n"); 456 goto cleanup; 457 } 458 459 if (sc->gic_res[2] == NULL) { 460 if (arm_pic_claim_root(dev, xref, arm_gic_intr, sc, 461 GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { 462 device_printf(dev, "could not set PIC as a root\n"); 463 arm_pic_unregister(dev, xref); 464 goto cleanup; 465 } 466 } else { 467 if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_CLK, 468 arm_gic_intr, NULL, sc, &sc->gic_intrhand)) { 469 device_printf(dev, "could not setup irq handler\n"); 470 arm_pic_unregister(dev, xref); 471 goto cleanup; 472 } 473 } 474 475 return (0); 476 477cleanup: 478 /* 479 * XXX - not implemented arm_gic_detach() should be called ! 480 */ 481 if (sc->gic_irqs != NULL) 482 free(sc->gic_irqs, M_DEVBUF); 483 bus_release_resources(dev, arm_gic_spec, sc->gic_res); 484 return(ENXIO); 485#endif 486} 487 488#ifdef ARM_INTRNG 489static int 490arm_gic_intr(void *arg) 491{ 492 struct arm_gic_softc *sc = arg; 493 struct arm_irqsrc *isrc; 494 uint32_t irq_active_reg, irq; 495 struct trapframe *tf; 496 497 irq_active_reg = gic_c_read_4(sc, GICC_IAR); 498 irq = irq_active_reg & 0x3FF; 499 500 /* 501 * 1. We do EOI here because recent read value from active interrupt 502 * register must be used for it. Another approach is to save this 503 * value into associated interrupt source. 504 * 2. EOI must be done on same CPU where interrupt has fired. Thus 505 * we must ensure that interrupted thread does not migrate to 506 * another CPU. 507 * 3. EOI cannot be delayed by any preemption which could happen on 508 * critical_exit() used in MI intr code, when interrupt thread is 509 * scheduled. See next point. 510 * 4. IPI_RENDEZVOUS assumes that no preemption is permitted during 511 * an action and any use of critical_exit() could break this 512 * assumption. See comments within smp_rendezvous_action(). 513 * 5. We always return FILTER_HANDLED as this is an interrupt 514 * controller dispatch function. Otherwise, in cascaded interrupt 515 * case, the whole interrupt subtree would be masked. 516 */ 517 518 if (irq >= sc->nirqs) { 519 device_printf(sc->gic_dev, "Spurious interrupt detected\n"); 520 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 521 return (FILTER_HANDLED); 522 } 523 524 tf = curthread->td_intr_frame; 525dispatch_irq: 526 isrc = sc->gic_irqs[irq]; 527 if (isrc == NULL) { 528 device_printf(sc->gic_dev, "Stray interrupt %u detected\n", irq); 529 gic_irq_mask(sc, irq); 530 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 531 goto next_irq; 532 } 533 534 /* 535 * Note that GIC_FIRST_SGI is zero and is not used in 'if' statement 536 * as compiler complains that comparing u_int >= 0 is always true. 537 */ 538 if (irq <= GIC_LAST_SGI) { 539#ifdef SMP 540 /* Call EOI for all IPI before dispatch. */ 541 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 542 arm_ipi_dispatch(isrc, tf); 543 goto next_irq; 544#else 545 printf("SGI %u on UP system detected\n", irq - GIC_FIRST_SGI); 546 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 547 goto next_irq; 548#endif 549 } 550 551 if (isrc->isrc_trig == INTR_TRIGGER_EDGE) 552 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 553 554 arm_irq_dispatch(isrc, tf); 555 556next_irq: 557// arm_irq_memory_barrier(irq); /* XXX */ 558// irq_active_reg = gic_c_read_4(sc, GICC_IAR); 559// irq = irq_active_reg & 0x3FF; 560 if (0 && irq < sc->nirqs) 561 goto dispatch_irq; 562 563 return (FILTER_HANDLED); 564} 565 566static int 567gic_attach_isrc(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int irq) 568{ 569 const char *name; 570 571 /* 572 * 1. The link between ISRC and controller must be set atomically. 573 * 2. Just do things only once in rare case when consumers 574 * of shared interrupt came here at the same moment. 575 */ 576 mtx_lock_spin(&sc->mutex); 577 if (sc->gic_irqs[irq] != NULL) { 578 mtx_unlock_spin(&sc->mutex); 579 return (sc->gic_irqs[irq] == isrc ? 0 : EEXIST); 580 } 581 sc->gic_irqs[irq] = isrc; 582 isrc->isrc_data = irq; 583 mtx_unlock_spin(&sc->mutex); 584 585 name = device_get_nameunit(sc->gic_dev); 586 if (irq <= GIC_LAST_SGI) 587 arm_irq_set_name(isrc, "%s,i%u", name, irq - GIC_FIRST_SGI); 588 else if (irq <= GIC_LAST_PPI) 589 arm_irq_set_name(isrc, "%s,p%u", name, irq - GIC_FIRST_PPI); 590 else 591 arm_irq_set_name(isrc, "%s,s%u", name, irq - GIC_FIRST_SPI); 592 return (0); 593} 594 595static int 596gic_detach_isrc(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int irq) 597{ 598 599 mtx_lock_spin(&sc->mutex); 600 if (sc->gic_irqs[irq] != isrc) { 601 mtx_unlock_spin(&sc->mutex); 602 return (sc->gic_irqs[irq] == NULL ? 0 : EINVAL); 603 } 604 sc->gic_irqs[irq] = NULL; 605 isrc->isrc_data = 0; 606 mtx_unlock_spin(&sc->mutex); 607 608 arm_irq_set_name(isrc, ""); 609 return (0); 610} 611 612static void 613gic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig, 614 enum intr_polarity pol) 615{ 616 uint32_t reg; 617 uint32_t mask; 618 619 if (irq < GIC_FIRST_SPI) 620 return; 621 622 mtx_lock_spin(&sc->mutex); 623 624 reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4)); 625 mask = (reg >> 2*(irq % 16)) & 0x3; 626 627 if (pol == INTR_POLARITY_LOW) { 628 mask &= ~GICD_ICFGR_POL_MASK; 629 mask |= GICD_ICFGR_POL_LOW; 630 } else if (pol == INTR_POLARITY_HIGH) { 631 mask &= ~GICD_ICFGR_POL_MASK; 632 mask |= GICD_ICFGR_POL_HIGH; 633 } 634 635 if (trig == INTR_TRIGGER_LEVEL) { 636 mask &= ~GICD_ICFGR_TRIG_MASK; 637 mask |= GICD_ICFGR_TRIG_LVL; 638 } else if (trig == INTR_TRIGGER_EDGE) { 639 mask &= ~GICD_ICFGR_TRIG_MASK; 640 mask |= GICD_ICFGR_TRIG_EDGE; 641 } 642 643 /* Set mask */ 644 reg = reg & ~(0x3 << 2*(irq % 16)); 645 reg = reg | (mask << 2*(irq % 16)); 646 gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg); 647 648 mtx_unlock_spin(&sc->mutex); 649} 650 651static int 652gic_bind(struct arm_gic_softc *sc, u_int irq, cpuset_t *cpus) 653{ 654 uint32_t cpu, end, mask; 655 656 end = min(mp_ncpus, 8); 657 for (cpu = end; cpu < MAXCPU; cpu++) 658 if (CPU_ISSET(cpu, cpus)) 659 return (EINVAL); 660 661 for (mask = 0, cpu = 0; cpu < end; cpu++) 662 if (CPU_ISSET(cpu, cpus)) 663 mask |= 1 << cpu; 664 665 gic_d_write_1(sc, GICD_ITARGETSR(0) + irq, mask); 666 return (0); 667} 668 669static int 670gic_irq_from_nspc(struct arm_gic_softc *sc, u_int type, u_int num, u_int *irqp) 671{ 672 673 switch (type) { 674 case ARM_IRQ_NSPC_PLAIN: 675 *irqp = num; 676 return (*irqp < sc->nirqs ? 0 : EINVAL); 677 678 case ARM_IRQ_NSPC_IRQ: 679 *irqp = num + GIC_FIRST_PPI; 680 return (*irqp < sc->nirqs ? 0 : EINVAL); 681 682 case ARM_IRQ_NSPC_IPI: 683 *irqp = num + GIC_FIRST_SGI; 684 return (*irqp < GIC_LAST_SGI ? 0 : EINVAL); 685 686 default: 687 return (EINVAL); 688 } 689} 690 691static int 692gic_map_nspc(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int *irqp) 693{ 694 int error; 695 696 error = gic_irq_from_nspc(sc, isrc->isrc_nspc_type, isrc->isrc_nspc_num, 697 irqp); 698 if (error != 0) 699 return (error); 700 return (gic_attach_isrc(sc, isrc, *irqp)); 701} 702 703#ifdef FDT 704static int 705gic_map_fdt(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int *irqp) 706{ 707 u_int irq, tripol; 708 enum intr_trigger trig; 709 enum intr_polarity pol; 710 int error; 711 712 if (isrc->isrc_ncells == 1) { 713 irq = isrc->isrc_cells[0]; 714 pol = INTR_POLARITY_CONFORM; 715 trig = INTR_TRIGGER_CONFORM; 716 } else if (isrc->isrc_ncells == 3) { 717 if (isrc->isrc_cells[0] == 0) 718 irq = isrc->isrc_cells[1] + GIC_FIRST_SPI; 719 else 720 irq = isrc->isrc_cells[1] + GIC_FIRST_PPI; 721 722 /* 723 * In intr[2], bits[3:0] are trigger type and level flags. 724 * 1 = low-to-high edge triggered 725 * 2 = high-to-low edge triggered 726 * 4 = active high level-sensitive 727 * 8 = active low level-sensitive 728 * The hardware only supports active-high-level or rising-edge. 729 */ 730 tripol = isrc->isrc_cells[2]; 731 if (tripol & 0x0a) { 732 printf("unsupported trigger/polarity configuration " 733 "0x%2x\n", tripol & 0x0f); 734 return (ENOTSUP); 735 } 736 pol = INTR_POLARITY_CONFORM; 737 if (tripol & 0x01) 738 trig = INTR_TRIGGER_EDGE; 739 else 740 trig = INTR_TRIGGER_LEVEL; 741 } else 742 return (EINVAL); 743 744 if (irq >= sc->nirqs) 745 return (EINVAL); 746 747 error = gic_attach_isrc(sc, isrc, irq); 748 if (error != 0) 749 return (error); 750 751 isrc->isrc_nspc_type = ARM_IRQ_NSPC_PLAIN; 752 isrc->isrc_nspc_num = irq; 753 isrc->isrc_trig = trig; 754 isrc->isrc_pol = pol; 755 756 *irqp = irq; 757 return (0); 758} 759#endif 760 761static int 762arm_gic_register(device_t dev, struct arm_irqsrc *isrc, boolean_t *is_percpu) 763{ 764 struct arm_gic_softc *sc = device_get_softc(dev); 765 u_int irq; 766 int error; 767 768 if (isrc->isrc_type == ARM_ISRCT_NAMESPACE) 769 error = gic_map_nspc(sc, isrc, &irq); 770#ifdef FDT 771 else if (isrc->isrc_type == ARM_ISRCT_FDT) 772 error = gic_map_fdt(sc, isrc, &irq); 773#endif 774 else 775 return (EINVAL); 776 777 if (error == 0) 778 *is_percpu = irq < GIC_FIRST_SPI ? TRUE : FALSE; 779 return (error); 780} 781 782static void 783arm_gic_enable_intr(device_t dev, struct arm_irqsrc *isrc) 784{ 785 struct arm_gic_softc *sc = device_get_softc(dev); 786 u_int irq = isrc->isrc_data; 787 788 if (isrc->isrc_trig == INTR_TRIGGER_CONFORM) 789 isrc->isrc_trig = INTR_TRIGGER_LEVEL; 790 791 /* 792 * XXX - In case that per CPU interrupt is going to be enabled in time 793 * when SMP is already started, we need some IPI call which 794 * enables it on others CPUs. Further, it's more complicated as 795 * pic_enable_source() and pic_disable_source() should act on 796 * per CPU basis only. Thus, it should be solved here somehow. 797 */ 798 if (isrc->isrc_flags & ARM_ISRCF_PERCPU) 799 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 800 801 gic_config(sc, irq, isrc->isrc_trig, isrc->isrc_pol); 802 arm_gic_bind(dev, isrc); 803} 804 805static void 806arm_gic_enable_source(device_t dev, struct arm_irqsrc *isrc) 807{ 808 struct arm_gic_softc *sc = device_get_softc(dev); 809 u_int irq = isrc->isrc_data; 810 811 arm_irq_memory_barrier(irq); 812 gic_irq_unmask(sc, irq); 813} 814 815static void 816arm_gic_disable_source(device_t dev, struct arm_irqsrc *isrc) 817{ 818 struct arm_gic_softc *sc = device_get_softc(dev); 819 u_int irq = isrc->isrc_data; 820 821 gic_irq_mask(sc, irq); 822} 823 824static int 825arm_gic_unregister(device_t dev, struct arm_irqsrc *isrc) 826{ 827 struct arm_gic_softc *sc = device_get_softc(dev); 828 u_int irq = isrc->isrc_data; 829 830 return (gic_detach_isrc(sc, isrc, irq)); 831} 832 833static void 834arm_gic_pre_ithread(device_t dev, struct arm_irqsrc *isrc) 835{ 836 struct arm_gic_softc *sc = device_get_softc(dev); 837 838 arm_gic_disable_source(dev, isrc); 839 gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data); 840} 841 842static void 843arm_gic_post_ithread(device_t dev, struct arm_irqsrc *isrc) 844{ 845 846 arm_irq_memory_barrier(0); 847 arm_gic_enable_source(dev, isrc); 848} 849 850static void 851arm_gic_post_filter(device_t dev, struct arm_irqsrc *isrc) 852{ 853 struct arm_gic_softc *sc = device_get_softc(dev); 854 855 /* EOI for edge-triggered done earlier. */ 856 if (isrc->isrc_trig == INTR_TRIGGER_EDGE) 857 return; 858 859 arm_irq_memory_barrier(0); 860 gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data); 861} 862 863#ifdef SMP 864static int 865arm_gic_bind(device_t dev, struct arm_irqsrc *isrc) 866{ 867 struct arm_gic_softc *sc = device_get_softc(dev); 868 uint32_t irq = isrc->isrc_data; 869 870 if (irq < GIC_FIRST_SPI) 871 return (EINVAL); 872 873 if (CPU_EMPTY(&isrc->isrc_cpu)) { 874 gic_irq_cpu = arm_irq_next_cpu(gic_irq_cpu, &all_cpus); 875 CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu); 876 } 877 return (gic_bind(sc, irq, &isrc->isrc_cpu)); 878} 879 880static void 881arm_gic_ipi_send(device_t dev, struct arm_irqsrc *isrc, cpuset_t cpus) 882{ 883 struct arm_gic_softc *sc = device_get_softc(dev); 884 uint32_t irq, val = 0, i; 885 886 irq = isrc->isrc_data; 887 888 for (i = 0; i < MAXCPU; i++) 889 if (CPU_ISSET(i, &cpus)) 890 val |= 1 << (16 + i); 891 892 gic_d_write_4(sc, GICD_SGIR(0), val | irq); 893} 894#endif 895#else 896static int 897arm_gic_next_irq(struct arm_gic_softc *sc, int last_irq) 898{ 899 uint32_t active_irq; 900 901 active_irq = gic_c_read_4(sc, GICC_IAR); 902 903 /* 904 * Immediatly EOIR the SGIs, because doing so requires the other 905 * bits (ie CPU number), not just the IRQ number, and we do not 906 * have this information later. 907 */ 908 if ((active_irq & 0x3ff) <= GIC_LAST_SGI) 909 gic_c_write_4(sc, GICC_EOIR, active_irq); 910 active_irq &= 0x3FF; 911 912 if (active_irq == 0x3FF) { 913 if (last_irq == -1) 914 printf("Spurious interrupt detected\n"); 915 return -1; 916 } 917 918 return active_irq; 919} 920 921static int 922arm_gic_config(device_t dev, int irq, enum intr_trigger trig, 923 enum intr_polarity pol) 924{ 925 struct arm_gic_softc *sc = device_get_softc(dev); 926 uint32_t reg; 927 uint32_t mask; 928 929 /* Function is public-accessible, so validate input arguments */ 930 if ((irq < 0) || (irq >= sc->nirqs)) 931 goto invalid_args; 932 if ((trig != INTR_TRIGGER_EDGE) && (trig != INTR_TRIGGER_LEVEL) && 933 (trig != INTR_TRIGGER_CONFORM)) 934 goto invalid_args; 935 if ((pol != INTR_POLARITY_HIGH) && (pol != INTR_POLARITY_LOW) && 936 (pol != INTR_POLARITY_CONFORM)) 937 goto invalid_args; 938 939 mtx_lock_spin(&sc->mutex); 940 941 reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4)); 942 mask = (reg >> 2*(irq % 16)) & 0x3; 943 944 if (pol == INTR_POLARITY_LOW) { 945 mask &= ~GICD_ICFGR_POL_MASK; 946 mask |= GICD_ICFGR_POL_LOW; 947 } else if (pol == INTR_POLARITY_HIGH) { 948 mask &= ~GICD_ICFGR_POL_MASK; 949 mask |= GICD_ICFGR_POL_HIGH; 950 } 951 952 if (trig == INTR_TRIGGER_LEVEL) { 953 mask &= ~GICD_ICFGR_TRIG_MASK; 954 mask |= GICD_ICFGR_TRIG_LVL; 955 } else if (trig == INTR_TRIGGER_EDGE) { 956 mask &= ~GICD_ICFGR_TRIG_MASK; 957 mask |= GICD_ICFGR_TRIG_EDGE; 958 } 959 960 /* Set mask */ 961 reg = reg & ~(0x3 << 2*(irq % 16)); 962 reg = reg | (mask << 2*(irq % 16)); 963 gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg); 964 965 mtx_unlock_spin(&sc->mutex); 966 967 return (0); 968 969invalid_args: 970 device_printf(dev, "gic_config_irg, invalid parameters\n"); 971 return (EINVAL); 972} 973 974 975static void 976arm_gic_mask(device_t dev, int irq) 977{ 978 struct arm_gic_softc *sc = device_get_softc(dev); 979 980 gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F))); 981 gic_c_write_4(sc, GICC_EOIR, irq); /* XXX - not allowed */ 982} 983 984static void 985arm_gic_unmask(device_t dev, int irq) 986{ 987 struct arm_gic_softc *sc = device_get_softc(dev); 988 989 if (irq > GIC_LAST_SGI) 990 arm_irq_memory_barrier(irq); 991 992 gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F))); 993} 994 995#ifdef SMP 996static void 997arm_gic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi) 998{ 999 struct arm_gic_softc *sc = device_get_softc(dev); 1000 uint32_t val = 0, i; 1001 1002 for (i = 0; i < MAXCPU; i++) 1003 if (CPU_ISSET(i, &cpus)) 1004 val |= 1 << (16 + i); 1005 1006 gic_d_write_4(sc, GICD_SGIR(0), val | ipi); 1007} 1008 1009static int 1010arm_gic_ipi_read(device_t dev, int i) 1011{ 1012 1013 if (i != -1) { 1014 /* 1015 * The intr code will automagically give the frame pointer 1016 * if the interrupt argument is 0. 1017 */ 1018 if ((unsigned int)i > 16) 1019 return (0); 1020 return (i); 1021 } 1022 1023 return (0x3ff); 1024} 1025 1026static void 1027arm_gic_ipi_clear(device_t dev, int ipi) 1028{ 1029 /* no-op */ 1030} 1031#endif 1032 1033static void 1034gic_post_filter(void *arg) 1035{ 1036 struct arm_gic_softc *sc = gic_sc; 1037 uintptr_t irq = (uintptr_t) arg; 1038 1039 if (irq > GIC_LAST_SGI) 1040 arm_irq_memory_barrier(irq); 1041 gic_c_write_4(sc, GICC_EOIR, irq); 1042} 1043 1044static int 1045gic_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol) 1046{ 1047 1048 return (arm_gic_config(gic_sc->gic_dev, irq, trig, pol)); 1049} 1050 1051void 1052arm_mask_irq(uintptr_t nb) 1053{ 1054 1055 arm_gic_mask(gic_sc->gic_dev, nb); 1056} 1057 1058void 1059arm_unmask_irq(uintptr_t nb) 1060{ 1061 1062 arm_gic_unmask(gic_sc->gic_dev, nb); 1063} 1064 1065int 1066arm_get_next_irq(int last_irq) 1067{ 1068 1069 return (arm_gic_next_irq(gic_sc, last_irq)); 1070} 1071 1072#ifdef SMP 1073void 1074arm_pic_init_secondary(void) 1075{ 1076 1077 arm_gic_init_secondary(gic_sc->gic_dev); 1078} 1079 1080void 1081pic_ipi_send(cpuset_t cpus, u_int ipi) 1082{ 1083 1084 arm_gic_ipi_send(gic_sc->gic_dev, cpus, ipi); 1085} 1086 1087int 1088pic_ipi_read(int i) 1089{ 1090 1091 return (arm_gic_ipi_read(gic_sc->gic_dev, i)); 1092} 1093 1094void 1095pic_ipi_clear(int ipi) 1096{ 1097 1098 arm_gic_ipi_clear(gic_sc->gic_dev, ipi); 1099} 1100#endif 1101#endif /* ARM_INTRNG */ 1102 1103static device_method_t arm_gic_methods[] = { 1104 /* Device interface */ 1105 DEVMETHOD(device_probe, arm_gic_probe), 1106 DEVMETHOD(device_attach, arm_gic_attach), 1107#ifdef ARM_INTRNG 1108 /* Interrupt controller interface */ 1109 DEVMETHOD(pic_disable_source, arm_gic_disable_source), 1110 DEVMETHOD(pic_enable_intr, arm_gic_enable_intr), 1111 DEVMETHOD(pic_enable_source, arm_gic_enable_source), 1112 DEVMETHOD(pic_post_filter, arm_gic_post_filter), 1113 DEVMETHOD(pic_post_ithread, arm_gic_post_ithread), 1114 DEVMETHOD(pic_pre_ithread, arm_gic_pre_ithread), 1115 DEVMETHOD(pic_register, arm_gic_register), 1116 DEVMETHOD(pic_unregister, arm_gic_unregister), 1117#ifdef SMP 1118 DEVMETHOD(pic_bind, arm_gic_bind), 1119 DEVMETHOD(pic_init_secondary, arm_gic_init_secondary), 1120 DEVMETHOD(pic_ipi_send, arm_gic_ipi_send), 1121#endif 1122#endif 1123 { 0, 0 } 1124}; 1125 1126static driver_t arm_gic_driver = { 1127 "gic", 1128 arm_gic_methods, 1129 sizeof(struct arm_gic_softc), 1130}; 1131 1132static devclass_t arm_gic_devclass; 1133 1134EARLY_DRIVER_MODULE(gic, simplebus, arm_gic_driver, arm_gic_devclass, 0, 0, 1135 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 1136EARLY_DRIVER_MODULE(gic, ofwbus, arm_gic_driver, arm_gic_devclass, 0, 0, 1137 BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); 1138