Page MenuHomeFreeBSD

D5730.id14855.diff
No OneTemporary

D5730.id14855.diff

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 <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -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 <sys/intr.h>
#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 <jceel@FreeBSD.org>
-# 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 <sys/bus.h>
#include <sys/cpuset.h>
-#include <machine/frame.h>
-#include <machine/intr.h>
+#include <sys/resource.h>
+#include <sys/intr.h>
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 <jceel@FreeBSD.org>.
- * 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 <sys/cdefs.h>
@@ -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 <sys/systm.h>
+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);

File Metadata

Mime Type
text/plain
Expires
Sun, Nov 16, 4:04 AM (5 h, 46 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
25351857
Default Alt Text
D5730.id14855.diff (81 KB)

Event Timeline