gic.c (297390) | gic.c (297539) |
---|---|
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 * --- 18 unchanged lines hidden (view full) --- 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> | 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 * --- 18 unchanged lines hidden (view full) --- 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 297390 2016-03-29 13:51:26Z andrew $"); | 35__FBSDID("$FreeBSD: head/sys/arm/arm/gic.c 297539 2016-04-04 09:15:25Z skra $"); |
36 37#include "opt_platform.h" 38 | 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> --- 64 unchanged lines hidden (view full) --- 113#define GICD_ICFGR_TRIG_EDGE (1 << 1) 114#define GICD_ICFGR_TRIG_MASK 0x2 115 116#ifndef GIC_DEFAULT_ICFGR_INIT 117#define GIC_DEFAULT_ICFGR_INIT 0x00000000 118#endif 119 120#ifdef ARM_INTRNG | 39#include <sys/param.h> 40#include <sys/systm.h> 41#include <sys/bus.h> 42#include <sys/kernel.h> 43#include <sys/ktr.h> 44#include <sys/module.h> 45#include <sys/malloc.h> 46#include <sys/rman.h> --- 64 unchanged lines hidden (view full) --- 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 |
119struct gic_irqsrc { 120 struct intr_irqsrc gi_isrc; 121 uint32_t gi_irq; 122 enum intr_polarity gi_pol; 123 enum intr_trigger gi_trig; 124}; 125 |
|
121static u_int gic_irq_cpu; 122static int arm_gic_intr(void *); | 126static u_int gic_irq_cpu; 127static int arm_gic_intr(void *); |
123static int arm_gic_bind(device_t dev, struct intr_irqsrc *isrc); | 128static int arm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc); |
124 125#ifdef SMP 126u_int sgi_to_ipi[GIC_LAST_SGI - GIC_FIRST_SGI + 1]; | 129 130#ifdef SMP 131u_int sgi_to_ipi[GIC_LAST_SGI - GIC_FIRST_SGI + 1]; |
127#define ISRC_IPI(isrc) sgi_to_ipi[isrc->isrc_data - GIC_FIRST_SGI] | 132u_int sgi_first_unused = GIC_FIRST_SGI; |
128#endif 129#endif 130 131struct arm_gic_softc { 132 device_t gic_dev; 133#ifdef ARM_INTRNG 134 void * gic_intrhand; | 133#endif 134#endif 135 136struct arm_gic_softc { 137 device_t gic_dev; 138#ifdef ARM_INTRNG 139 void * gic_intrhand; |
135 struct intr_irqsrc ** gic_irqs; | 140 struct gic_irqsrc * gic_irqs; |
136#endif 137 struct resource * gic_res[3]; 138 bus_space_tag_t gic_c_bst; 139 bus_space_tag_t gic_d_bst; 140 bus_space_handle_t gic_c_bsh; 141 bus_space_handle_t gic_d_bsh; 142 uint8_t ver; 143 struct mtx mutex; 144 uint32_t nirqs; 145#ifdef GIC_DEBUG_SPURIOUS 146 uint32_t last_irq[MAXCPU]; 147#endif 148}; 149 | 141#endif 142 struct resource * gic_res[3]; 143 bus_space_tag_t gic_c_bst; 144 bus_space_tag_t gic_d_bst; 145 bus_space_handle_t gic_c_bsh; 146 bus_space_handle_t gic_d_bsh; 147 uint8_t ver; 148 struct mtx mutex; 149 uint32_t nirqs; 150#ifdef GIC_DEBUG_SPURIOUS 151 uint32_t last_irq[MAXCPU]; 152#endif 153}; 154 |
155#ifdef ARM_INTRNG 156#define GIC_INTR_ISRC(sc, irq) (&sc->gic_irqs[irq].gi_isrc) 157#endif 158 |
|
150static struct resource_spec arm_gic_spec[] = { 151 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ 152 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ 153#ifdef ARM_INTRNG 154 { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */ 155#endif 156 { -1, 0 } 157}; --- 80 unchanged lines hidden (view full) --- 238 /* Set priority mask register. */ 239 gic_c_write_4(sc, GICC_PMR, 0xff); 240 241 /* Enable interrupt distribution */ 242 gic_d_write_4(sc, GICD_CTLR, 0x01); 243 244 /* Unmask attached SGI interrupts. */ 245 for (irq = GIC_FIRST_SGI; irq <= GIC_LAST_SGI; irq++) { | 159static struct resource_spec arm_gic_spec[] = { 160 { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ 161 { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ 162#ifdef ARM_INTRNG 163 { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */ 164#endif 165 { -1, 0 } 166}; --- 80 unchanged lines hidden (view full) --- 247 /* Set priority mask register. */ 248 gic_c_write_4(sc, GICC_PMR, 0xff); 249 250 /* Enable interrupt distribution */ 251 gic_d_write_4(sc, GICD_CTLR, 0x01); 252 253 /* Unmask attached SGI interrupts. */ 254 for (irq = GIC_FIRST_SGI; irq <= GIC_LAST_SGI; irq++) { |
246 isrc = sc->gic_irqs[irq]; | 255 isrc = GIC_INTR_ISRC(sc, irq); |
247 if (isrc != NULL && isrc->isrc_handlers != 0) { 248 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 249 gic_irq_unmask(sc, irq); 250 } 251 } 252 253 /* Unmask attached PPI interrupts. */ 254 for (irq = GIC_FIRST_PPI; irq <= GIC_LAST_PPI; irq++) { | 256 if (isrc != NULL && isrc->isrc_handlers != 0) { 257 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 258 gic_irq_unmask(sc, irq); 259 } 260 } 261 262 /* Unmask attached PPI interrupts. */ 263 for (irq = GIC_FIRST_PPI; irq <= GIC_LAST_PPI; irq++) { |
255 isrc = sc->gic_irqs[irq]; | 264 isrc = GIC_INTR_ISRC(sc, irq); |
256 if (isrc == NULL || isrc->isrc_handlers == 0) 257 continue; 258 if (isrc->isrc_flags & INTR_ISRCF_BOUND) { 259 if (CPU_ISSET(PCPU_GET(cpuid), &isrc->isrc_cpu)) 260 gic_irq_unmask(sc, irq); 261 } else { 262 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 263 gic_irq_unmask(sc, irq); --- 100 unchanged lines hidden (view full) --- 364gic_xref(device_t dev) 365{ 366#ifdef FDT 367 return (OF_xref_from_node(ofw_bus_get_node(dev))); 368#else 369 return (0); 370#endif 371} | 265 if (isrc == NULL || isrc->isrc_handlers == 0) 266 continue; 267 if (isrc->isrc_flags & INTR_ISRCF_BOUND) { 268 if (CPU_ISSET(PCPU_GET(cpuid), &isrc->isrc_cpu)) 269 gic_irq_unmask(sc, irq); 270 } else { 271 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 272 gic_irq_unmask(sc, irq); --- 100 unchanged lines hidden (view full) --- 373gic_xref(device_t dev) 374{ 375#ifdef FDT 376 return (OF_xref_from_node(ofw_bus_get_node(dev))); 377#else 378 return (0); 379#endif 380} |
381 382static int 383arm_gic_register_isrcs(struct arm_gic_softc *sc, uint32_t num) 384{ 385 int error; 386 uint32_t irq; 387 struct gic_irqsrc *irqs; 388 struct intr_irqsrc *isrc; 389 const char *name; 390 391 irqs = malloc(num * sizeof(struct gic_irqsrc), M_DEVBUF, 392 M_WAITOK | M_ZERO); 393 394 name = device_get_nameunit(sc->gic_dev); 395 for (irq = 0; irq < num; irq++) { 396 irqs[irq].gi_irq = irq; 397 irqs[irq].gi_pol = INTR_POLARITY_CONFORM; 398 irqs[irq].gi_trig = INTR_TRIGGER_CONFORM; 399 400 isrc = &irqs[irq].gi_isrc; 401 if (irq <= GIC_LAST_SGI) { 402 error = intr_isrc_register(isrc, sc->gic_dev, 403 INTR_ISRCF_IPI, "%s,i%u", name, irq - GIC_FIRST_SGI); 404 } else if (irq <= GIC_LAST_PPI) { 405 error = intr_isrc_register(isrc, sc->gic_dev, 406 INTR_ISRCF_PPI, "%s,p%u", name, irq - GIC_FIRST_PPI); 407 } else { 408 error = intr_isrc_register(isrc, sc->gic_dev, 0, 409 "%s,s%u", name, irq - GIC_FIRST_SPI); 410 } 411 if (error != 0) { 412 /* XXX call intr_isrc_deregister() */ 413 free(irqs, M_DEVBUF); 414 return (error); 415 } 416 } 417 sc->gic_irqs = irqs; 418 sc->nirqs = num; 419 return (0); 420} |
|
372#endif 373 374static int 375arm_gic_attach(device_t dev) 376{ 377 struct arm_gic_softc *sc; 378 int i; | 421#endif 422 423static int 424arm_gic_attach(device_t dev) 425{ 426 struct arm_gic_softc *sc; 427 int i; |
379 uint32_t icciidr, mask; | 428 uint32_t icciidr, mask, nirqs; |
380#ifdef ARM_INTRNG 381 phandle_t pxref; 382 intptr_t xref = gic_xref(dev); 383#endif 384 385 if (gic_sc) 386 return (ENXIO); 387 --- 17 unchanged lines hidden (view full) --- 405 /* CPU Interface */ 406 sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]); 407 sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]); 408 409 /* Disable interrupt forwarding to the CPU interface */ 410 gic_d_write_4(sc, GICD_CTLR, 0x00); 411 412 /* Get the number of interrupts */ | 429#ifdef ARM_INTRNG 430 phandle_t pxref; 431 intptr_t xref = gic_xref(dev); 432#endif 433 434 if (gic_sc) 435 return (ENXIO); 436 --- 17 unchanged lines hidden (view full) --- 454 /* CPU Interface */ 455 sc->gic_c_bst = rman_get_bustag(sc->gic_res[1]); 456 sc->gic_c_bsh = rman_get_bushandle(sc->gic_res[1]); 457 458 /* Disable interrupt forwarding to the CPU interface */ 459 gic_d_write_4(sc, GICD_CTLR, 0x00); 460 461 /* Get the number of interrupts */ |
413 sc->nirqs = gic_d_read_4(sc, GICD_TYPER); 414 sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1); | 462 nirqs = gic_d_read_4(sc, GICD_TYPER); 463 nirqs = 32 * ((nirqs & 0x1f) + 1); |
415 416#ifdef ARM_INTRNG | 464 465#ifdef ARM_INTRNG |
417 sc->gic_irqs = malloc(sc->nirqs * sizeof (*sc->gic_irqs), M_DEVBUF, 418 M_WAITOK | M_ZERO); | 466 if (arm_gic_register_isrcs(sc, nirqs)) { 467 device_printf(dev, "could not register irqs\n"); 468 goto cleanup; 469 } |
419#else | 470#else |
471 sc->nirqs = nirqs; 472 |
|
420 /* Set up function pointers */ 421 arm_post_filter = gic_post_filter; 422 arm_config_irq = gic_config_irq; 423#endif 424 425 icciidr = gic_c_read_4(sc, GICC_IIDR); 426 device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n", 427 icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf, --- 63 unchanged lines hidden (view full) --- 491 * - doesn't have interrupt parent 492 * - his interrupt parent is this controller 493 */ 494 pxref = ofw_bus_find_iparent(ofw_bus_get_node(dev)); 495 if (pxref == 0 || xref == pxref) { 496 if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc, 497 GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { 498 device_printf(dev, "could not set PIC as a root\n"); | 473 /* Set up function pointers */ 474 arm_post_filter = gic_post_filter; 475 arm_config_irq = gic_config_irq; 476#endif 477 478 icciidr = gic_c_read_4(sc, GICC_IIDR); 479 device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n", 480 icciidr>>20, (icciidr>>16) & 0xF, (icciidr>>12) & 0xf, --- 63 unchanged lines hidden (view full) --- 544 * - doesn't have interrupt parent 545 * - his interrupt parent is this controller 546 */ 547 pxref = ofw_bus_find_iparent(ofw_bus_get_node(dev)); 548 if (pxref == 0 || xref == pxref) { 549 if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc, 550 GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { 551 device_printf(dev, "could not set PIC as a root\n"); |
499 intr_pic_unregister(dev, xref); | 552 intr_pic_deregister(dev, xref); |
500 goto cleanup; 501 } 502 } else { 503 if (sc->gic_res[2] == NULL) { 504 device_printf(dev, 505 "not root PIC must have defined interrupt\n"); | 553 goto cleanup; 554 } 555 } else { 556 if (sc->gic_res[2] == NULL) { 557 device_printf(dev, 558 "not root PIC must have defined interrupt\n"); |
506 intr_pic_unregister(dev, xref); | 559 intr_pic_deregister(dev, xref); |
507 goto cleanup; 508 } 509 if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_CLK, 510 arm_gic_intr, NULL, sc, &sc->gic_intrhand)) { 511 device_printf(dev, "could not setup irq handler\n"); | 560 goto cleanup; 561 } 562 if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_CLK, 563 arm_gic_intr, NULL, sc, &sc->gic_intrhand)) { 564 device_printf(dev, "could not setup irq handler\n"); |
512 intr_pic_unregister(dev, xref); | 565 intr_pic_deregister(dev, xref); |
513 goto cleanup; 514 } 515 } 516 517 OF_device_register_xref(xref, dev); 518 return (0); 519 520cleanup: --- 7 unchanged lines hidden (view full) --- 528#endif 529} 530 531#ifdef ARM_INTRNG 532static int 533arm_gic_intr(void *arg) 534{ 535 struct arm_gic_softc *sc = arg; | 566 goto cleanup; 567 } 568 } 569 570 OF_device_register_xref(xref, dev); 571 return (0); 572 573cleanup: --- 7 unchanged lines hidden (view full) --- 581#endif 582} 583 584#ifdef ARM_INTRNG 585static int 586arm_gic_intr(void *arg) 587{ 588 struct arm_gic_softc *sc = arg; |
536 struct intr_irqsrc *isrc; | 589 struct gic_irqsrc *gi; |
537 uint32_t irq_active_reg, irq; 538 struct trapframe *tf; 539 540 irq_active_reg = gic_c_read_4(sc, GICC_IAR); 541 irq = irq_active_reg & 0x3FF; 542 543 /* 544 * 1. We do EOI here because recent read value from active interrupt --- 19 unchanged lines hidden (view full) --- 564 "Spurious interrupt detected: last irq: %d on CPU%d\n", 565 sc->last_irq[PCPU_GET(cpuid)], PCPU_GET(cpuid)); 566#endif 567 return (FILTER_HANDLED); 568 } 569 570 tf = curthread->td_intr_frame; 571dispatch_irq: | 590 uint32_t irq_active_reg, irq; 591 struct trapframe *tf; 592 593 irq_active_reg = gic_c_read_4(sc, GICC_IAR); 594 irq = irq_active_reg & 0x3FF; 595 596 /* 597 * 1. We do EOI here because recent read value from active interrupt --- 19 unchanged lines hidden (view full) --- 617 "Spurious interrupt detected: last irq: %d on CPU%d\n", 618 sc->last_irq[PCPU_GET(cpuid)], PCPU_GET(cpuid)); 619#endif 620 return (FILTER_HANDLED); 621 } 622 623 tf = curthread->td_intr_frame; 624dispatch_irq: |
572 isrc = sc->gic_irqs[irq]; 573 if (isrc == NULL) { 574 device_printf(sc->gic_dev, "Stray interrupt %u detected\n", irq); 575 gic_irq_mask(sc, irq); 576 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 577 goto next_irq; 578 } 579 | 625 gi = sc->gic_irqs + irq; |
580 /* 581 * Note that GIC_FIRST_SGI is zero and is not used in 'if' statement 582 * as compiler complains that comparing u_int >= 0 is always true. 583 */ 584 if (irq <= GIC_LAST_SGI) { 585#ifdef SMP 586 /* Call EOI for all IPI before dispatch. */ 587 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); | 626 /* 627 * Note that GIC_FIRST_SGI is zero and is not used in 'if' statement 628 * as compiler complains that comparing u_int >= 0 is always true. 629 */ 630 if (irq <= GIC_LAST_SGI) { 631#ifdef SMP 632 /* Call EOI for all IPI before dispatch. */ 633 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); |
588 intr_ipi_dispatch(ISRC_IPI(isrc), tf); | 634 intr_ipi_dispatch(sgi_to_ipi[gi->gi_irq], tf); |
589 goto next_irq; 590#else 591 device_printf(sc->gic_dev, "SGI %u on UP system detected\n", 592 irq - GIC_FIRST_SGI); 593 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 594 goto next_irq; 595#endif 596 } 597 598#ifdef GIC_DEBUG_SPURIOUS 599 sc->last_irq[PCPU_GET(cpuid)] = irq; 600#endif | 635 goto next_irq; 636#else 637 device_printf(sc->gic_dev, "SGI %u on UP system detected\n", 638 irq - GIC_FIRST_SGI); 639 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 640 goto next_irq; 641#endif 642 } 643 644#ifdef GIC_DEBUG_SPURIOUS 645 sc->last_irq[PCPU_GET(cpuid)] = irq; 646#endif |
601 if (isrc->isrc_trig == INTR_TRIGGER_EDGE) | 647 if (gi->gi_trig == INTR_TRIGGER_EDGE) |
602 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 603 | 648 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 649 |
604 intr_irq_dispatch(isrc, tf); | 650 if (intr_isrc_dispatch(&gi->gi_isrc, tf) != 0) { 651 gic_irq_mask(sc, irq); 652 if (gi->gi_trig != INTR_TRIGGER_EDGE) 653 gic_c_write_4(sc, GICC_EOIR, irq_active_reg); 654 device_printf(sc->gic_dev, "Stray irq %u disabled\n", irq); 655 } |
605 606next_irq: 607 arm_irq_memory_barrier(irq); 608 irq_active_reg = gic_c_read_4(sc, GICC_IAR); 609 irq = irq_active_reg & 0x3FF; 610 if (irq < sc->nirqs) 611 goto dispatch_irq; 612 613 return (FILTER_HANDLED); 614} 615 | 656 657next_irq: 658 arm_irq_memory_barrier(irq); 659 irq_active_reg = gic_c_read_4(sc, GICC_IAR); 660 irq = irq_active_reg & 0x3FF; 661 if (irq < sc->nirqs) 662 goto dispatch_irq; 663 664 return (FILTER_HANDLED); 665} 666 |
616static int 617gic_attach_isrc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int irq) 618{ 619 const char *name; 620 621 /* 622 * 1. The link between ISRC and controller must be set atomically. 623 * 2. Just do things only once in rare case when consumers 624 * of shared interrupt came here at the same moment. 625 */ 626 mtx_lock_spin(&sc->mutex); 627 if (sc->gic_irqs[irq] != NULL) { 628 mtx_unlock_spin(&sc->mutex); 629 return (sc->gic_irqs[irq] == isrc ? 0 : EEXIST); 630 } 631 sc->gic_irqs[irq] = isrc; 632 isrc->isrc_data = irq; 633 mtx_unlock_spin(&sc->mutex); 634 635 name = device_get_nameunit(sc->gic_dev); 636 if (irq <= GIC_LAST_SGI) 637 intr_irq_set_name(isrc, "%s,i%u", name, irq - GIC_FIRST_SGI); 638 else if (irq <= GIC_LAST_PPI) 639 intr_irq_set_name(isrc, "%s,p%u", name, irq - GIC_FIRST_PPI); 640 else 641 intr_irq_set_name(isrc, "%s,s%u", name, irq - GIC_FIRST_SPI); 642 return (0); 643} 644 645static int 646gic_detach_isrc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int irq) 647{ 648 649 mtx_lock_spin(&sc->mutex); 650 if (sc->gic_irqs[irq] != isrc) { 651 mtx_unlock_spin(&sc->mutex); 652 return (sc->gic_irqs[irq] == NULL ? 0 : EINVAL); 653 } 654 sc->gic_irqs[irq] = NULL; 655 isrc->isrc_data = 0; 656 mtx_unlock_spin(&sc->mutex); 657 658 intr_irq_set_name(isrc, ""); 659 return (0); 660} 661 | |
662static void 663gic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig, 664 enum intr_polarity pol) 665{ 666 uint32_t reg; 667 uint32_t mask; 668 669 if (irq < GIC_FIRST_SPI) --- 41 unchanged lines hidden (view full) --- 711 for (mask = 0, cpu = 0; cpu < end; cpu++) 712 if (CPU_ISSET(cpu, cpus)) 713 mask |= 1 << cpu; 714 715 gic_d_write_1(sc, GICD_ITARGETSR(0) + irq, mask); 716 return (0); 717} 718 | 667static void 668gic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig, 669 enum intr_polarity pol) 670{ 671 uint32_t reg; 672 uint32_t mask; 673 674 if (irq < GIC_FIRST_SPI) --- 41 unchanged lines hidden (view full) --- 716 for (mask = 0, cpu = 0; cpu < end; cpu++) 717 if (CPU_ISSET(cpu, cpus)) 718 mask |= 1 << cpu; 719 720 gic_d_write_1(sc, GICD_ITARGETSR(0) + irq, mask); 721 return (0); 722} 723 |
724#ifdef FDT |
|
719static int | 725static int |
720gic_irq_from_nspc(struct arm_gic_softc *sc, u_int type, u_int num, u_int *irqp) | 726gic_map_fdt(device_t dev, u_int ncells, pcell_t *cells, u_int *irqp, 727 enum intr_polarity *polp, enum intr_trigger *trigp) |
721{ 722 | 728{ 729 |
723 switch (type) { 724 case INTR_IRQ_NSPC_PLAIN: 725 *irqp = num; 726 return (*irqp < sc->nirqs ? 0 : EINVAL); | 730 if (ncells == 1) { 731 *irqp = cells[0]; 732 *polp = INTR_POLARITY_CONFORM; 733 *trigp = INTR_TRIGGER_CONFORM; 734 return (0); 735 } 736 if (ncells == 3) { 737 u_int irq, tripol; |
727 | 738 |
728 case INTR_IRQ_NSPC_IRQ: 729 *irqp = num + GIC_FIRST_PPI; 730 return (*irqp < sc->nirqs ? 0 : EINVAL); | 739 /* 740 * The 1st cell is the interrupt type: 741 * 0 = SPI 742 * 1 = PPI 743 * The 2nd cell contains the interrupt number: 744 * [0 - 987] for SPI 745 * [0 - 15] for PPI 746 * The 3rd cell is the flags, encoded as follows: 747 * bits[3:0] trigger type and level flags 748 * 1 = low-to-high edge triggered 749 * 2 = high-to-low edge triggered 750 * 4 = active high level-sensitive 751 * 8 = active low level-sensitive 752 * bits[15:8] PPI interrupt cpu mask 753 * Each bit corresponds to each of the 8 possible cpus 754 * attached to the GIC. A bit set to '1' indicated 755 * the interrupt is wired to that CPU. 756 */ 757 switch (cells[0]) { 758 case 0: 759 irq = GIC_FIRST_SPI + cells[1]; 760 /* SPI irq is checked later. */ 761 break; 762 case 1: 763 irq = GIC_FIRST_PPI + cells[1]; 764 if (irq > GIC_LAST_PPI) { 765 device_printf(dev, "unsupported PPI interrupt " 766 "number %u\n", cells[1]); 767 return (EINVAL); 768 } 769 break; 770 default: 771 device_printf(dev, "unsupported interrupt type " 772 "configuration %u\n", cells[0]); 773 return (EINVAL); 774 } |
731 | 775 |
732 case INTR_IRQ_NSPC_IPI: 733 *irqp = num + GIC_FIRST_SGI; 734 return (*irqp < GIC_LAST_SGI ? 0 : EINVAL); | 776 tripol = cells[2] & 0xff; 777 if (tripol & 0xf0 || (tripol & 0x0a && cells[0] == 0)) 778 device_printf(dev, "unsupported trigger/polarity " 779 "configuration 0x%02x\n", tripol); |
735 | 780 |
736 default: 737 return (EINVAL); | 781 *irqp = irq; 782 *polp = INTR_POLARITY_CONFORM; 783 *trigp = tripol & 0x03 ? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL; 784 return (0); |
738 } | 785 } |
786 return (EINVAL); |
|
739} | 787} |
788#endif |
|
740 741static int | 789 790static int |
742gic_map_nspc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp) | 791gic_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp, 792 enum intr_polarity *polp, enum intr_trigger *trigp) |
743{ | 793{ |
744 int error; 745 746 error = gic_irq_from_nspc(sc, isrc->isrc_nspc_type, isrc->isrc_nspc_num, 747 irqp); 748 if (error != 0) 749 return (error); 750 return (gic_attach_isrc(sc, isrc, *irqp)); 751} 752 753#ifdef FDT 754static int 755gic_map_fdt(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp) 756{ 757 u_int irq, tripol; 758 enum intr_trigger trig; | 794 u_int irq; |
759 enum intr_polarity pol; | 795 enum intr_polarity pol; |
760 int error; | 796 enum intr_trigger trig; 797 struct arm_gic_softc *sc; |
761 | 798 |
762 if (isrc->isrc_ncells == 1) { 763 irq = isrc->isrc_cells[0]; 764 pol = INTR_POLARITY_CONFORM; 765 trig = INTR_TRIGGER_CONFORM; 766 } else if (isrc->isrc_ncells == 3) { 767 if (isrc->isrc_cells[0] == 0) 768 irq = isrc->isrc_cells[1] + GIC_FIRST_SPI; 769 else 770 irq = isrc->isrc_cells[1] + GIC_FIRST_PPI; 771 772 /* 773 * In intr[2], bits[3:0] are trigger type and level flags. 774 * 1 = low-to-high edge triggered 775 * 2 = high-to-low edge triggered 776 * 4 = active high level-sensitive 777 * 8 = active low level-sensitive 778 * The hardware only supports active-high-level or rising-edge. 779 */ 780 tripol = isrc->isrc_cells[2]; 781 if (tripol & 0x0a && irq >= GIC_FIRST_SPI) { 782 device_printf(sc->gic_dev, 783 "unsupported trigger/polarity configuration " 784 "0x%02x\n", tripol & 0x0f); 785 } 786 pol = INTR_POLARITY_CONFORM; 787 if (tripol & 0x03) 788 trig = INTR_TRIGGER_EDGE; 789 else 790 trig = INTR_TRIGGER_LEVEL; 791 } else | 799 sc = device_get_softc(dev); 800 switch (data->type) { 801#ifdef FDT 802 case INTR_MAP_DATA_FDT: 803 if (gic_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq, 804 &pol, &trig) != 0) 805 return (EINVAL); 806 break; 807#endif 808 default: |
792 return (EINVAL); | 809 return (EINVAL); |
810 } |
|
793 794 if (irq >= sc->nirqs) 795 return (EINVAL); | 811 812 if (irq >= sc->nirqs) 813 return (EINVAL); |
814 if (pol != INTR_POLARITY_CONFORM && pol != INTR_POLARITY_LOW && 815 pol != INTR_POLARITY_HIGH) 816 return (EINVAL); 817 if (trig != INTR_TRIGGER_CONFORM && trig != INTR_TRIGGER_EDGE && 818 trig != INTR_TRIGGER_LEVEL) 819 return (EINVAL); |
|
796 | 820 |
797 error = gic_attach_isrc(sc, isrc, irq); 798 if (error != 0) 799 return (error); 800 801 isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN; 802 isrc->isrc_nspc_num = irq; 803 isrc->isrc_trig = trig; 804 isrc->isrc_pol = pol; 805 | |
806 *irqp = irq; | 821 *irqp = irq; |
822 if (polp != NULL) 823 *polp = pol; 824 if (trigp != NULL) 825 *trigp = trig; |
|
807 return (0); 808} | 826 return (0); 827} |
809#endif | |
810 811static int | 828 829static int |
812arm_gic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu) | 830arm_gic_map_intr(device_t dev, struct intr_map_data *data, 831 struct intr_irqsrc **isrcp) |
813{ | 832{ |
814 struct arm_gic_softc *sc = device_get_softc(dev); 815 u_int irq; | |
816 int error; | 833 int error; |
834 u_int irq; 835 struct arm_gic_softc *sc; |
|
817 | 836 |
818 if (isrc->isrc_type == INTR_ISRCT_NAMESPACE) 819 error = gic_map_nspc(sc, isrc, &irq); 820#ifdef FDT 821 else if (isrc->isrc_type == INTR_ISRCT_FDT) 822 error = gic_map_fdt(sc, isrc, &irq); 823#endif 824 else 825 return (EINVAL); 826 827 if (error == 0) 828 *is_percpu = irq < GIC_FIRST_SPI ? TRUE : FALSE; | 837 error = gic_map_intr(dev, data, &irq, NULL, NULL); 838 if (error == 0) { 839 sc = device_get_softc(dev); 840 *isrcp = GIC_INTR_ISRC(sc, irq); 841 } |
829 return (error); 830} 831 | 842 return (error); 843} 844 |
832static void 833arm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc) | 845static int 846arm_gic_setup_intr(device_t dev, struct intr_irqsrc *isrc, 847 struct resource *res, struct intr_map_data *data) |
834{ 835 struct arm_gic_softc *sc = device_get_softc(dev); | 848{ 849 struct arm_gic_softc *sc = device_get_softc(dev); |
836 u_int irq = isrc->isrc_data; | 850 struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 851 u_int irq; 852 enum intr_trigger trig; 853 enum intr_polarity pol; |
837 | 854 |
838 if (isrc->isrc_trig == INTR_TRIGGER_CONFORM) 839 isrc->isrc_trig = INTR_TRIGGER_LEVEL; | 855 if (data == NULL) 856 return (ENOTSUP); |
840 | 857 |
858 /* Get config for resource. */ 859 if (gic_map_intr(dev, data, &irq, &pol, &trig)) 860 return (EINVAL); 861 862 if (gi->gi_irq != irq) 863 return (EINVAL); 864 865 /* Compare config if this is not first setup. */ 866 if (isrc->isrc_handlers != 0) { 867 if ((pol != INTR_POLARITY_CONFORM && pol != gi->gi_pol) || 868 (trig != INTR_TRIGGER_CONFORM && trig != gi->gi_trig)) 869 return (EINVAL); 870 else 871 return (0); 872 } 873 874 if (pol == INTR_POLARITY_CONFORM) 875 pol = INTR_POLARITY_LOW; /* just pick some */ 876 if (trig == INTR_TRIGGER_CONFORM) 877 trig = INTR_TRIGGER_EDGE; /* just pick some */ 878 879 gi->gi_pol = pol; 880 gi->gi_trig = trig; 881 |
|
841 /* 842 * XXX - In case that per CPU interrupt is going to be enabled in time 843 * when SMP is already started, we need some IPI call which 844 * enables it on others CPUs. Further, it's more complicated as 845 * pic_enable_source() and pic_disable_source() should act on 846 * per CPU basis only. Thus, it should be solved here somehow. 847 */ | 882 /* 883 * XXX - In case that per CPU interrupt is going to be enabled in time 884 * when SMP is already started, we need some IPI call which 885 * enables it on others CPUs. Further, it's more complicated as 886 * pic_enable_source() and pic_disable_source() should act on 887 * per CPU basis only. Thus, it should be solved here somehow. 888 */ |
848 if (isrc->isrc_flags & INTR_ISRCF_PERCPU) | 889 if (isrc->isrc_flags & INTR_ISRCF_PPI) |
849 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 850 | 890 CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); 891 |
851 gic_config(sc, irq, isrc->isrc_trig, isrc->isrc_pol); 852 arm_gic_bind(dev, isrc); | 892 gic_config(sc, gi->gi_irq, trig, pol); 893 arm_gic_bind_intr(dev, isrc); 894 return (0); |
853} 854 | 895} 896 |
855static void 856arm_gic_enable_source(device_t dev, struct intr_irqsrc *isrc) | 897static int 898arm_gic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, 899 struct resource *res, struct intr_map_data *data) |
857{ | 900{ |
858 struct arm_gic_softc *sc = device_get_softc(dev); 859 u_int irq = isrc->isrc_data; | 901 struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; |
860 | 902 |
861 arm_irq_memory_barrier(irq); 862 gic_irq_unmask(sc, irq); | 903 if (isrc->isrc_handlers == 0) { 904 gi->gi_pol = INTR_POLARITY_CONFORM; 905 gi->gi_trig = INTR_TRIGGER_CONFORM; 906 } 907 return (0); |
863} 864 865static void | 908} 909 910static void |
866arm_gic_disable_source(device_t dev, struct intr_irqsrc *isrc) | 911arm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc) |
867{ 868 struct arm_gic_softc *sc = device_get_softc(dev); | 912{ 913 struct arm_gic_softc *sc = device_get_softc(dev); |
869 u_int irq = isrc->isrc_data; | 914 struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; |
870 | 915 |
871 gic_irq_mask(sc, irq); | 916 arm_irq_memory_barrier(gi->gi_irq); 917 gic_irq_unmask(sc, gi->gi_irq); |
872} 873 | 918} 919 |
874static int 875arm_gic_unregister(device_t dev, struct intr_irqsrc *isrc) | 920static void 921arm_gic_disable_intr(device_t dev, struct intr_irqsrc *isrc) |
876{ 877 struct arm_gic_softc *sc = device_get_softc(dev); | 922{ 923 struct arm_gic_softc *sc = device_get_softc(dev); |
878 u_int irq = isrc->isrc_data; | 924 struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; |
879 | 925 |
880 return (gic_detach_isrc(sc, isrc, irq)); | 926 gic_irq_mask(sc, gi->gi_irq); |
881} 882 883static void 884arm_gic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 885{ 886 struct arm_gic_softc *sc = device_get_softc(dev); | 927} 928 929static void 930arm_gic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) 931{ 932 struct arm_gic_softc *sc = device_get_softc(dev); |
933 struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; |
|
887 | 934 |
888 arm_gic_disable_source(dev, isrc); 889 gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data); | 935 arm_gic_disable_intr(dev, isrc); 936 gic_c_write_4(sc, GICC_EOIR, gi->gi_irq); |
890} 891 892static void 893arm_gic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 894{ 895 896 arm_irq_memory_barrier(0); | 937} 938 939static void 940arm_gic_post_ithread(device_t dev, struct intr_irqsrc *isrc) 941{ 942 943 arm_irq_memory_barrier(0); |
897 arm_gic_enable_source(dev, isrc); | 944 arm_gic_enable_intr(dev, isrc); |
898} 899 900static void 901arm_gic_post_filter(device_t dev, struct intr_irqsrc *isrc) 902{ 903 struct arm_gic_softc *sc = device_get_softc(dev); | 945} 946 947static void 948arm_gic_post_filter(device_t dev, struct intr_irqsrc *isrc) 949{ 950 struct arm_gic_softc *sc = device_get_softc(dev); |
951 struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; |
|
904 905 /* EOI for edge-triggered done earlier. */ | 952 953 /* EOI for edge-triggered done earlier. */ |
906 if (isrc->isrc_trig == INTR_TRIGGER_EDGE) | 954 if (gi->gi_trig == INTR_TRIGGER_EDGE) |
907 return; 908 909 arm_irq_memory_barrier(0); | 955 return; 956 957 arm_irq_memory_barrier(0); |
910 gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data); | 958 gic_c_write_4(sc, GICC_EOIR, gi->gi_irq); |
911} 912 913static int | 959} 960 961static int |
914arm_gic_bind(device_t dev, struct intr_irqsrc *isrc) | 962arm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc) |
915{ 916 struct arm_gic_softc *sc = device_get_softc(dev); | 963{ 964 struct arm_gic_softc *sc = device_get_softc(dev); |
917 uint32_t irq = isrc->isrc_data; | 965 struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; |
918 | 966 |
919 if (irq < GIC_FIRST_SPI) | 967 if (gi->gi_irq < GIC_FIRST_SPI) |
920 return (EINVAL); 921 922 if (CPU_EMPTY(&isrc->isrc_cpu)) { 923 gic_irq_cpu = intr_irq_next_cpu(gic_irq_cpu, &all_cpus); 924 CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu); 925 } | 968 return (EINVAL); 969 970 if (CPU_EMPTY(&isrc->isrc_cpu)) { 971 gic_irq_cpu = intr_irq_next_cpu(gic_irq_cpu, &all_cpus); 972 CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu); 973 } |
926 return (gic_bind(sc, irq, &isrc->isrc_cpu)); | 974 return (gic_bind(sc, gi->gi_irq, &isrc->isrc_cpu)); |
927} 928 929#ifdef SMP 930static void | 975} 976 977#ifdef SMP 978static void |
931arm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus) | 979arm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, 980 u_int ipi) |
932{ 933 struct arm_gic_softc *sc = device_get_softc(dev); | 981{ 982 struct arm_gic_softc *sc = device_get_softc(dev); |
934 uint32_t irq, val = 0, i; | 983 struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; 984 uint32_t val = 0, i; |
935 | 985 |
936 irq = isrc->isrc_data; 937 | |
938 for (i = 0; i < MAXCPU; i++) 939 if (CPU_ISSET(i, &cpus)) 940 val |= 1 << (16 + i); 941 | 986 for (i = 0; i < MAXCPU; i++) 987 if (CPU_ISSET(i, &cpus)) 988 val |= 1 << (16 + i); 989 |
942 gic_d_write_4(sc, GICD_SGIR(0), val | irq); | 990 gic_d_write_4(sc, GICD_SGIR(0), val | gi->gi_irq); |
943} 944 945static int | 991} 992 993static int |
946arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc *isrc) | 994arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) |
947{ 948 struct arm_gic_softc *sc = device_get_softc(dev); | 995{ 996 struct arm_gic_softc *sc = device_get_softc(dev); |
949 u_int irq; 950 int error; | |
951 | 997 |
952 error = gic_map_nspc(sc, isrc, &irq); 953 if (error != 0) 954 return (error); 955 sgi_to_ipi[irq - GIC_FIRST_SGI] = ipi; | 998 if (sgi_first_unused > GIC_LAST_SGI) 999 return (ENOSPC); 1000 1001 *isrcp = GIC_INTR_ISRC(sc, sgi_first_unused); 1002 sgi_to_ipi[sgi_first_unused++] = ipi; |
956 return (0); 957} 958#endif 959#else 960static int 961arm_gic_next_irq(struct arm_gic_softc *sc, int last_irq) 962{ 963 uint32_t active_irq; --- 202 unchanged lines hidden (view full) --- 1166#endif /* ARM_INTRNG */ 1167 1168static device_method_t arm_gic_methods[] = { 1169 /* Device interface */ 1170 DEVMETHOD(device_probe, arm_gic_probe), 1171 DEVMETHOD(device_attach, arm_gic_attach), 1172#ifdef ARM_INTRNG 1173 /* Interrupt controller interface */ | 1003 return (0); 1004} 1005#endif 1006#else 1007static int 1008arm_gic_next_irq(struct arm_gic_softc *sc, int last_irq) 1009{ 1010 uint32_t active_irq; --- 202 unchanged lines hidden (view full) --- 1213#endif /* ARM_INTRNG */ 1214 1215static device_method_t arm_gic_methods[] = { 1216 /* Device interface */ 1217 DEVMETHOD(device_probe, arm_gic_probe), 1218 DEVMETHOD(device_attach, arm_gic_attach), 1219#ifdef ARM_INTRNG 1220 /* Interrupt controller interface */ |
1174 DEVMETHOD(pic_disable_source, arm_gic_disable_source), | 1221 DEVMETHOD(pic_disable_intr, arm_gic_disable_intr), |
1175 DEVMETHOD(pic_enable_intr, arm_gic_enable_intr), | 1222 DEVMETHOD(pic_enable_intr, arm_gic_enable_intr), |
1176 DEVMETHOD(pic_enable_source, arm_gic_enable_source), | 1223 DEVMETHOD(pic_map_intr, arm_gic_map_intr), 1224 DEVMETHOD(pic_setup_intr, arm_gic_setup_intr), 1225 DEVMETHOD(pic_teardown_intr, arm_gic_teardown_intr), |
1177 DEVMETHOD(pic_post_filter, arm_gic_post_filter), 1178 DEVMETHOD(pic_post_ithread, arm_gic_post_ithread), 1179 DEVMETHOD(pic_pre_ithread, arm_gic_pre_ithread), | 1226 DEVMETHOD(pic_post_filter, arm_gic_post_filter), 1227 DEVMETHOD(pic_post_ithread, arm_gic_post_ithread), 1228 DEVMETHOD(pic_pre_ithread, arm_gic_pre_ithread), |
1180 DEVMETHOD(pic_register, arm_gic_register), 1181 DEVMETHOD(pic_unregister, arm_gic_unregister), | |
1182#ifdef SMP | 1229#ifdef SMP |
1183 DEVMETHOD(pic_bind, arm_gic_bind), | 1230 DEVMETHOD(pic_bind_intr, arm_gic_bind_intr), |
1184 DEVMETHOD(pic_init_secondary, arm_gic_init_secondary), 1185 DEVMETHOD(pic_ipi_send, arm_gic_ipi_send), 1186 DEVMETHOD(pic_ipi_setup, arm_gic_ipi_setup), 1187#endif 1188#endif 1189 { 0, 0 } 1190}; 1191 --- 12 unchanged lines hidden --- | 1231 DEVMETHOD(pic_init_secondary, arm_gic_init_secondary), 1232 DEVMETHOD(pic_ipi_send, arm_gic_ipi_send), 1233 DEVMETHOD(pic_ipi_setup, arm_gic_ipi_setup), 1234#endif 1235#endif 1236 { 0, 0 } 1237}; 1238 --- 12 unchanged lines hidden --- |