Index: head/sys/arm/arm/gic.c =================================================================== --- head/sys/arm/arm/gic.c +++ head/sys/arm/arm/gic.c @@ -36,8 +36,6 @@ #include "opt_platform.h" -#include "opt_platform.h" - #include #include #include @@ -118,13 +116,20 @@ #endif #ifdef ARM_INTRNG +struct gic_irqsrc { + struct intr_irqsrc gi_isrc; + uint32_t gi_irq; + enum intr_polarity gi_pol; + enum intr_trigger gi_trig; +}; + static u_int gic_irq_cpu; static int arm_gic_intr(void *); -static int arm_gic_bind(device_t dev, struct intr_irqsrc *isrc); +static int arm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc); #ifdef SMP u_int sgi_to_ipi[GIC_LAST_SGI - GIC_FIRST_SGI + 1]; -#define ISRC_IPI(isrc) sgi_to_ipi[isrc->isrc_data - GIC_FIRST_SGI] +u_int sgi_first_unused = GIC_FIRST_SGI; #endif #endif @@ -132,7 +137,7 @@ device_t gic_dev; #ifdef ARM_INTRNG void * gic_intrhand; - struct intr_irqsrc ** gic_irqs; + struct gic_irqsrc * gic_irqs; #endif struct resource * gic_res[3]; bus_space_tag_t gic_c_bst; @@ -147,6 +152,10 @@ #endif }; +#ifdef ARM_INTRNG +#define GIC_INTR_ISRC(sc, irq) (&sc->gic_irqs[irq].gi_isrc) +#endif + static struct resource_spec arm_gic_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Distributor registers */ { SYS_RES_MEMORY, 1, RF_ACTIVE }, /* CPU Interrupt Intf. registers */ @@ -243,7 +252,7 @@ /* Unmask attached SGI interrupts. */ for (irq = GIC_FIRST_SGI; irq <= GIC_LAST_SGI; irq++) { - isrc = sc->gic_irqs[irq]; + isrc = GIC_INTR_ISRC(sc, irq); if (isrc != NULL && isrc->isrc_handlers != 0) { CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); gic_irq_unmask(sc, irq); @@ -252,7 +261,7 @@ /* Unmask attached PPI interrupts. */ for (irq = GIC_FIRST_PPI; irq <= GIC_LAST_PPI; irq++) { - isrc = sc->gic_irqs[irq]; + isrc = GIC_INTR_ISRC(sc, irq); if (isrc == NULL || isrc->isrc_handlers == 0) continue; if (isrc->isrc_flags & INTR_ISRCF_BOUND) { @@ -369,6 +378,46 @@ return (0); #endif } + +static int +arm_gic_register_isrcs(struct arm_gic_softc *sc, uint32_t num) +{ + int error; + uint32_t irq; + struct gic_irqsrc *irqs; + struct intr_irqsrc *isrc; + const char *name; + + irqs = malloc(num * sizeof(struct gic_irqsrc), M_DEVBUF, + M_WAITOK | M_ZERO); + + name = device_get_nameunit(sc->gic_dev); + for (irq = 0; irq < num; irq++) { + irqs[irq].gi_irq = irq; + irqs[irq].gi_pol = INTR_POLARITY_CONFORM; + irqs[irq].gi_trig = INTR_TRIGGER_CONFORM; + + isrc = &irqs[irq].gi_isrc; + if (irq <= GIC_LAST_SGI) { + error = intr_isrc_register(isrc, sc->gic_dev, + INTR_ISRCF_IPI, "%s,i%u", name, irq - GIC_FIRST_SGI); + } else if (irq <= GIC_LAST_PPI) { + error = intr_isrc_register(isrc, sc->gic_dev, + INTR_ISRCF_PPI, "%s,p%u", name, irq - GIC_FIRST_PPI); + } else { + error = intr_isrc_register(isrc, sc->gic_dev, 0, + "%s,s%u", name, irq - GIC_FIRST_SPI); + } + if (error != 0) { + /* XXX call intr_isrc_deregister() */ + free(irqs, M_DEVBUF); + return (error); + } + } + sc->gic_irqs = irqs; + sc->nirqs = num; + return (0); +} #endif static int @@ -376,7 +425,7 @@ { struct arm_gic_softc *sc; int i; - uint32_t icciidr, mask; + uint32_t icciidr, mask, nirqs; #ifdef ARM_INTRNG phandle_t pxref; intptr_t xref = gic_xref(dev); @@ -410,13 +459,17 @@ gic_d_write_4(sc, GICD_CTLR, 0x00); /* Get the number of interrupts */ - sc->nirqs = gic_d_read_4(sc, GICD_TYPER); - sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1); + nirqs = gic_d_read_4(sc, GICD_TYPER); + nirqs = 32 * ((nirqs & 0x1f) + 1); #ifdef ARM_INTRNG - sc->gic_irqs = malloc(sc->nirqs * sizeof (*sc->gic_irqs), M_DEVBUF, - M_WAITOK | M_ZERO); + if (arm_gic_register_isrcs(sc, nirqs)) { + device_printf(dev, "could not register irqs\n"); + goto cleanup; + } #else + sc->nirqs = nirqs; + /* Set up function pointers */ arm_post_filter = gic_post_filter; arm_config_irq = gic_config_irq; @@ -496,20 +549,20 @@ if (intr_pic_claim_root(dev, xref, arm_gic_intr, sc, GIC_LAST_SGI - GIC_FIRST_SGI + 1) != 0) { device_printf(dev, "could not set PIC as a root\n"); - intr_pic_unregister(dev, xref); + intr_pic_deregister(dev, xref); goto cleanup; } } else { if (sc->gic_res[2] == NULL) { device_printf(dev, "not root PIC must have defined interrupt\n"); - intr_pic_unregister(dev, xref); + intr_pic_deregister(dev, xref); goto cleanup; } if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_CLK, arm_gic_intr, NULL, sc, &sc->gic_intrhand)) { device_printf(dev, "could not setup irq handler\n"); - intr_pic_unregister(dev, xref); + intr_pic_deregister(dev, xref); goto cleanup; } } @@ -533,7 +586,7 @@ arm_gic_intr(void *arg) { struct arm_gic_softc *sc = arg; - struct intr_irqsrc *isrc; + struct gic_irqsrc *gi; uint32_t irq_active_reg, irq; struct trapframe *tf; @@ -569,14 +622,7 @@ tf = curthread->td_intr_frame; dispatch_irq: - isrc = sc->gic_irqs[irq]; - if (isrc == NULL) { - device_printf(sc->gic_dev, "Stray interrupt %u detected\n", irq); - gic_irq_mask(sc, irq); - gic_c_write_4(sc, GICC_EOIR, irq_active_reg); - goto next_irq; - } - + gi = sc->gic_irqs + irq; /* * Note that GIC_FIRST_SGI is zero and is not used in 'if' statement * as compiler complains that comparing u_int >= 0 is always true. @@ -585,7 +631,7 @@ #ifdef SMP /* Call EOI for all IPI before dispatch. */ gic_c_write_4(sc, GICC_EOIR, irq_active_reg); - intr_ipi_dispatch(ISRC_IPI(isrc), tf); + intr_ipi_dispatch(sgi_to_ipi[gi->gi_irq], tf); goto next_irq; #else device_printf(sc->gic_dev, "SGI %u on UP system detected\n", @@ -598,10 +644,15 @@ #ifdef GIC_DEBUG_SPURIOUS sc->last_irq[PCPU_GET(cpuid)] = irq; #endif - if (isrc->isrc_trig == INTR_TRIGGER_EDGE) + if (gi->gi_trig == INTR_TRIGGER_EDGE) gic_c_write_4(sc, GICC_EOIR, irq_active_reg); - intr_irq_dispatch(isrc, tf); + if (intr_isrc_dispatch(&gi->gi_isrc, tf) != 0) { + gic_irq_mask(sc, irq); + if (gi->gi_trig != INTR_TRIGGER_EDGE) + gic_c_write_4(sc, GICC_EOIR, irq_active_reg); + device_printf(sc->gic_dev, "Stray irq %u disabled\n", irq); + } next_irq: arm_irq_memory_barrier(irq); @@ -613,52 +664,6 @@ return (FILTER_HANDLED); } -static int -gic_attach_isrc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int irq) -{ - const char *name; - - /* - * 1. The link between ISRC and controller must be set atomically. - * 2. Just do things only once in rare case when consumers - * of shared interrupt came here at the same moment. - */ - mtx_lock_spin(&sc->mutex); - if (sc->gic_irqs[irq] != NULL) { - mtx_unlock_spin(&sc->mutex); - return (sc->gic_irqs[irq] == isrc ? 0 : EEXIST); - } - sc->gic_irqs[irq] = isrc; - isrc->isrc_data = irq; - mtx_unlock_spin(&sc->mutex); - - name = device_get_nameunit(sc->gic_dev); - if (irq <= GIC_LAST_SGI) - intr_irq_set_name(isrc, "%s,i%u", name, irq - GIC_FIRST_SGI); - else if (irq <= GIC_LAST_PPI) - intr_irq_set_name(isrc, "%s,p%u", name, irq - GIC_FIRST_PPI); - else - intr_irq_set_name(isrc, "%s,s%u", name, irq - GIC_FIRST_SPI); - return (0); -} - -static int -gic_detach_isrc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int irq) -{ - - mtx_lock_spin(&sc->mutex); - if (sc->gic_irqs[irq] != isrc) { - mtx_unlock_spin(&sc->mutex); - return (sc->gic_irqs[irq] == NULL ? 0 : EINVAL); - } - sc->gic_irqs[irq] = NULL; - isrc->isrc_data = 0; - mtx_unlock_spin(&sc->mutex); - - intr_irq_set_name(isrc, ""); - return (0); -} - static void gic_config(struct arm_gic_softc *sc, u_int irq, enum intr_trigger trig, enum intr_polarity pol) @@ -716,127 +721,163 @@ return (0); } +#ifdef FDT static int -gic_irq_from_nspc(struct arm_gic_softc *sc, u_int type, u_int num, u_int *irqp) +gic_map_fdt(device_t dev, u_int ncells, pcell_t *cells, u_int *irqp, + enum intr_polarity *polp, enum intr_trigger *trigp) { - switch (type) { - case INTR_IRQ_NSPC_PLAIN: - *irqp = num; - return (*irqp < sc->nirqs ? 0 : EINVAL); - - case INTR_IRQ_NSPC_IRQ: - *irqp = num + GIC_FIRST_PPI; - return (*irqp < sc->nirqs ? 0 : EINVAL); - - case INTR_IRQ_NSPC_IPI: - *irqp = num + GIC_FIRST_SGI; - return (*irqp < GIC_LAST_SGI ? 0 : EINVAL); - - default: - return (EINVAL); + if (ncells == 1) { + *irqp = cells[0]; + *polp = INTR_POLARITY_CONFORM; + *trigp = INTR_TRIGGER_CONFORM; + return (0); } -} + if (ncells == 3) { + u_int irq, tripol; -static int -gic_map_nspc(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp) -{ - int error; + /* + * The 1st cell is the interrupt type: + * 0 = SPI + * 1 = PPI + * The 2nd cell contains the interrupt number: + * [0 - 987] for SPI + * [0 - 15] for PPI + * The 3rd cell is the flags, encoded as follows: + * bits[3:0] trigger type and level flags + * 1 = low-to-high edge triggered + * 2 = high-to-low edge triggered + * 4 = active high level-sensitive + * 8 = active low level-sensitive + * bits[15:8] PPI interrupt cpu mask + * Each bit corresponds to each of the 8 possible cpus + * attached to the GIC. A bit set to '1' indicated + * the interrupt is wired to that CPU. + */ + switch (cells[0]) { + case 0: + irq = GIC_FIRST_SPI + cells[1]; + /* SPI irq is checked later. */ + break; + case 1: + irq = GIC_FIRST_PPI + cells[1]; + if (irq > GIC_LAST_PPI) { + device_printf(dev, "unsupported PPI interrupt " + "number %u\n", cells[1]); + return (EINVAL); + } + break; + default: + device_printf(dev, "unsupported interrupt type " + "configuration %u\n", cells[0]); + return (EINVAL); + } - error = gic_irq_from_nspc(sc, isrc->isrc_nspc_type, isrc->isrc_nspc_num, - irqp); - if (error != 0) - return (error); - return (gic_attach_isrc(sc, isrc, *irqp)); + tripol = cells[2] & 0xff; + if (tripol & 0xf0 || (tripol & 0x0a && cells[0] == 0)) + device_printf(dev, "unsupported trigger/polarity " + "configuration 0x%02x\n", tripol); + + *irqp = irq; + *polp = INTR_POLARITY_CONFORM; + *trigp = tripol & 0x03 ? INTR_TRIGGER_EDGE : INTR_TRIGGER_LEVEL; + return (0); + } + return (EINVAL); } +#endif -#ifdef FDT static int -gic_map_fdt(struct arm_gic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp) +gic_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp, + enum intr_polarity *polp, enum intr_trigger *trigp) { - u_int irq, tripol; - enum intr_trigger trig; + u_int irq; enum intr_polarity pol; - int error; - - if (isrc->isrc_ncells == 1) { - irq = isrc->isrc_cells[0]; - pol = INTR_POLARITY_CONFORM; - trig = INTR_TRIGGER_CONFORM; - } else if (isrc->isrc_ncells == 3) { - if (isrc->isrc_cells[0] == 0) - irq = isrc->isrc_cells[1] + GIC_FIRST_SPI; - else - irq = isrc->isrc_cells[1] + GIC_FIRST_PPI; + enum intr_trigger trig; + struct arm_gic_softc *sc; - /* - * In intr[2], bits[3:0] are trigger type and level flags. - * 1 = low-to-high edge triggered - * 2 = high-to-low edge triggered - * 4 = active high level-sensitive - * 8 = active low level-sensitive - * The hardware only supports active-high-level or rising-edge. - */ - tripol = isrc->isrc_cells[2]; - if (tripol & 0x0a && irq >= GIC_FIRST_SPI) { - device_printf(sc->gic_dev, - "unsupported trigger/polarity configuration " - "0x%02x\n", tripol & 0x0f); - } - pol = INTR_POLARITY_CONFORM; - if (tripol & 0x03) - trig = INTR_TRIGGER_EDGE; - else - trig = INTR_TRIGGER_LEVEL; - } else + sc = device_get_softc(dev); + switch (data->type) { +#ifdef FDT + case INTR_MAP_DATA_FDT: + if (gic_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq, + &pol, &trig) != 0) + return (EINVAL); + break; +#endif + default: return (EINVAL); + } if (irq >= sc->nirqs) return (EINVAL); - - error = gic_attach_isrc(sc, isrc, irq); - if (error != 0) - return (error); - - isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN; - isrc->isrc_nspc_num = irq; - isrc->isrc_trig = trig; - isrc->isrc_pol = pol; + if (pol != INTR_POLARITY_CONFORM && pol != INTR_POLARITY_LOW && + pol != INTR_POLARITY_HIGH) + return (EINVAL); + if (trig != INTR_TRIGGER_CONFORM && trig != INTR_TRIGGER_EDGE && + trig != INTR_TRIGGER_LEVEL) + return (EINVAL); *irqp = irq; + if (polp != NULL) + *polp = pol; + if (trigp != NULL) + *trigp = trig; return (0); } -#endif static int -arm_gic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu) +arm_gic_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) { - struct arm_gic_softc *sc = device_get_softc(dev); - u_int irq; int error; + u_int irq; + struct arm_gic_softc *sc; - if (isrc->isrc_type == INTR_ISRCT_NAMESPACE) - error = gic_map_nspc(sc, isrc, &irq); -#ifdef FDT - else if (isrc->isrc_type == INTR_ISRCT_FDT) - error = gic_map_fdt(sc, isrc, &irq); -#endif - else - return (EINVAL); - - if (error == 0) - *is_percpu = irq < GIC_FIRST_SPI ? TRUE : FALSE; + error = gic_map_intr(dev, data, &irq, NULL, NULL); + if (error == 0) { + sc = device_get_softc(dev); + *isrcp = GIC_INTR_ISRC(sc, irq); + } return (error); } -static void -arm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc) +static int +arm_gic_setup_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) { struct arm_gic_softc *sc = device_get_softc(dev); - u_int irq = isrc->isrc_data; + struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; + u_int irq; + enum intr_trigger trig; + enum intr_polarity pol; + + if (data == NULL) + return (ENOTSUP); + + /* Get config for resource. */ + if (gic_map_intr(dev, data, &irq, &pol, &trig)) + return (EINVAL); + + if (gi->gi_irq != irq) + return (EINVAL); + + /* Compare config if this is not first setup. */ + if (isrc->isrc_handlers != 0) { + if ((pol != INTR_POLARITY_CONFORM && pol != gi->gi_pol) || + (trig != INTR_TRIGGER_CONFORM && trig != gi->gi_trig)) + return (EINVAL); + else + return (0); + } + + if (pol == INTR_POLARITY_CONFORM) + pol = INTR_POLARITY_LOW; /* just pick some */ + if (trig == INTR_TRIGGER_CONFORM) + trig = INTR_TRIGGER_EDGE; /* just pick some */ - if (isrc->isrc_trig == INTR_TRIGGER_CONFORM) - isrc->isrc_trig = INTR_TRIGGER_LEVEL; + gi->gi_pol = pol; + gi->gi_trig = trig; /* * XXX - In case that per CPU interrupt is going to be enabled in time @@ -845,48 +886,54 @@ * pic_enable_source() and pic_disable_source() should act on * per CPU basis only. Thus, it should be solved here somehow. */ - if (isrc->isrc_flags & INTR_ISRCF_PERCPU) + if (isrc->isrc_flags & INTR_ISRCF_PPI) CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu); - gic_config(sc, irq, isrc->isrc_trig, isrc->isrc_pol); - arm_gic_bind(dev, isrc); + gic_config(sc, gi->gi_irq, trig, pol); + arm_gic_bind_intr(dev, isrc); + return (0); } -static void -arm_gic_enable_source(device_t dev, struct intr_irqsrc *isrc) +static int +arm_gic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) { - struct arm_gic_softc *sc = device_get_softc(dev); - u_int irq = isrc->isrc_data; + struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; - arm_irq_memory_barrier(irq); - gic_irq_unmask(sc, irq); + if (isrc->isrc_handlers == 0) { + gi->gi_pol = INTR_POLARITY_CONFORM; + gi->gi_trig = INTR_TRIGGER_CONFORM; + } + return (0); } static void -arm_gic_disable_source(device_t dev, struct intr_irqsrc *isrc) +arm_gic_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); - u_int irq = isrc->isrc_data; + struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; - gic_irq_mask(sc, irq); + arm_irq_memory_barrier(gi->gi_irq); + gic_irq_unmask(sc, gi->gi_irq); } -static int -arm_gic_unregister(device_t dev, struct intr_irqsrc *isrc) +static void +arm_gic_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); - u_int irq = isrc->isrc_data; + struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; - return (gic_detach_isrc(sc, isrc, irq)); + gic_irq_mask(sc, gi->gi_irq); } static void arm_gic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); + struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; - arm_gic_disable_source(dev, isrc); - gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data); + arm_gic_disable_intr(dev, isrc); + gic_c_write_4(sc, GICC_EOIR, gi->gi_irq); } static void @@ -894,65 +941,65 @@ { arm_irq_memory_barrier(0); - arm_gic_enable_source(dev, isrc); + arm_gic_enable_intr(dev, isrc); } static void arm_gic_post_filter(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); + struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; /* EOI for edge-triggered done earlier. */ - if (isrc->isrc_trig == INTR_TRIGGER_EDGE) + if (gi->gi_trig == INTR_TRIGGER_EDGE) return; arm_irq_memory_barrier(0); - gic_c_write_4(sc, GICC_EOIR, isrc->isrc_data); + gic_c_write_4(sc, GICC_EOIR, gi->gi_irq); } static int -arm_gic_bind(device_t dev, struct intr_irqsrc *isrc) +arm_gic_bind_intr(device_t dev, struct intr_irqsrc *isrc) { struct arm_gic_softc *sc = device_get_softc(dev); - uint32_t irq = isrc->isrc_data; + struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; - if (irq < GIC_FIRST_SPI) + if (gi->gi_irq < GIC_FIRST_SPI) return (EINVAL); if (CPU_EMPTY(&isrc->isrc_cpu)) { gic_irq_cpu = intr_irq_next_cpu(gic_irq_cpu, &all_cpus); CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu); } - return (gic_bind(sc, irq, &isrc->isrc_cpu)); + return (gic_bind(sc, gi->gi_irq, &isrc->isrc_cpu)); } #ifdef SMP static void -arm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus) +arm_gic_ipi_send(device_t dev, struct intr_irqsrc *isrc, cpuset_t cpus, + u_int ipi) { struct arm_gic_softc *sc = device_get_softc(dev); - uint32_t irq, val = 0, i; - - irq = isrc->isrc_data; + struct gic_irqsrc *gi = (struct gic_irqsrc *)isrc; + uint32_t val = 0, i; for (i = 0; i < MAXCPU; i++) if (CPU_ISSET(i, &cpus)) val |= 1 << (16 + i); - gic_d_write_4(sc, GICD_SGIR(0), val | irq); + gic_d_write_4(sc, GICD_SGIR(0), val | gi->gi_irq); } static int -arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc *isrc) +arm_gic_ipi_setup(device_t dev, u_int ipi, struct intr_irqsrc **isrcp) { struct arm_gic_softc *sc = device_get_softc(dev); - u_int irq; - int error; - error = gic_map_nspc(sc, isrc, &irq); - if (error != 0) - return (error); - sgi_to_ipi[irq - GIC_FIRST_SGI] = ipi; + if (sgi_first_unused > GIC_LAST_SGI) + return (ENOSPC); + + *isrcp = GIC_INTR_ISRC(sc, sgi_first_unused); + sgi_to_ipi[sgi_first_unused++] = ipi; return (0); } #endif @@ -1171,16 +1218,16 @@ DEVMETHOD(device_attach, arm_gic_attach), #ifdef ARM_INTRNG /* Interrupt controller interface */ - DEVMETHOD(pic_disable_source, arm_gic_disable_source), + DEVMETHOD(pic_disable_intr, arm_gic_disable_intr), DEVMETHOD(pic_enable_intr, arm_gic_enable_intr), - DEVMETHOD(pic_enable_source, arm_gic_enable_source), + DEVMETHOD(pic_map_intr, arm_gic_map_intr), + DEVMETHOD(pic_setup_intr, arm_gic_setup_intr), + DEVMETHOD(pic_teardown_intr, arm_gic_teardown_intr), DEVMETHOD(pic_post_filter, arm_gic_post_filter), DEVMETHOD(pic_post_ithread, arm_gic_post_ithread), DEVMETHOD(pic_pre_ithread, arm_gic_pre_ithread), - DEVMETHOD(pic_register, arm_gic_register), - DEVMETHOD(pic_unregister, arm_gic_unregister), #ifdef SMP - DEVMETHOD(pic_bind, arm_gic_bind), + DEVMETHOD(pic_bind_intr, arm_gic_bind_intr), DEVMETHOD(pic_init_secondary, arm_gic_init_secondary), DEVMETHOD(pic_ipi_send, arm_gic_ipi_send), DEVMETHOD(pic_ipi_setup, arm_gic_ipi_setup), Index: head/sys/arm/arm/machdep_intr.c =================================================================== --- head/sys/arm/arm/machdep_intr.c +++ head/sys/arm/arm/machdep_intr.c @@ -1,8 +1,6 @@ -/* $NetBSD: intr.c,v 1.12 2003/07/15 00:24:41 lukem Exp $ */ - /*- - * Copyright (c) 2004 Olivier Houchard. - * Copyright (c) 1994-1998 Mark Brinicombe. + * Copyright (c) 2015-2016 Svatopluk Kraus + * Copyright (c) 2015-2016 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -13,27 +11,18 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Mark Brinicombe - * for the NetBSD Project. - * 4. The name of the company nor the name of the author may be used to - * endorse or promote products derived from this software without specific - * prior written permission. - * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR - * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES - * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * Soft interrupt and other generic interrupt functions. */ #include "opt_platform.h" @@ -76,7 +65,6 @@ }; static struct intr_ipi ipi_sources[INTR_IPI_COUNT]; -u_int ipi_next_num; #endif #endif @@ -184,7 +172,7 @@ if (ii->ii_count == NULL) panic("%s: not setup IPI %u", __func__, ipi); - ii->ii_send(ii->ii_send_arg, cpus); + ii->ii_send(ii->ii_send_arg, cpus, ipi); } void @@ -211,11 +199,11 @@ * Send IPI thru interrupt controller. */ static void -pic_ipi_send(void *arg, cpuset_t cpus) +pic_ipi_send(void *arg, cpuset_t cpus, u_int ipi) { KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__)); - PIC_IPI_SEND(intr_irq_root_dev, arg, cpus); + PIC_IPI_SEND(intr_irq_root_dev, arg, cpus, ipi); } /* @@ -232,18 +220,11 @@ KASSERT(intr_irq_root_dev != NULL, ("%s: no root attached", __func__)); - isrc = intr_isrc_alloc(INTR_ISRCT_NAMESPACE, 0); - isrc->isrc_nspc_type = INTR_IRQ_NSPC_IPI; - isrc->isrc_nspc_num = ipi_next_num; - - error = PIC_IPI_SETUP(intr_irq_root_dev, ipi, isrc); + error = PIC_IPI_SETUP(intr_irq_root_dev, ipi, &isrc); if (error != 0) return (error); - ipi_next_num++; - - isrc->isrc_dev = intr_irq_root_dev; - isrc->isrc_handlers = 1; + isrc->isrc_handlers++; intr_ipi_setup(ipi, name, hand, arg, pic_ipi_send, isrc); return (0); } Index: head/sys/arm/arm/nexus.c =================================================================== --- head/sys/arm/arm/nexus.c +++ head/sys/arm/arm/nexus.c @@ -281,7 +281,8 @@ int ret = ENODEV; #ifdef ARM_INTRNG - ret = intr_irq_config(irq, trig, pol); + device_printf(dev, "bus_config_intr is obsolete and not supported!\n"); + ret = EOPNOTSUPP; #else if (arm_config_irq) ret = (*arm_config_irq)(irq, trig, pol); @@ -293,22 +294,23 @@ nexus_setup_intr(device_t dev, device_t child, struct resource *res, int flags, driver_filter_t *filt, driver_intr_t *intr, void *arg, void **cookiep) { +#ifndef ARM_INTRNG int irq; +#endif if ((rman_get_flags(res) & RF_SHAREABLE) == 0) flags |= INTR_EXCL; - for (irq = rman_get_start(res); irq <= rman_get_end(res); irq++) { #ifdef ARM_INTRNG - intr_irq_add_handler(child, filt, intr, arg, irq, flags, - cookiep); + return(intr_setup_irq(child, res, filt, intr, arg, flags, cookiep)); #else + for (irq = rman_get_start(res); irq <= rman_get_end(res); irq++) { arm_setup_irqhandler(device_get_nameunit(child), filt, intr, arg, irq, flags, cookiep); arm_unmask_irq(irq); -#endif } return (0); +#endif } static int @@ -316,7 +318,7 @@ { #ifdef ARM_INTRNG - return (intr_irq_remove_handler(child, rman_get_start(r), ih)); + return (intr_teardown_irq(child, r, ih)); #else return (arm_remove_irqhandler(rman_get_start(r), ih)); #endif @@ -328,7 +330,7 @@ void *cookie, const char *descr) { - return (intr_irq_describe(rman_get_start(irq), cookie, descr)); + return (intr_describe_irq(child, irq, cookie, descr)); } #ifdef SMP @@ -336,7 +338,7 @@ nexus_bind_intr(device_t dev, device_t child, struct resource *irq, int cpu) { - return (intr_irq_bind(rman_get_start(irq), cpu)); + return (intr_bind_irq(child, irq, cpu)); } #endif #endif Index: head/sys/arm/freescale/imx/imx_gpio.c =================================================================== --- head/sys/arm/freescale/imx/imx_gpio.c +++ head/sys/arm/freescale/imx/imx_gpio.c @@ -91,6 +91,15 @@ #define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT) #define NGPIO 32 +#ifdef ARM_INTRNG +struct gpio_irqsrc { + struct intr_irqsrc gi_isrc; + u_int gi_irq; + enum intr_polarity gi_pol; + enum intr_trigger gi_trig; +}; +#endif + struct imx51_gpio_softc { device_t dev; device_t sc_busdev; @@ -101,7 +110,9 @@ bus_space_handle_t sc_ioh; int gpio_npins; struct gpio_pin gpio_pins[NGPIO]; - struct intr_irqsrc *gpio_pic_irqsrc[NGPIO]; +#ifdef ARM_INTRNG + struct gpio_irqsrc gpio_pic_irqsrc[NGPIO]; +#endif }; static struct ofw_compat_data compat_data[] = { @@ -145,8 +156,30 @@ static int imx51_gpio_pin_toggle(device_t, uint32_t pin); #ifdef ARM_INTRNG +static int +gpio_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) +{ + struct imx51_gpio_softc *sc; + struct gpio_irqsrc *gi; + + sc = device_get_softc(dev); + if (isrc->isrc_handlers == 0) { + gi = (struct gpio_irqsrc *)isrc; + gi->gi_pol = INTR_POLARITY_CONFORM; + gi->gi_trig = INTR_TRIGGER_CONFORM; + + // XXX Not sure this is necessary + mtx_lock_spin(&sc->sc_mtx); + CLEAR4(sc, IMX_GPIO_IMR_REG, (1U << gi->gi_irq)); + WRITE4(sc, IMX_GPIO_ISR_REG, (1U << gi->gi_irq)); + mtx_unlock_spin(&sc->sc_mtx); + } + return (0); +} + /* - * this is teardown_intr + * this is mask_intr */ static void gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) @@ -155,55 +188,143 @@ u_int irq; sc = device_get_softc(dev); - irq = isrc->isrc_data; + irq = ((struct gpio_irqsrc *)isrc)->gi_irq; - // XXX Not sure this is necessary mtx_lock_spin(&sc->sc_mtx); CLEAR4(sc, IMX_GPIO_IMR_REG, (1U << irq)); - WRITE4(sc, IMX_GPIO_ISR_REG, (1U << irq)); mtx_unlock_spin(&sc->sc_mtx); } -/* - * this is mask_intr - */ -static void -gpio_pic_disable_source(device_t dev, struct intr_irqsrc *isrc) +static int +gpio_pic_map_fdt(device_t dev, u_int ncells, pcell_t *cells, u_int *irqp, + enum intr_polarity *polp, enum intr_trigger *trigp) { struct imx51_gpio_softc *sc; + u_int irq, tripol; + enum intr_polarity pol; + enum intr_trigger trig; sc = device_get_softc(dev); - mtx_lock_spin(&sc->sc_mtx); - CLEAR4(sc, IMX_GPIO_IMR_REG, (1U << isrc->isrc_data)); - mtx_unlock_spin(&sc->sc_mtx); + /* + * From devicetree/bindings/gpio/fsl-imx-gpio.txt: + * #interrupt-cells: 2. The first cell is the GPIO number. The second + * cell bits[3:0] is used to specify trigger type and level flags: + * 1 = low-to-high edge triggered. + * 2 = high-to-low edge triggered. + * 4 = active high level-sensitive. + * 8 = active low level-sensitive. + * We can do any single one of these modes, but nothing in combo. + */ + + if (ncells != 2) { + device_printf(sc->dev, "Invalid #interrupt-cells"); + return (EINVAL); + } + + irq = cells[0]; + tripol = cells[1]; + if (irq >= sc->gpio_npins) { + device_printf(sc->dev, "Invalid interrupt number %d", irq); + return (EINVAL); + } + switch (tripol) { + case 1: + trig = INTR_TRIGGER_EDGE; + pol = INTR_POLARITY_HIGH; + break; + case 2: + trig = INTR_TRIGGER_EDGE; + pol = INTR_POLARITY_LOW; + break; + case 4: + trig = INTR_TRIGGER_LEVEL; + pol = INTR_POLARITY_HIGH; + break; + case 8: + trig = INTR_TRIGGER_LEVEL; + pol = INTR_POLARITY_LOW; + break; + default: + device_printf(sc->dev, "unsupported trigger/polarity 0x%2x\n", + tripol); + return (ENOTSUP); + } + *irqp = irq; + if (polp != NULL) + *polp = pol; + if (trigp != NULL) + *trigp = trig; + return (0); } -/* - * this is setup_intr - */ -static void -gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) +static int +gpio_pic_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) +{ + int error; + u_int irq; + struct imx51_gpio_softc *sc; + + if (data->type != INTR_MAP_DATA_FDT) + return (ENOTSUP); + + error = gpio_pic_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq, + NULL, NULL); + if (error == 0) { + sc = device_get_softc(dev); + *isrcp = &sc->gpio_pic_irqsrc[irq].gi_isrc; + } + return (error); +} + +static int +gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) { struct imx51_gpio_softc *sc; - int icfg; + struct gpio_irqsrc *gi; + int error, icfg; u_int irq, reg, shift, wrk; + enum intr_trigger trig; + enum intr_polarity pol; sc = device_get_softc(dev); + gi = (struct gpio_irqsrc *)isrc; + + /* Get config for interrupt. */ + if (data == NULL || data->type != INTR_MAP_DATA_FDT) + return (ENOTSUP); + error = gpio_pic_map_fdt(dev, data->fdt.ncells, data->fdt.cells, &irq, + &pol, &trig); + if (error != 0) + return (error); + if (gi->gi_irq != irq) + return (EINVAL); - if (isrc->isrc_trig == INTR_TRIGGER_LEVEL) { - if (isrc->isrc_pol == INTR_POLARITY_LOW) + /* Compare config if this is not first setup. */ + if (isrc->isrc_handlers != 0) { + if (pol != gi->gi_pol || trig != gi->gi_trig) + return (EINVAL); + else + return (0); + } + + gi->gi_pol = pol; + gi->gi_trig = trig; + + if (trig == INTR_TRIGGER_LEVEL) { + if (pol == INTR_POLARITY_LOW) icfg = GPIO_ICR_COND_LOW; else icfg = GPIO_ICR_COND_HIGH; } else { - if (isrc->isrc_pol == INTR_POLARITY_HIGH) + if (pol == INTR_POLARITY_HIGH) icfg = GPIO_ICR_COND_FALL; else icfg = GPIO_ICR_COND_RISE; } - irq = isrc->isrc_data; if (irq < 16) { reg = IMX_GPIO_ICR1_REG; shift = 2 * irq; @@ -220,20 +341,23 @@ wrk |= icfg << shift; WRITE4(sc, reg, wrk); mtx_unlock_spin(&sc->sc_mtx); + return (0); } /* * this is unmask_intr */ static void -gpio_pic_enable_source(device_t dev, struct intr_irqsrc *isrc) +gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct imx51_gpio_softc *sc; + u_int irq; sc = device_get_softc(dev); + irq = ((struct gpio_irqsrc *)isrc)->gi_irq; mtx_lock_spin(&sc->sc_mtx); - SET4(sc, IMX_GPIO_IMR_REG, (1U << isrc->isrc_data)); + SET4(sc, IMX_GPIO_IMR_REG, (1U << irq)); mtx_unlock_spin(&sc->sc_mtx); } @@ -241,12 +365,14 @@ gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc) { struct imx51_gpio_softc *sc; + u_int irq; sc = device_get_softc(dev); + irq = ((struct gpio_irqsrc *)isrc)->gi_irq; arm_irq_memory_barrier(0); /* EOI. W1C reg so no r-m-w, no locking needed. */ - WRITE4(sc, IMX_GPIO_ISR_REG, (1U << isrc->isrc_data)); + WRITE4(sc, IMX_GPIO_ISR_REG, (1U << irq)); } static void @@ -254,119 +380,21 @@ { arm_irq_memory_barrier(0); - gpio_pic_enable_source(dev, isrc); + gpio_pic_enable_intr(dev, isrc); } static void gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { - gpio_pic_disable_source(dev, isrc); -} - -/* - * intrng calls this to make a new isrc known to us. - */ -static int -gpio_pic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu) -{ - struct imx51_gpio_softc *sc; - u_int irq, tripol; - - sc = device_get_softc(dev); - - /* - * From devicetree/bindings/gpio/fsl-imx-gpio.txt: - * #interrupt-cells: 2. The first cell is the GPIO number. The second - * cell bits[3:0] is used to specify trigger type and level flags: - * 1 = low-to-high edge triggered. - * 2 = high-to-low edge triggered. - * 4 = active high level-sensitive. - * 8 = active low level-sensitive. - * We can do any single one of these modes, but nothing in combo. - */ - - if (isrc->isrc_ncells != 2) { - device_printf(sc->dev, "Invalid #interrupt-cells"); - return (EINVAL); - } - - irq = isrc->isrc_cells[0]; - tripol = isrc->isrc_cells[1]; - if (irq >= sc->gpio_npins) { - device_printf(sc->dev, "Invalid interrupt number %d", irq); - return (EINVAL); - } - switch (tripol) - { - case 1: - isrc->isrc_trig = INTR_TRIGGER_EDGE; - isrc->isrc_pol = INTR_POLARITY_HIGH; - break; - case 2: - isrc->isrc_trig = INTR_TRIGGER_EDGE; - isrc->isrc_pol = INTR_POLARITY_LOW; - break; - case 4: - isrc->isrc_trig = INTR_TRIGGER_LEVEL; - isrc->isrc_pol = INTR_POLARITY_HIGH; - break; - case 8: - isrc->isrc_trig = INTR_TRIGGER_LEVEL; - isrc->isrc_pol = INTR_POLARITY_LOW; - break; - default: - device_printf(sc->dev, "unsupported trigger/polarity 0x%2x\n", - tripol); - return (ENOTSUP); - } - isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN; - isrc->isrc_nspc_num = irq; - - /* - * 1. The link between ISRC and controller must be set atomically. - * 2. Just do things only once in rare case when consumers - * of shared interrupt came here at the same moment. - */ - mtx_lock_spin(&sc->sc_mtx); - if (sc->gpio_pic_irqsrc[irq] != NULL) { - mtx_unlock_spin(&sc->sc_mtx); - return (sc->gpio_pic_irqsrc[irq] == isrc ? 0 : EEXIST); - } - sc->gpio_pic_irqsrc[irq] = isrc; - isrc->isrc_data = irq; - mtx_unlock_spin(&sc->sc_mtx); - - intr_irq_set_name(isrc, "%s,%u", device_get_nameunit(sc->dev), irq); - return (0); -} - -static int -gpio_pic_unregister(device_t dev, struct intr_irqsrc *isrc) -{ - struct imx51_gpio_softc *sc; - u_int irq; - - sc = device_get_softc(dev); - - mtx_lock_spin(&sc->sc_mtx); - irq = isrc->isrc_data; - if (sc->gpio_pic_irqsrc[irq] != isrc) { - mtx_unlock_spin(&sc->sc_mtx); - return (sc->gpio_pic_irqsrc[irq] == NULL ? 0 : EINVAL); - } - sc->gpio_pic_irqsrc[irq] = NULL; - isrc->isrc_data = 0; - mtx_unlock_spin(&sc->sc_mtx); - - intr_irq_set_name(isrc, ""); - return (0); + gpio_pic_disable_intr(dev, isrc); } static int gpio_pic_filter(void *arg) { struct imx51_gpio_softc *sc; + struct intr_irqsrc *isrc; uint32_t i, interrupts; sc = arg; @@ -377,14 +405,43 @@ for (i = 0; interrupts != 0; i++, interrupts >>= 1) { if ((interrupts & 0x1) == 0) continue; - if (sc->gpio_pic_irqsrc[i]) - intr_irq_dispatch(sc->gpio_pic_irqsrc[i], curthread->td_intr_frame); - else - device_printf(sc->dev, "spurious interrupt %d\n", i); + isrc = &sc->gpio_pic_irqsrc[i].gi_isrc; + if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) { + gpio_pic_disable_intr(sc->dev, isrc); + gpio_pic_post_filter(sc->dev, isrc); + device_printf(sc->dev, "Stray irq %u disabled\n", i); + } } return (FILTER_HANDLED); } + +/* + * register our isrcs into intrng to make it known about them. + */ +static int +gpio_pic_register_isrcs(struct imx51_gpio_softc *sc) +{ + int error; + uint32_t irq; + const char *name; + + name = device_get_nameunit(sc->dev); + for (irq = 0; irq < NGPIO; irq++) { + sc->gpio_pic_irqsrc[irq].gi_irq = irq; + sc->gpio_pic_irqsrc[irq].gi_pol = INTR_POLARITY_CONFORM; + sc->gpio_pic_irqsrc[irq].gi_trig = INTR_TRIGGER_CONFORM; + + error = intr_isrc_register(&sc->gpio_pic_irqsrc[irq].gi_isrc, + sc->dev, 0, "%s,%u", name, irq); + if (error != 0) { + /* XXX call intr_isrc_deregister() */ + device_printf(sc->dev, "%s failed", __func__); + return (error); + } + } + return (0); +} #endif /* @@ -656,6 +713,7 @@ } #ifdef ARM_INTRNG + gpio_pic_register_isrcs(sc); intr_pic_register(dev, OF_xref_from_node(ofw_bus_get_node(dev))); #endif sc->sc_busdev = gpiobus_attach_bus(dev); @@ -695,14 +753,13 @@ #ifdef ARM_INTRNG /* Interrupt controller interface */ DEVMETHOD(pic_disable_intr, gpio_pic_disable_intr), - DEVMETHOD(pic_disable_source, gpio_pic_disable_source), DEVMETHOD(pic_enable_intr, gpio_pic_enable_intr), - DEVMETHOD(pic_enable_source, gpio_pic_enable_source), + DEVMETHOD(pic_map_intr, gpio_pic_map_intr), + DEVMETHOD(pic_setup_intr, gpio_pic_setup_intr), + DEVMETHOD(pic_teardown_intr, gpio_pic_teardown_intr), DEVMETHOD(pic_post_filter, gpio_pic_post_filter), DEVMETHOD(pic_post_ithread, gpio_pic_post_ithread), DEVMETHOD(pic_pre_ithread, gpio_pic_pre_ithread), - DEVMETHOD(pic_register, gpio_pic_register), - DEVMETHOD(pic_unregister, gpio_pic_unregister), #endif /* GPIO protocol */ Index: head/sys/arm/include/intr.h =================================================================== --- head/sys/arm/include/intr.h +++ head/sys/arm/include/intr.h @@ -52,7 +52,7 @@ #include #ifdef SMP -typedef void intr_ipi_send_t(void *, cpuset_t); +typedef void intr_ipi_send_t(void *, cpuset_t, u_int); typedef void intr_ipi_handler_t(void *); void intr_ipi_dispatch(u_int, struct trapframe *); Index: head/sys/arm/mv/mpic.c =================================================================== --- head/sys/arm/mv/mpic.c +++ head/sys/arm/mv/mpic.c @@ -98,6 +98,13 @@ #define MPIC_PPI 32 +#ifdef ARM_INTRNG +struct mv_mpic_irqsrc { + struct intr_irqsrc mmi_isrc; + u_int mmi_irq; +}; +#endif + struct mv_mpic_softc { device_t sc_dev; struct resource * mpic_res[4]; @@ -108,8 +115,9 @@ bus_space_tag_t drbl_bst; bus_space_handle_t drbl_bsh; struct mtx mtx; - - struct intr_irqsrc ** mpic_isrcs; +#ifdef ARM_INTRNG + struct mv_mpic_irqsrc * mpic_isrcs; +#endif int nirqs; void * intr_hand; }; @@ -177,6 +185,40 @@ return (0); } +#ifdef ARM_INTRNG +static int +mv_mpic_register_isrcs(struct mv_mpic_softc *sc) +{ + int error; + uint32_t irq; + struct intr_irqsrc *isrc; + const char *name; + + sc->mpic_isrcs = malloc(sc->nirqs * sizeof (*sc->mpic_isrcs), M_DEVBUF, + M_WAITOK | M_ZERO); + + name = device_get_nameunit(sc->sc_dev); + for (irq = 0; irq < sc->nirqs; irq++) { + sc->mpic_isrcs[irq].mmi_irq = irq; + + isrc = &sc->mpic_isrcs[irq].mmi_isrc; + if (irq < MPIC_PPI) { + error = intr_isrc_register(isrc, sc->sc_dev, + INTR_ISRCF_PPI, "%s", name); + } else { + error = intr_isrc_register(isrc, sc->sc_dev, 0, "%s", + name); + } + if (error != 0) { + /* XXX call intr_isrc_deregister() */ + device_printf(sc->sc_dev, "%s failed", __func__); + return (error); + } + } + return (0); +} +#endif + static int mv_mpic_attach(device_t dev) { @@ -227,9 +269,11 @@ sc->nirqs = MPIC_CTRL_NIRQS(val); #ifdef ARM_INTRNG - sc->mpic_isrcs = malloc(sc->nirqs * sizeof (*sc->mpic_isrcs), M_DEVBUF, - M_WAITOK | M_ZERO); - + if (mv_mpic_register_isrcs(sc) != 0) { + device_printf(dev, "could not register PIC ISRCs\n"); + bus_release_resources(dev, mv_mpic_spec, sc->mpic_res); + return (ENXIO); + } if (intr_pic_register(dev, OF_xref_from_device(dev)) != 0) { device_printf(dev, "could not register PIC\n"); bus_release_resources(dev, mv_mpic_spec, sc->mpic_res); @@ -247,14 +291,11 @@ mpic_intr(void *arg) { struct mv_mpic_softc *sc; - struct trapframe *tf; - struct intr_irqsrc *isrc; uint32_t cause, irqsrc; unsigned int irq; u_int cpuid; sc = arg; - tf = curthread->td_intr_frame; cpuid = PCPU_GET(cpuid); irq = 0; @@ -264,117 +305,64 @@ irqsrc = MPIC_READ(sc, MPIC_INT_CTL(irq)); if ((irqsrc & MPIC_INT_IRQ_FIQ_MASK(cpuid)) == 0) continue; - isrc = sc->mpic_isrcs[irq]; - if (isrc == NULL) { - device_printf(sc->sc_dev, "Stray interrupt %u detected\n", irq); + if (intr_isrc_dispatch(&sc->mpic_isrcs[irq].mmi_isrc, + curthread->td_intr_frame) != 0) { mpic_mask_irq(irq); - continue; + device_printf(sc->sc_dev, "Stray irq %u " + "disabled\n", irq); } - intr_irq_dispatch(isrc, tf); } } return (FILTER_HANDLED); } -static int -mpic_attach_isrc(struct mv_mpic_softc *sc, struct intr_irqsrc *isrc, u_int irq) +static void +mpic_disable_intr(device_t dev, struct intr_irqsrc *isrc) { - const char *name; - - mtx_lock_spin(&sc->mtx); - if (sc->mpic_isrcs[irq] != NULL) { - mtx_unlock_spin(&sc->mtx); - return (sc->mpic_isrcs[irq] == isrc ? 0 : EEXIST); - } - sc->mpic_isrcs[irq] = isrc; - isrc->isrc_data = irq; - mtx_unlock_spin(&sc->mtx); - - name = device_get_nameunit(sc->sc_dev); - intr_irq_set_name(isrc, "%s", name); + u_int irq; - return (0); + irq = ((struct mv_mpic_irqsrc *)isrc)->mmi_irq; + mpic_mask_irq(irq); } -#ifdef FDT -static int -mpic_map_fdt(struct mv_mpic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp) +static void +mpic_enable_intr(device_t dev, struct intr_irqsrc *isrc) { u_int irq; - int error; - if (isrc->isrc_ncells != 1) - return (EINVAL); - - irq = isrc->isrc_cells[0]; - - error = mpic_attach_isrc(sc, isrc, irq); - if (error != 0) - return (error); - - isrc->isrc_nspc_num = irq; - isrc->isrc_trig = INTR_TRIGGER_CONFORM; - isrc->isrc_pol = INTR_POLARITY_CONFORM; - isrc->isrc_nspc_type = INTR_IRQ_NSPC_PLAIN; - - *irqp = irq; - - return (0); + irq = ((struct mv_mpic_irqsrc *)isrc)->mmi_irq; + mpic_unmask_irq(irq); } -#endif static int -mpic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu) +mpic_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) { struct mv_mpic_softc *sc; - int error; - u_int irq = 0; sc = device_get_softc(dev); -#ifdef FDT - if (isrc->isrc_type == INTR_ISRCT_FDT) - error = mpic_map_fdt(sc, isrc, &irq); - else -#endif - error = EINVAL; - - if (error == 0) - *is_percpu = irq < MPIC_PPI; - - return (error); -} - -static void -mpic_disable_source(device_t dev, struct intr_irqsrc *isrc) -{ - u_int irq; + if (data->type != INTR_MAP_DATA_FDT || data->fdt.ncells !=1 || + data->fdt.cells[0] >= sc->nirqs) + return (EINVAL); - irq = isrc->isrc_data; - mpic_mask_irq(irq); + *isrcp = &sc->mpic_isrcs[data->fdt.cells[0]].mmi_isrc; + return (0); } static void -mpic_enable_source(device_t dev, struct intr_irqsrc *isrc) -{ - u_int irq; - - irq = isrc->isrc_data; - mpic_unmask_irq(irq); -} -static void mpic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) { - mpic_disable_source(dev, isrc); + mpic_disable_intr(dev, isrc); } static void mpic_post_ithread(device_t dev, struct intr_irqsrc *isrc) { - mpic_enable_source(dev, isrc); + mpic_enable_intr(dev, isrc); } #endif @@ -383,9 +371,9 @@ DEVMETHOD(device_attach, mv_mpic_attach), #ifdef ARM_INTRNG - DEVMETHOD(pic_register, mpic_register), - DEVMETHOD(pic_disable_source, mpic_disable_source), - DEVMETHOD(pic_enable_source, mpic_enable_source), + DEVMETHOD(pic_disable_intr, mpic_disable_intr), + DEVMETHOD(pic_enable_intr, mpic_enable_intr), + DEVMETHOD(pic_map_intr, mpic_map_intr), DEVMETHOD(pic_post_ithread, mpic_post_ithread), DEVMETHOD(pic_pre_ithread, mpic_pre_ithread), #endif Index: head/sys/arm/nvidia/tegra_lic.c =================================================================== --- head/sys/arm/nvidia/tegra_lic.c +++ head/sys/arm/nvidia/tegra_lic.c @@ -88,43 +88,64 @@ }; static int -tegra_lic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu) +tegra_lic_alloc_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) { struct tegra_lic_sc *sc = device_get_softc(dev); - return (PIC_REGISTER(sc->parent, isrc, is_percpu)); + return (PIC_ALLOC_INTR(sc->parent, isrc, res, data)); } -static int -tegra_lic_unregister(device_t dev, struct intr_irqsrc *isrc) +static void +tegra_lic_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct tegra_lic_sc *sc = device_get_softc(dev); - return (PIC_UNREGISTER(sc->parent, isrc)); + PIC_DISABLE_INTR(sc->parent, isrc); } static void -tegra_lic_enable_source(device_t dev, struct intr_irqsrc *isrc) +tegra_lic_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct tegra_lic_sc *sc = device_get_softc(dev); - PIC_ENABLE_SOURCE(sc->parent, isrc); + PIC_ENABLE_INTR(sc->parent, isrc); } -static void -tegra_lic_disable_source(device_t dev, struct intr_irqsrc *isrc) +static int +tegra_lic_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) { struct tegra_lic_sc *sc = device_get_softc(dev); - PIC_DISABLE_SOURCE(sc->parent, isrc); + return (PIC_MAP_INTR(sc->parent, data, isrcp)); } -static void -tegra_lic_enable_intr(device_t dev, struct intr_irqsrc *isrc) +static int +tegra_lic_release_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) { struct tegra_lic_sc *sc = device_get_softc(dev); - PIC_ENABLE_INTR(sc->parent, isrc); + return (PIC_RELEASE_INTR(sc->parent, isrc, res, data)); +} + +static int +tegra_lic_setup_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) +{ + struct tegra_lic_sc *sc = device_get_softc(dev); + + return (PIC_SETUP_INTR(sc->parent, isrc, res, data)); +} + +static int +tegra_lic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) +{ + struct tegra_lic_sc *sc = device_get_softc(dev); + + return (PIC_TEARDOWN_INTR(sc->parent, isrc, res, data)); } static void @@ -154,11 +175,11 @@ #ifdef SMP static int -tegra_lic_bind(device_t dev, struct intr_irqsrc *isrc) +tegra_lic_bind_intr(device_t dev, struct intr_irqsrc *isrc) { struct tegra_lic_sc *sc = device_get_softc(dev); - return (PIC_BIND(sc->parent, isrc)); + return (PIC_BIND_INTR(sc->parent, isrc)); } #endif @@ -245,16 +266,18 @@ DEVMETHOD(device_detach, tegra_lic_detach), /* Interrupt controller interface */ - DEVMETHOD(pic_register, tegra_lic_register), - DEVMETHOD(pic_unregister, tegra_lic_unregister), - DEVMETHOD(pic_enable_source, tegra_lic_enable_source), - DEVMETHOD(pic_disable_source, tegra_lic_disable_source), + DEVMETHOD(pic_alloc_intr, tegra_lic_alloc_intr), + DEVMETHOD(pic_disable_intr, tegra_lic_disable_intr), DEVMETHOD(pic_enable_intr, tegra_lic_enable_intr), + DEVMETHOD(pic_map_intr, tegra_lic_map_intr), + DEVMETHOD(pic_release_intr, tegra_lic_release_intr), + DEVMETHOD(pic_setup_intr, tegra_lic_setup_intr), + DEVMETHOD(pic_teardown_intr, tegra_lic_teardown_intr), DEVMETHOD(pic_pre_ithread, tegra_lic_pre_ithread), DEVMETHOD(pic_post_ithread, tegra_lic_post_ithread), DEVMETHOD(pic_post_filter, tegra_lic_post_filter), #ifdef SMP - DEVMETHOD(pic_bind, tegra_lic_bind), + DEVMETHOD(pic_bind_intr, tegra_lic_bind_intr), #endif DEVMETHOD_END }; Index: head/sys/arm/ti/omap4/omap4_wugen.c =================================================================== --- head/sys/arm/ti/omap4/omap4_wugen.c +++ head/sys/arm/ti/omap4/omap4_wugen.c @@ -57,44 +57,64 @@ }; static int -omap4_wugen_register(device_t dev, struct intr_irqsrc *isrc, - boolean_t *is_percpu) +omap4_wugen_alloc_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) { struct omap4_wugen_sc *sc = device_get_softc(dev); - return (PIC_REGISTER(sc->sc_parent, isrc, is_percpu)); + return (PIC_ALLOC_INTR(sc->sc_parent, isrc, res, data)); } -static int -omap4_wugen_unregister(device_t dev, struct intr_irqsrc *isrc) +static void +omap4_wugen_disable_intr(device_t dev, struct intr_irqsrc *isrc) { struct omap4_wugen_sc *sc = device_get_softc(dev); - return (PIC_UNREGISTER(sc->sc_parent, isrc)); + PIC_DISABLE_INTR(sc->sc_parent, isrc); } static void -omap4_wugen_enable_source(device_t dev, struct intr_irqsrc *isrc) +omap4_wugen_enable_intr(device_t dev, struct intr_irqsrc *isrc) { struct omap4_wugen_sc *sc = device_get_softc(dev); - PIC_ENABLE_SOURCE(sc->sc_parent, isrc); + PIC_ENABLE_INTR(sc->sc_parent, isrc); } -static void -omap4_wugen_disable_source(device_t dev, struct intr_irqsrc *isrc) +static int +omap4_wugen_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) { struct omap4_wugen_sc *sc = device_get_softc(dev); - PIC_DISABLE_SOURCE(sc->sc_parent, isrc); + return (PIC_MAP_INTR(sc->sc_parent, data, isrcp)); } -static void -omap4_wugen_enable_intr(device_t dev, struct intr_irqsrc *isrc) +static int +omap4_wugen_release_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) { struct omap4_wugen_sc *sc = device_get_softc(dev); - PIC_ENABLE_INTR(sc->sc_parent, isrc); + return (PIC_RELEASE_INTR(sc->sc_parent, isrc, res, data)); +} + +static int +omap4_wugen_setup_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) +{ + struct omap4_wugen_sc *sc = device_get_softc(dev); + + return (PIC_SETUP_INTR(sc->sc_parent, isrc, res, data)); +} + +static int +omap4_wugen_teardown_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) +{ + struct omap4_wugen_sc *sc = device_get_softc(dev); + + return (PIC_TEARDOWN_INTR(sc->sc_parent, isrc, res, data)); } static void @@ -124,11 +144,11 @@ #ifdef SMP static int -omap4_wugen_bind(device_t dev, struct intr_irqsrc *isrc) +omap4_wugen_bind_intr(device_t dev, struct intr_irqsrc *isrc) { struct omap4_wugen_sc *sc = device_get_softc(dev); - return (PIC_BIND(sc->sc_parent, isrc)); + return (PIC_BIND_INTR(sc->sc_parent, isrc)); } #endif @@ -207,16 +227,18 @@ DEVMETHOD(device_detach, omap4_wugen_detach), /* Interrupt controller interface */ - DEVMETHOD(pic_register, omap4_wugen_register), - DEVMETHOD(pic_unregister, omap4_wugen_unregister), - DEVMETHOD(pic_enable_source, omap4_wugen_enable_source), - DEVMETHOD(pic_disable_source, omap4_wugen_disable_source), + DEVMETHOD(pic_alloc_intr, omap4_wugen_alloc_intr), + DEVMETHOD(pic_disable_intr, omap4_wugen_disable_intr), DEVMETHOD(pic_enable_intr, omap4_wugen_enable_intr), + DEVMETHOD(pic_map_intr, omap4_wugen_map_intr), + DEVMETHOD(pic_release_intr, omap4_wugen_release_intr), + DEVMETHOD(pic_setup_intr, omap4_wugen_setup_intr), + DEVMETHOD(pic_teardown_intr, omap4_wugen_teardown_intr), DEVMETHOD(pic_pre_ithread, omap4_wugen_pre_ithread), DEVMETHOD(pic_post_ithread, omap4_wugen_post_ithread), DEVMETHOD(pic_post_filter, omap4_wugen_post_filter), #ifdef SMP - DEVMETHOD(pic_bind, omap4_wugen_bind), + DEVMETHOD(pic_bind_intr, omap4_wugen_bind_intr), #endif DEVMETHOD_END }; Index: head/sys/kern/pic_if.m =================================================================== --- head/sys/kern/pic_if.m +++ head/sys/kern/pic_if.m @@ -1,7 +1,6 @@ #- -# Copyright (c) 2012 Jakub Wojciech Klama -# Copyright (c) 2015 Svatopluk Kraus -# Copyright (c) 2015 Michal Meloun +# Copyright (c) 2015-2016 Svatopluk Kraus +# Copyright (c) 2015-2016 Michal Meloun # All rights reserved. # # Redistribution and use in source and binary forms, with or without @@ -30,35 +29,59 @@ #include #include -#include -#include +#include +#include INTERFACE pic; CODE { - static int null_pic_bind(device_t dev, struct intr_irqsrc *isrc) + static int + dflt_pic_bind_intr(device_t dev, struct intr_irqsrc *isrc) { + return (EOPNOTSUPP); } - static void null_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) + static int + null_pic_alloc_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) + { + + return (0); + } + + static int + null_pic_release_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) + { + + return (0); + } + + static int + null_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) { - return; + + return (0); } - static void null_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) + static int + null_pic_teardown_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) { - return; + + return (0); } - static void null_pic_init_secondary(device_t dev) + static void + null_pic_init_secondary(device_t dev) { - return; } - static void null_pic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi) + static void + null_pic_ipi_send(device_t dev, cpuset_t cpus, u_int ipi) { - return; } static int @@ -69,56 +92,69 @@ } }; -METHOD int register { +METHOD int alloc_intr { device_t dev; struct intr_irqsrc *isrc; - boolean_t *is_percpu; -}; + struct resource *res; + struct intr_map_data *data; +} DEFAULT null_pic_alloc_intr; -METHOD int unregister { +METHOD int bind_intr { device_t dev; struct intr_irqsrc *isrc; -}; +} DEFAULT dflt_pic_bind_intr; METHOD void disable_intr { device_t dev; struct intr_irqsrc *isrc; -} DEFAULT null_pic_disable_intr; +}; -METHOD void disable_source { +METHOD void enable_intr { device_t dev; struct intr_irqsrc *isrc; }; -METHOD void enable_source { +METHOD int map_intr { device_t dev; - struct intr_irqsrc *isrc; + struct intr_map_data *data; + struct intr_irqsrc **isrcp; }; -METHOD void enable_intr { +METHOD int release_intr { device_t dev; struct intr_irqsrc *isrc; -} DEFAULT null_pic_enable_intr; + struct resource *res; + struct intr_map_data *data; +} DEFAULT null_pic_release_intr; -METHOD void pre_ithread { +METHOD int setup_intr { device_t dev; struct intr_irqsrc *isrc; -}; + struct resource *res; + struct intr_map_data *data; +} DEFAULT null_pic_setup_intr; -METHOD void post_ithread { +METHOD int teardown_intr { device_t dev; struct intr_irqsrc *isrc; -}; + struct resource *res; + struct intr_map_data *data; +} DEFAULT null_pic_teardown_intr; METHOD void post_filter { device_t dev; struct intr_irqsrc *isrc; }; -METHOD int bind { +METHOD void post_ithread { device_t dev; struct intr_irqsrc *isrc; -} DEFAULT null_pic_bind; +}; + +METHOD void pre_ithread { + device_t dev; + struct intr_irqsrc *isrc; +}; METHOD void init_secondary { device_t dev; @@ -128,10 +164,11 @@ device_t dev; struct intr_irqsrc *isrc; cpuset_t cpus; + u_int ipi; } DEFAULT null_pic_ipi_send; METHOD int ipi_setup { device_t dev; u_int ipi; - struct intr_irqsrc *isrc; + struct intr_irqsrc **isrcp; } DEFAULT dflt_pic_ipi_setup; Index: head/sys/kern/subr_intr.c =================================================================== --- head/sys/kern/subr_intr.c +++ head/sys/kern/subr_intr.c @@ -1,7 +1,6 @@ /*- - * Copyright (c) 2012-2014 Jakub Wojciech Klama . - * Copyright (c) 2015 Svatopluk Kraus - * Copyright (c) 2015 Michal Meloun + * Copyright (c) 2015-2016 Svatopluk Kraus + * Copyright (c) 2015-2016 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -24,8 +23,6 @@ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. - * - * $FreeBSD$ */ #include @@ -38,6 +35,7 @@ * - to complete things for removable PICs */ +#include "opt_acpi.h" #include "opt_ddb.h" #include "opt_platform.h" @@ -112,6 +110,35 @@ #define IRQ_INVALID nitems(irq_sources) +/* + * XXX - All stuff around struct intr_dev_data is considered as temporary + * until better place for storing struct intr_map_data will be find. + * + * For now, there are two global interrupt numbers spaces: + * <0, NIRQ) ... interrupts without config data + * managed in irq_sources[] + * IRQ_DDATA_BASE + <0, 2 * NIRQ) ... interrupts with config data + * managed in intr_ddata_tab[] + * + * Read intr_ddata_lookup() to see how these spaces are worked with. + * Note that each interrupt number from second space duplicates some number + * from first space at this moment. An interrupt number from first space can + * be duplicated even multiple times in second space. + */ +struct intr_dev_data { + device_t idd_dev; + intptr_t idd_xref; + u_int idd_irq; + struct intr_map_data idd_data; + struct intr_irqsrc * idd_isrc; +}; + +static struct intr_dev_data *intr_ddata_tab[2 * NIRQ]; +static u_int intr_ddata_first_unused; + +#define IRQ_DDATA_BASE 10000 +CTASSERT(IRQ_DDATA_BASE > IRQ_INVALID); + #ifdef SMP static boolean_t irq_assign_cpu = FALSE; #endif @@ -173,12 +200,10 @@ isrc_increment_count(struct intr_irqsrc *isrc) { - /* - * XXX - It should be atomic for PPI interrupts. It was proven that - * the lost is measurable easily for timer PPI interrupts. - */ - isrc->isrc_count[0]++; - /*atomic_add_long(&isrc->isrc_count[0], 1);*/ + if (isrc->isrc_flags & INTR_ISRCF_PPI) + atomic_add_long(&isrc->isrc_count[0], 1); + else + isrc->isrc_count[0]++; } /* @@ -233,6 +258,16 @@ isrc_update_name(isrc, NULL); } +/* + * Virtualization for interrupt source interrupt counters release. + */ +static void +isrc_release_counters(struct intr_irqsrc *isrc) +{ + + panic("%s: not implemented", __func__); +} + #ifdef SMP /* * Virtualization for interrupt source IPI counters setup. @@ -279,8 +314,8 @@ * be called straight from the interrupt controller, when associated interrupt * source is learned. */ -void -intr_irq_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf) +int +intr_isrc_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf) { KASSERT(isrc != NULL, ("%s: no source", __func__)); @@ -293,57 +328,16 @@ error = isrc->isrc_filter(isrc->isrc_arg, tf); PIC_POST_FILTER(isrc->isrc_dev, isrc); if (error == FILTER_HANDLED) - return; - } else + return (0); + } else #endif if (isrc->isrc_event != NULL) { if (intr_event_handle(isrc->isrc_event, tf) == 0) - return; + return (0); } isrc_increment_straycount(isrc); - PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc); - - device_printf(isrc->isrc_dev, "stray irq <%s> disabled", - isrc->isrc_name); -} - -/* - * Allocate interrupt source. - */ -struct intr_irqsrc * -intr_isrc_alloc(u_int type, u_int extsize) -{ - struct intr_irqsrc *isrc; - - isrc = malloc(sizeof(*isrc) + extsize, M_INTRNG, M_WAITOK | M_ZERO); - isrc->isrc_irq = IRQ_INVALID; /* just to be safe */ - isrc->isrc_type = type; - isrc->isrc_nspc_type = INTR_IRQ_NSPC_NONE; - isrc->isrc_trig = INTR_TRIGGER_CONFORM; - isrc->isrc_pol = INTR_POLARITY_CONFORM; - CPU_ZERO(&isrc->isrc_cpu); - return (isrc); -} - -/* - * Free interrupt source. - */ -void -intr_isrc_free(struct intr_irqsrc *isrc) -{ - - free(isrc, M_INTRNG); -} - -void -intr_irq_set_name(struct intr_irqsrc *isrc, const char *fmt, ...) -{ - va_list ap; - - va_start(ap, fmt); - vsnprintf(isrc->isrc_name, INTR_ISRC_NAMELEN, fmt, ap); - va_end(ap); + return (EINVAL); } /* @@ -356,8 +350,8 @@ * immediately. However, if only one free handle left which is reused * constantly... */ -static int -isrc_alloc_irq_locked(struct intr_irqsrc *isrc) +static inline int +isrc_alloc_irq(struct intr_irqsrc *isrc) { u_int maxirqs, irq; @@ -383,46 +377,35 @@ isrc->isrc_irq = irq; irq_sources[irq] = isrc; - intr_irq_set_name(isrc, "irq%u", irq); - isrc_setup_counters(isrc); - irq_next_free = irq + 1; if (irq_next_free >= maxirqs) irq_next_free = 0; return (0); } -#ifdef notyet + /* * Free unique interrupt number (resource handle) from interrupt source. */ -static int +static inline int isrc_free_irq(struct intr_irqsrc *isrc) { - u_int maxirqs; - mtx_assert(&isrc_table_lock, MA_NOTOWNED); + mtx_assert(&isrc_table_lock, MA_OWNED); - maxirqs = nitems(irq_sources); - if (isrc->isrc_irq >= maxirqs) + if (isrc->isrc_irq >= nitems(irq_sources)) return (EINVAL); - - mtx_lock(&isrc_table_lock); - if (irq_sources[isrc->isrc_irq] != isrc) { - mtx_unlock(&isrc_table_lock); + if (irq_sources[isrc->isrc_irq] != isrc) return (EINVAL); - } irq_sources[isrc->isrc_irq] = NULL; isrc->isrc_irq = IRQ_INVALID; /* just to be safe */ - mtx_unlock(&isrc_table_lock); - return (0); } -#endif + /* * Lookup interrupt source by interrupt number (resource handle). */ -static struct intr_irqsrc * +static inline struct intr_irqsrc * isrc_lookup(u_int irq) { @@ -432,158 +415,159 @@ } /* - * Lookup interrupt source by namespace description. + * Initialize interrupt source and register it into global interrupt table. */ -static struct intr_irqsrc * -isrc_namespace_lookup(device_t dev, uint16_t type, uint16_t num) +int +intr_isrc_register(struct intr_irqsrc *isrc, device_t dev, u_int flags, + const char *fmt, ...) { - u_int irq; - struct intr_irqsrc *isrc; + int error; + va_list ap; - mtx_assert(&isrc_table_lock, MA_OWNED); + bzero(isrc, sizeof(struct intr_irqsrc)); + isrc->isrc_dev = dev; + isrc->isrc_irq = IRQ_INVALID; /* just to be safe */ + isrc->isrc_flags = flags; + + va_start(ap, fmt); + vsnprintf(isrc->isrc_name, INTR_ISRC_NAMELEN, fmt, ap); + va_end(ap); - for (irq = 0; irq < nitems(irq_sources); irq++) { - isrc = irq_sources[irq]; - if (isrc != NULL && isrc->isrc_dev == dev && - isrc->isrc_nspc_type == type && isrc->isrc_nspc_num == num) - return (isrc); + mtx_lock(&isrc_table_lock); + error = isrc_alloc_irq(isrc); + if (error != 0) { + mtx_unlock(&isrc_table_lock); + return (error); } - return (NULL); + /* + * Setup interrupt counters, but not for IPI sources. Those are setup + * later and only for used ones (up to INTR_IPI_COUNT) to not exhaust + * our counter pool. + */ + if ((isrc->isrc_flags & INTR_ISRCF_IPI) == 0) + isrc_setup_counters(isrc); + mtx_unlock(&isrc_table_lock); + return (0); } /* - * Map interrupt source according to namespace into framework. If such mapping - * does not exist, create it. Return unique interrupt number (resource handle) - * associated with mapped interrupt source. + * Deregister interrupt source from global interrupt table. */ -u_int -intr_namespace_map_irq(device_t dev, uint16_t type, uint16_t num) +int +intr_isrc_deregister(struct intr_irqsrc *isrc) { - struct intr_irqsrc *isrc, *new_isrc; int error; - new_isrc = intr_isrc_alloc(INTR_ISRCT_NAMESPACE, 0); - mtx_lock(&isrc_table_lock); - isrc = isrc_namespace_lookup(dev, type, num); - if (isrc != NULL) { - mtx_unlock(&isrc_table_lock); - intr_isrc_free(new_isrc); - return (isrc->isrc_irq); /* already mapped */ - } + if ((isrc->isrc_flags & INTR_ISRCF_IPI) == 0) + isrc_release_counters(isrc); + error = isrc_free_irq(isrc); + mtx_unlock(&isrc_table_lock); + return (error); +} - error = isrc_alloc_irq_locked(new_isrc); - if (error != 0) { +static struct intr_dev_data * +intr_ddata_alloc(u_int extsize) +{ + struct intr_dev_data *ddata; + + ddata = malloc(sizeof(*ddata) + extsize, M_INTRNG, M_WAITOK | M_ZERO); + + mtx_lock(&isrc_table_lock); + if (intr_ddata_first_unused >= nitems(intr_ddata_tab)) { mtx_unlock(&isrc_table_lock); - intr_isrc_free(new_isrc); - return (IRQ_INVALID); /* no space left */ + free(ddata, M_INTRNG); + return (NULL); } - - new_isrc->isrc_dev = dev; - new_isrc->isrc_nspc_type = type; - new_isrc->isrc_nspc_num = num; + intr_ddata_tab[intr_ddata_first_unused] = ddata; + ddata->idd_irq = IRQ_DDATA_BASE + intr_ddata_first_unused++; mtx_unlock(&isrc_table_lock); - - return (new_isrc->isrc_irq); + return (ddata); } -#ifdef FDT -/* - * Lookup interrupt source by FDT description. - */ static struct intr_irqsrc * -isrc_fdt_lookup(intptr_t xref, pcell_t *cells, u_int ncells) +intr_ddata_lookup(u_int irq, struct intr_map_data **datap) { - u_int irq, cellsize; + int error; struct intr_irqsrc *isrc; + struct intr_dev_data *ddata; - mtx_assert(&isrc_table_lock, MA_OWNED); + isrc = isrc_lookup(irq); + if (isrc != NULL) { + if (datap != NULL) + *datap = NULL; + return (isrc); + } - cellsize = ncells * sizeof(*cells); - for (irq = 0; irq < nitems(irq_sources); irq++) { - isrc = irq_sources[irq]; - if (isrc != NULL && isrc->isrc_type == INTR_ISRCT_FDT && - isrc->isrc_xref == xref && isrc->isrc_ncells == ncells && - memcmp(isrc->isrc_cells, cells, cellsize) == 0) - return (isrc); + if (irq < IRQ_DDATA_BASE) + return (NULL); + + irq -= IRQ_DDATA_BASE; + if (irq >= nitems(intr_ddata_tab)) + return (NULL); + + ddata = intr_ddata_tab[irq]; + if (ddata->idd_isrc == NULL) { + error = intr_map_irq(ddata->idd_dev, ddata->idd_xref, + &ddata->idd_data, &irq); + if (error != 0) + return (NULL); + ddata->idd_isrc = isrc_lookup(irq); } - return (NULL); + if (datap != NULL) + *datap = &ddata->idd_data; + return (ddata->idd_isrc); } +#ifdef DEV_ACPI /* - * Map interrupt source according to FDT data into framework. If such mapping + * Map interrupt source according to ACPI info into framework. If such mapping * does not exist, create it. Return unique interrupt number (resource handle) * associated with mapped interrupt source. */ u_int -intr_fdt_map_irq(phandle_t node, pcell_t *cells, u_int ncells) +intr_acpi_map_irq(device_t dev, u_int irq, enum intr_polarity pol, + enum intr_trigger trig) { - struct intr_irqsrc *isrc, *new_isrc; - u_int cellsize; - intptr_t xref; - int error; + struct intr_dev_data *ddata; - xref = (intptr_t)node; /* It's so simple for now. */ - - cellsize = ncells * sizeof(*cells); - new_isrc = intr_isrc_alloc(INTR_ISRCT_FDT, cellsize); - - mtx_lock(&isrc_table_lock); - isrc = isrc_fdt_lookup(xref, cells, ncells); - if (isrc != NULL) { - mtx_unlock(&isrc_table_lock); - intr_isrc_free(new_isrc); - return (isrc->isrc_irq); /* already mapped */ - } - - error = isrc_alloc_irq_locked(new_isrc); - if (error != 0) { - mtx_unlock(&isrc_table_lock); - intr_isrc_free(new_isrc); - return (IRQ_INVALID); /* no space left */ - } - - new_isrc->isrc_xref = xref; - new_isrc->isrc_ncells = ncells; - memcpy(new_isrc->isrc_cells, cells, cellsize); - mtx_unlock(&isrc_table_lock); - - return (new_isrc->isrc_irq); + ddata = intr_ddata_alloc(0); + if (ddata == NULL) + return (0xFFFFFFFF); /* no space left */ + + ddata->idd_dev = dev; + ddata->idd_data.type = INTR_MAP_DATA_ACPI; + ddata->idd_data.acpi.irq = irq; + ddata->idd_data.acpi.pol = pol; + ddata->idd_data.acpi.trig = trig; + return (ddata->idd_irq); } #endif - +#ifdef FDT /* - * Register interrupt source into interrupt controller. + * Map interrupt source according to FDT data into framework. If such mapping + * does not exist, create it. Return unique interrupt number (resource handle) + * associated with mapped interrupt source. */ -static int -isrc_register(struct intr_irqsrc *isrc) +u_int +intr_fdt_map_irq(phandle_t node, pcell_t *cells, u_int ncells) { - struct intr_pic *pic; - boolean_t is_percpu; - int error; - - if (isrc->isrc_flags & INTR_ISRCF_REGISTERED) - return (0); - - if (isrc->isrc_dev == NULL) { - pic = pic_lookup(NULL, isrc->isrc_xref); - if (pic == NULL || pic->pic_dev == NULL) - return (ESRCH); - isrc->isrc_dev = pic->pic_dev; - } - - error = PIC_REGISTER(isrc->isrc_dev, isrc, &is_percpu); - if (error != 0) - return (error); + struct intr_dev_data *ddata; + u_int cellsize; - mtx_lock(&isrc_table_lock); - isrc->isrc_flags |= INTR_ISRCF_REGISTERED; - if (is_percpu) - isrc->isrc_flags |= INTR_ISRCF_PERCPU; - isrc_update_name(isrc, NULL); - mtx_unlock(&isrc_table_lock); - return (0); + cellsize = ncells * sizeof(*cells); + ddata = intr_ddata_alloc(cellsize); + if (ddata == NULL) + return (0xFFFFFFFF); /* no space left */ + + ddata->idd_xref = (intptr_t)node; + ddata->idd_data.type = INTR_MAP_DATA_FDT; + ddata->idd_data.fdt.ncells = ncells; + ddata->idd_data.fdt.cells = (pcell_t *)(ddata + 1); + memcpy(ddata->idd_data.fdt.cells, cells, cellsize); + return (ddata->idd_irq); } +#endif #ifdef INTR_SOLO /* @@ -678,7 +662,7 @@ * informed if the call is successfull. */ if (irq_assign_cpu) { - error = PIC_BIND(isrc->isrc_dev, isrc); + error = PIC_BIND_INTR(isrc->isrc_dev, isrc); if (error) { CPU_ZERO(&isrc->isrc_cpu); mtx_unlock(&isrc_table_lock); @@ -774,7 +758,7 @@ /* * Lookup interrupt controller locked. */ -static struct intr_pic * +static inline struct intr_pic * pic_lookup_locked(device_t dev, intptr_t xref) { struct intr_pic *pic; @@ -801,7 +785,6 @@ mtx_lock(&pic_list_lock); pic = pic_lookup_locked(dev, xref); mtx_unlock(&pic_list_lock); - return (pic); } @@ -871,7 +854,7 @@ * Unregister interrupt controller. */ int -intr_pic_unregister(device_t dev, intptr_t xref) +intr_pic_deregister(device_t dev, intptr_t xref) { panic("%s: not implemented", __func__); @@ -923,12 +906,73 @@ } int -intr_irq_add_handler(device_t dev, driver_filter_t filt, driver_intr_t hand, - void *arg, u_int irq, int flags, void **cookiep) +intr_map_irq(device_t dev, intptr_t xref, struct intr_map_data *data, + u_int *irqp) { - const char *name; + int error; + struct intr_irqsrc *isrc; + struct intr_pic *pic; + + if (data == NULL) + return (EINVAL); + + pic = pic_lookup(dev, xref); + if (pic == NULL || pic->pic_dev == NULL) + return (ESRCH); + + error = PIC_MAP_INTR(pic->pic_dev, data, &isrc); + if (error == 0) + *irqp = isrc->isrc_irq; + return (error); +} + +int +intr_alloc_irq(device_t dev, struct resource *res) +{ + struct intr_map_data *data; + struct intr_irqsrc *isrc; + + KASSERT(rman_get_start(res) == rman_get_end(res), + ("%s: more interrupts in resource", __func__)); + + isrc = intr_ddata_lookup(rman_get_start(res), &data); + if (isrc == NULL) + return (EINVAL); + + return (PIC_ALLOC_INTR(isrc->isrc_dev, isrc, res, data)); +} + +int +intr_release_irq(device_t dev, struct resource *res) +{ + struct intr_map_data *data; struct intr_irqsrc *isrc; + + KASSERT(rman_get_start(res) == rman_get_end(res), + ("%s: more interrupts in resource", __func__)); + + isrc = intr_ddata_lookup(rman_get_start(res), &data); + if (isrc == NULL) + return (EINVAL); + + return (PIC_RELEASE_INTR(isrc->isrc_dev, isrc, res, data)); +} + +int +intr_setup_irq(device_t dev, struct resource *res, driver_filter_t filt, + driver_intr_t hand, void *arg, int flags, void **cookiep) +{ int error; + struct intr_map_data *data; + struct intr_irqsrc *isrc; + const char *name; + + KASSERT(rman_get_start(res) == rman_get_end(res), + ("%s: more interrupts in resource", __func__)); + + isrc = intr_ddata_lookup(rman_get_start(res), &data); + if (isrc == NULL) + return (EINVAL); name = device_get_nameunit(dev); @@ -947,21 +991,7 @@ debugf("irq %u cannot solo on %s\n", irq, name); return (EINVAL); } -#endif - - isrc = isrc_lookup(irq); - if (isrc == NULL) { - debugf("irq %u without source on %s\n", irq, name); - return (EINVAL); - } - error = isrc_register(isrc); - if (error != 0) { - debugf("irq %u map error %d on %s\n", irq, error, name); - return (error); - } - -#ifdef INTR_SOLO if (flags & INTR_SOLO) { error = iscr_setup_filter(isrc, name, (intr_irq_filter_t *)filt, arg, cookiep); @@ -978,24 +1008,32 @@ return (error); mtx_lock(&isrc_table_lock); - isrc->isrc_handlers++; - if (isrc->isrc_handlers == 1) { - PIC_ENABLE_INTR(isrc->isrc_dev, isrc); - PIC_ENABLE_SOURCE(isrc->isrc_dev, isrc); + error = PIC_SETUP_INTR(isrc->isrc_dev, isrc, res, data); + if (error == 0) { + isrc->isrc_handlers++; + if (isrc->isrc_handlers == 1) + PIC_ENABLE_INTR(isrc->isrc_dev, isrc); } mtx_unlock(&isrc_table_lock); - return (0); + if (error != 0) + intr_event_remove_handler(*cookiep); + return (error); } int -intr_irq_remove_handler(device_t dev, u_int irq, void *cookie) +intr_teardown_irq(device_t dev, struct resource *res, void *cookie) { - struct intr_irqsrc *isrc; int error; + struct intr_map_data *data; + struct intr_irqsrc *isrc; - isrc = isrc_lookup(irq); + KASSERT(rman_get_start(res) == rman_get_end(res), + ("%s: more interrupts in resource", __func__)); + + isrc = intr_ddata_lookup(rman_get_start(res), &data); if (isrc == NULL || isrc->isrc_handlers == 0) return (EINVAL); + #ifdef INTR_SOLO if (isrc->isrc_filter != NULL) { if (isrc != cookie) @@ -1005,8 +1043,8 @@ isrc->isrc_filter = NULL; isrc->isrc_arg = NULL; isrc->isrc_handlers = 0; - PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc); PIC_DISABLE_INTR(isrc->isrc_dev, isrc); + PIC_TEARDOWN_INTR(isrc->isrc_dev, isrc, res, data); isrc_update_name(isrc, NULL); mtx_unlock(&isrc_table_lock); return (0); @@ -1019,10 +1057,9 @@ if (error == 0) { mtx_lock(&isrc_table_lock); isrc->isrc_handlers--; - if (isrc->isrc_handlers == 0) { - PIC_DISABLE_SOURCE(isrc->isrc_dev, isrc); + if (isrc->isrc_handlers == 0) PIC_DISABLE_INTR(isrc->isrc_dev, isrc); - } + PIC_TEARDOWN_INTR(isrc->isrc_dev, isrc, res, data); intrcnt_updatename(isrc); mtx_unlock(&isrc_table_lock); } @@ -1030,36 +1067,16 @@ } int -intr_irq_config(u_int irq, enum intr_trigger trig, enum intr_polarity pol) +intr_describe_irq(device_t dev, struct resource *res, void *cookie, + const char *descr) { + int error; struct intr_irqsrc *isrc; - isrc = isrc_lookup(irq); - if (isrc == NULL) - return (EINVAL); - - if (isrc->isrc_handlers != 0) - return (EBUSY); /* interrrupt is enabled (active) */ + KASSERT(rman_get_start(res) == rman_get_end(res), + ("%s: more interrupts in resource", __func__)); - /* - * Once an interrupt is enabled, we do not change its configuration. - * A controller PIC_ENABLE_INTR() method is called when an interrupt - * is going to be enabled. In this method, a controller should setup - * the interrupt according to saved configuration parameters. - */ - isrc->isrc_trig = trig; - isrc->isrc_pol = pol; - - return (0); -} - -int -intr_irq_describe(u_int irq, void *cookie, const char *descr) -{ - struct intr_irqsrc *isrc; - int error; - - isrc = isrc_lookup(irq); + isrc = intr_ddata_lookup(rman_get_start(res), NULL); if (isrc == NULL || isrc->isrc_handlers == 0) return (EINVAL); #ifdef INTR_SOLO @@ -1084,11 +1101,14 @@ #ifdef SMP int -intr_irq_bind(u_int irq, int cpu) +intr_bind_irq(device_t dev, struct resource *res, int cpu) { struct intr_irqsrc *isrc; - isrc = isrc_lookup(irq); + KASSERT(rman_get_start(res) == rman_get_end(res), + ("%s: more interrupts in resource", __func__)); + + isrc = intr_ddata_lookup(rman_get_start(res), NULL); if (isrc == NULL || isrc->isrc_handlers == 0) return (EINVAL); #ifdef INTR_SOLO @@ -1135,7 +1155,7 @@ for (i = 0; i < NIRQ; i++) { isrc = irq_sources[i]; if (isrc == NULL || isrc->isrc_handlers == 0 || - isrc->isrc_flags & INTR_ISRCF_PERCPU) + isrc->isrc_flags & INTR_ISRCF_PPI) continue; if (isrc->isrc_event != NULL && @@ -1151,7 +1171,7 @@ * for bound ISRC. The best thing we can do is to clear * isrc_cpu so inconsistency with ie_cpu will be detectable. */ - if (PIC_BIND(isrc->isrc_dev, isrc) != 0) + if (PIC_BIND_INTR(isrc->isrc_dev, isrc) != 0) CPU_ZERO(&isrc->isrc_cpu); } mtx_unlock(&isrc_table_lock); @@ -1196,6 +1216,7 @@ DB_SHOW_COMMAND(irqs, db_show_irqs) { u_int i, irqsum; + u_long num; struct intr_irqsrc *isrc; for (irqsum = 0, i = 0; i < NIRQ; i++) { @@ -1203,11 +1224,11 @@ if (isrc == NULL) continue; + num = isrc->isrc_count != NULL ? isrc->isrc_count[0] : 0; db_printf("irq%-3u <%s>: cpu %02lx%s cnt %lu\n", i, isrc->isrc_name, isrc->isrc_cpu.__bits[0], - isrc->isrc_flags & INTR_ISRCF_BOUND ? " (bound)" : "", - isrc->isrc_count[0]); - irqsum += isrc->isrc_count[0]; + isrc->isrc_flags & INTR_ISRCF_BOUND ? " (bound)" : "", num); + irqsum += num; } db_printf("irq total %u\n", irqsum); } Index: head/sys/sys/intr.h =================================================================== --- head/sys/sys/intr.h +++ head/sys/sys/intr.h @@ -1,7 +1,6 @@ -/* $NetBSD: intr.h,v 1.7 2003/06/16 20:01:00 thorpej Exp $ */ - /*- - * Copyright (c) 1997 Mark Brinicombe. + * Copyright (c) 2015-2016 Svatopluk Kraus + * Copyright (c) 2015-2016 Michal Meloun * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -12,28 +11,20 @@ * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. - * 3. All advertising materials mentioning features or use of this software - * must display the following acknowledgement: - * This product includes software developed by Mark Brinicombe - * for the NetBSD Project. - * 4. The name of the company nor the name of the author may be used to - * endorse or promote products derived from this software without specific - * prior written permission. * - * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED - * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF - * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. - * IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, - * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR - * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. * * $FreeBSD$ - * */ #ifndef _SYS_INTR_H_ @@ -41,6 +32,37 @@ #include +enum intr_map_data_type { + INTR_MAP_DATA_ACPI, + INTR_MAP_DATA_FDT, +}; + +#ifdef DEV_ACPI +struct intr_map_data_acpi { + u_int irq; + enum intr_polarity pol; + enum intr_trigger trig; +}; +#endif +#ifdef FDT +struct intr_map_data_fdt { + u_int ncells; + pcell_t *cells; +}; +#endif + +struct intr_map_data { + enum intr_map_data_type type; + union { +#ifdef DEV_ACPI + struct intr_map_data_acpi acpi; +#endif +#ifdef FDT + struct intr_map_data_fdt fdt; +#endif + }; +}; + #ifdef notyet #define INTR_SOLO INTR_MD1 typedef int intr_irq_filter_t(void *arg, struct trapframe *tf); @@ -50,28 +72,16 @@ #define INTR_ISRC_NAMELEN (MAXCOMLEN + 1) -enum intr_isrc_type { - INTR_ISRCT_NAMESPACE, - INTR_ISRCT_FDT -}; - -#define INTR_ISRCF_REGISTERED 0x01 /* registered in a controller */ -#define INTR_ISRCF_PERCPU 0x02 /* per CPU interrupt */ +#define INTR_ISRCF_IPI 0x01 /* IPI interrupt */ +#define INTR_ISRCF_PPI 0x02 /* PPI interrupt */ #define INTR_ISRCF_BOUND 0x04 /* bound to a CPU */ /* Interrupt source definition. */ struct intr_irqsrc { device_t isrc_dev; /* where isrc is mapped */ - intptr_t isrc_xref; /* device reference key */ - uintptr_t isrc_data; /* device data for isrc */ u_int isrc_irq; /* unique identificator */ - enum intr_isrc_type isrc_type; /* how is isrc decribed */ u_int isrc_flags; char isrc_name[INTR_ISRC_NAMELEN]; - uint16_t isrc_nspc_type; - uint16_t isrc_nspc_num; - enum intr_trigger isrc_trig; - enum intr_polarity isrc_pol; cpuset_t isrc_cpu; /* on which CPUs is enabled */ u_int isrc_index; u_long * isrc_count; @@ -81,47 +91,44 @@ intr_irq_filter_t * isrc_filter; void * isrc_arg; #endif -#ifdef FDT - u_int isrc_ncells; - pcell_t isrc_cells[]; /* leave it last */ -#endif }; -struct intr_irqsrc *intr_isrc_alloc(u_int type, u_int extsize); -void intr_isrc_free(struct intr_irqsrc *isrc); +/* Intr interface for PIC. */ +int intr_isrc_deregister(struct intr_irqsrc *); +int intr_isrc_register(struct intr_irqsrc *, device_t, u_int, const char *, ...) + __printflike(4, 5); -void intr_irq_set_name(struct intr_irqsrc *isrc, const char *fmt, ...) - __printflike(2, 3); +int intr_isrc_dispatch(struct intr_irqsrc *, struct trapframe *); +u_int intr_irq_next_cpu(u_int current_cpu, cpuset_t *cpumask); -void intr_irq_dispatch(struct intr_irqsrc *isrc, struct trapframe *tf); +int intr_pic_register(device_t, intptr_t); +int intr_pic_deregister(device_t, intptr_t); +int intr_pic_claim_root(device_t, intptr_t, intr_irq_filter_t *, void *, u_int); -#define INTR_IRQ_NSPC_NONE 0 -#define INTR_IRQ_NSPC_PLAIN 1 -#define INTR_IRQ_NSPC_IRQ 2 -#define INTR_IRQ_NSPC_IPI 3 +extern device_t intr_irq_root_dev; -u_int intr_namespace_map_irq(device_t dev, uint16_t type, uint16_t num); -#ifdef FDT -u_int intr_fdt_map_irq(phandle_t, pcell_t *, u_int); -#endif +/* Intr interface for BUS. */ +int intr_map_irq(device_t, intptr_t, struct intr_map_data *, u_int *); -extern device_t intr_irq_root_dev; +int intr_alloc_irq(device_t, struct resource *); +int intr_release_irq(device_t, struct resource *); -int intr_pic_register(device_t dev, intptr_t xref); -int intr_pic_unregister(device_t dev, intptr_t xref); -int intr_pic_claim_root(device_t dev, intptr_t xref, intr_irq_filter_t *filter, - void *arg, u_int ipicount); - -int intr_irq_add_handler(device_t dev, driver_filter_t, driver_intr_t, void *, - u_int, int, void **); -int intr_irq_remove_handler(device_t dev, u_int, void *); -int intr_irq_config(u_int, enum intr_trigger, enum intr_polarity); -int intr_irq_describe(u_int, void *, const char *); +int intr_setup_irq(device_t, struct resource *, driver_filter_t, driver_intr_t, + void *, int, void **); +int intr_teardown_irq(device_t, struct resource *, void *); -u_int intr_irq_next_cpu(u_int current_cpu, cpuset_t *cpumask); +int intr_describe_irq(device_t, struct resource *, void *, const char *); + +#ifdef DEV_ACPI +u_int intr_acpi_map_irq(device_t, u_int, enum intr_polarity, + enum intr_trigger); +#endif +#ifdef FDT +u_int intr_fdt_map_irq(phandle_t, pcell_t *, u_int); +#endif #ifdef SMP -int intr_irq_bind(u_int, int); +int intr_bind_irq(device_t, struct resource *, int); void intr_pic_init_secondary(void);