From owner-svn-src-all@freebsd.org Mon Apr 4 09:15:27 2016 Return-Path: Delivered-To: svn-src-all@mailman.ysv.freebsd.org Received: from mx1.freebsd.org (mx1.freebsd.org [IPv6:2001:1900:2254:206a::19:1]) by mailman.ysv.freebsd.org (Postfix) with ESMTP id 15385B02468; Mon, 4 Apr 2016 09:15:27 +0000 (UTC) (envelope-from skra@FreeBSD.org) Received: from repo.freebsd.org (repo.freebsd.org [IPv6:2610:1c1:1:6068::e6a:0]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (Client did not present a certificate) by mx1.freebsd.org (Postfix) with ESMTPS id CD58F1767; Mon, 4 Apr 2016 09:15:26 +0000 (UTC) (envelope-from skra@FreeBSD.org) Received: from repo.freebsd.org ([127.0.1.37]) by repo.freebsd.org (8.15.2/8.15.2) with ESMTP id u349FQxY096505; Mon, 4 Apr 2016 09:15:26 GMT (envelope-from skra@FreeBSD.org) Received: (from skra@localhost) by repo.freebsd.org (8.15.2/8.15.2/Submit) id u349FPNt096500; Mon, 4 Apr 2016 09:15:25 GMT (envelope-from skra@FreeBSD.org) Message-Id: <201604040915.u349FPNt096500@repo.freebsd.org> X-Authentication-Warning: repo.freebsd.org: skra set sender to skra@FreeBSD.org using -f From: Svatopluk Kraus Date: Mon, 4 Apr 2016 09:15:25 +0000 (UTC) To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r297539 - in head/sys: arm/arm arm/freescale/imx arm/include arm/mv arm/nvidia arm/ti/omap4 kern sys X-SVN-Group: head MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit X-BeenThere: svn-src-all@freebsd.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "SVN commit messages for the entire src tree \(except for " user" and " projects" \)" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Mon, 04 Apr 2016 09:15:27 -0000 Author: skra Date: Mon Apr 4 09:15:25 2016 New Revision: 297539 URL: https://svnweb.freebsd.org/changeset/base/297539 Log: Remove FDT specific parts from INTRNG. Change its interface to make it universal. (1) New struct intr_map_data is defined as a container for arbitrary description of an interrupt used by a device. Typically, an interrupt number and configuration relevant to an interrupt controller is encoded in such description. However, any additional information may be encoded too like a set of cpus on which an interrupt should be enabled or vendor specific data needed for setup of an interrupt in controller. The struct intr_map_data itself is meant to be opaque for INTRNG. (2) An intr_map_irq() function is created which takes an interrupt controller identification and struct intr_map_data as arguments and returns global interrupt number which identifies an interrupt. (3) A set of functions to be used by bus drivers is created as well as a corresponding set of methods for interrupt controller drivers. These sets take both struct resource and struct intr_map_data as one of the arguments. There is a goal to keep struct intr_map_data in struct resource, however, this way a final solution is not limited to that. (4) Other small changes are done to reflect new situation. This is only first step aiming to create stable interface for interrupt controller drivers. Thus, some temporary solution is taken. Interrupt descriptions for devices are stored in INTRNG and two specific mapping function are created to be temporary used by bus drivers. That's why the struct intr_map_data is not opaque for INTRNG now. This temporary solution will be replaced by final one in next step. Differential Revision: https://reviews.freebsd.org/D5730 Modified: head/sys/arm/arm/gic.c head/sys/arm/arm/machdep_intr.c head/sys/arm/arm/nexus.c head/sys/arm/freescale/imx/imx_gpio.c head/sys/arm/include/intr.h head/sys/arm/mv/mpic.c head/sys/arm/nvidia/tegra_lic.c head/sys/arm/ti/omap4/omap4_wugen.c head/sys/kern/pic_if.m head/sys/kern/subr_intr.c head/sys/sys/intr.h Modified: head/sys/arm/arm/gic.c ============================================================================== --- head/sys/arm/arm/gic.c Mon Apr 4 07:16:43 2016 (r297538) +++ head/sys/arm/arm/gic.c Mon Apr 4 09:15:25 2016 (r297539) @@ -36,8 +36,6 @@ __FBSDID("$FreeBSD$"); #include "opt_platform.h" -#include "opt_platform.h" - #include #include #include @@ -118,13 +116,20 @@ __FBSDID("$FreeBSD$"); #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 @@ struct arm_gic_softc { 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 @@ struct arm_gic_softc { #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 @@ arm_gic_init_secondary(device_t dev) /* 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 @@ arm_gic_init_secondary(device_t dev) /* 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 @@ gic_xref(device_t dev) 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 @@ arm_gic_attach(device_t dev) { 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 @@ arm_gic_attach(device_t dev) 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 @@ arm_gic_attach(device_t dev) 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 @@ static int 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 @@ arm_gic_intr(void *arg) 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 @@ dispatch_irq: #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 @@ dispatch_irq: #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 @@ next_irq: 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 @@ gic_bind(struct arm_gic_softc *sc, u_int 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 @@ arm_gic_enable_intr(device_t dev, struct * 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_gic_post_ithread(device_t dev, struc { 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 @@ static device_method_t arm_gic_methods[] 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), Modified: head/sys/arm/arm/machdep_intr.c ============================================================================== --- head/sys/arm/arm/machdep_intr.c Mon Apr 4 07:16:43 2016 (r297538) +++ head/sys/arm/arm/machdep_intr.c Mon Apr 4 09:15:25 2016 (r297539) @@ -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 @@ struct intr_ipi { }; static struct intr_ipi ipi_sources[INTR_IPI_COUNT]; -u_int ipi_next_num; #endif #endif @@ -184,7 +172,7 @@ intr_ipi_send(cpuset_t cpus, u_int ipi) 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 @@ intr_ipi_setup(u_int ipi, const char *na * 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 @@ intr_pic_ipi_setup(u_int ipi, const char 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); } Modified: head/sys/arm/arm/nexus.c ============================================================================== --- head/sys/arm/arm/nexus.c Mon Apr 4 07:16:43 2016 (r297538) +++ head/sys/arm/arm/nexus.c Mon Apr 4 09:15:25 2016 (r297539) @@ -281,7 +281,8 @@ nexus_config_intr(device_t dev, int irq, 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 @@ static int 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 @@ nexus_teardown_intr(device_t dev, device { #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 @@ nexus_describe_intr(device_t dev, device 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 @@ static int 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 Modified: head/sys/arm/freescale/imx/imx_gpio.c ============================================================================== --- head/sys/arm/freescale/imx/imx_gpio.c Mon Apr 4 07:16:43 2016 (r297538) +++ head/sys/arm/freescale/imx/imx_gpio.c Mon Apr 4 09:15:25 2016 (r297539) @@ -91,6 +91,15 @@ __FBSDID("$FreeBSD$"); #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 @@ struct imx51_gpio_softc { 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_get(device_t, 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 @@ gpio_pic_disable_intr(device_t dev, stru 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; *** DIFF OUTPUT TRUNCATED AT 1000 LINES ***