Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F136021308
D5730.id14855.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
81 KB
Referenced Files
None
Subscribers
None
D5730.id14855.diff
View Options
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
Details
Attached
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)
Attached To
Mode
D5730: INTRNG generalization step 1 - new PIC interface and BUS related functions
Attached
Detach File
Event Timeline
Log In to Comment