svn commit: r297539 - in head/sys: arm/arm arm/freescale/imx arm/include arm/mv arm/nvidia arm/ti/omap4 kern sys

Svatopluk Kraus skra at FreeBSD.org
Mon Apr 4 09:15:27 UTC 2016


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 <sys/param.h>
 #include <sys/systm.h>
 #include <sys/bus.h>
@@ -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 ***


More information about the svn-src-head mailing list