Page MenuHomeFreeBSD

D2048.id7985.diff
No OneTemporary

D2048.id7985.diff

Index: sys/arm/arm/gic.c
===================================================================
--- sys/arm/arm/gic.c
+++ sys/arm/arm/gic.c
@@ -34,18 +34,25 @@
#include <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/ktr.h>
#include <sys/module.h>
+#include <sys/malloc.h>
#include <sys/rman.h>
#include <sys/pcpu.h>
#include <sys/proc.h>
#include <sys/cpuset.h>
#include <sys/lock.h>
#include <sys/mutex.h>
+#include <sys/smp.h>
+#ifdef ARM_INTRNG
+#include <sys/sched.h>
+#endif
#include <machine/bus.h>
#include <machine/intr.h>
#include <machine/smp.h>
@@ -55,6 +62,10 @@
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#ifdef ARM_INTRNG
+#include "pic_if.h"
+#endif
+
/* We are using GICv2 register naming */
/* Distributor Registers */
@@ -83,8 +94,8 @@
#define GICC_ABPR 0x001C /* v1 ICCABPR */
#define GICC_IIDR 0x00FC /* v1 ICCIIDR*/
-#define GIC_FIRST_IPI 0 /* Irqs 0-15 are SGIs/IPIs. */
-#define GIC_LAST_IPI 15
+#define GIC_FIRST_SGI 0 /* Irqs 0-15 are SGIs/IPIs. */
+#define GIC_LAST_SGI 15
#define GIC_FIRST_PPI 16 /* Irqs 16-31 are private (per */
#define GIC_LAST_PPI 31 /* core) peripheral interrupts. */
#define GIC_FIRST_SPI 32 /* Irqs 32+ are shared peripherals. */
@@ -102,8 +113,18 @@
#define GIC_DEFAULT_ICFGR_INIT 0x00000000
#endif
+#ifdef ARM_INTRNG
+static u_int gic_irq_cpu;
+static int arm_gic_intr(void *, struct trapframe *);
+static int arm_gic_bind(device_t dev, struct arm_irqsrc *isrc);
+#endif
+
struct arm_gic_softc {
device_t gic_dev;
+#ifdef ARM_INTRNG
+ void * gic_intrhand;
+ struct arm_irqsrc ** gic_irqs;
+#endif
struct resource * gic_res[3];
bus_space_tag_t gic_c_bst;
bus_space_tag_t gic_d_bst;
@@ -117,10 +138,13 @@
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 */
+#ifdef ARM_INTRNG
+ { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL }, /* Parent interrupt */
+#endif
{ -1, 0 }
};
-static struct arm_gic_softc *arm_gic_sc = NULL;
+static struct arm_gic_softc *gic_sc = NULL;
#define gic_c_read_4(_sc, _reg) \
bus_space_read_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg))
@@ -128,12 +152,16 @@
bus_space_write_4((_sc)->gic_c_bst, (_sc)->gic_c_bsh, (_reg), (_val))
#define gic_d_read_4(_sc, _reg) \
bus_space_read_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg))
+#define gic_d_write_1(_sc, _reg, _val) \
+ bus_space_write_1((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
#define gic_d_write_4(_sc, _reg, _val) \
bus_space_write_4((_sc)->gic_d_bst, (_sc)->gic_d_bsh, (_reg), (_val))
+#ifndef ARM_INTRNG
static int gic_config_irq(int irq, enum intr_trigger trig,
enum intr_polarity pol);
static void gic_post_filter(void *);
+#endif
static struct ofw_compat_data compat_data[] = {
{"arm,gic", true}, /* Non-standard, used in FreeBSD dts. */
@@ -159,6 +187,72 @@
return (BUS_PROBE_DEFAULT);
}
+#ifdef ARM_INTRNG
+static inline void
+gic_irq_unmask(struct arm_gic_softc *sc, u_int irq)
+{
+
+ gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
+}
+
+static inline void
+gic_irq_mask(struct arm_gic_softc *sc, u_int irq)
+{
+
+ gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
+}
+#endif
+
+#ifdef SMP
+#ifdef ARM_INTRNG
+static void
+arm_gic_init_secondary(device_t dev)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ struct arm_irqsrc *isrc;
+ u_int irq;
+
+ for (irq = 0; irq < sc->nirqs; irq += 4)
+ gic_d_write_4(sc, GICD_IPRIORITYR(irq >> 2), 0);
+
+ /* Set all the interrupts to be in Group 0 (secure) */
+ for (irq = 0; irq < sc->nirqs; irq += 32) {
+ gic_d_write_4(sc, GICD_IGROUPR(irq >> 5), 0);
+ }
+
+ /* Enable CPU interface */
+ gic_c_write_4(sc, GICC_CTLR, 1);
+
+ /* Set priority mask register. */
+ gic_c_write_4(sc, GICC_PMR, 0xff);
+
+ /* Enable interrupt distribution */
+ gic_d_write_4(sc, GICD_CTLR, 0x01);
+
+ /* Unmask attached SGI interrupts. */
+ for (irq = GIC_FIRST_SGI; irq <= GIC_LAST_SGI; irq++) {
+ isrc = sc->gic_irqs[irq];
+ if (isrc != NULL && isrc->isrc_handlers != 0) {
+ CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
+ gic_irq_unmask(sc, irq);
+ }
+ }
+
+ /* Unmask attached PPI interrupts. */
+ for (irq = GIC_FIRST_PPI; irq <= GIC_LAST_PPI; irq++) {
+ isrc = sc->gic_irqs[irq];
+ if (isrc == NULL || isrc->isrc_handlers == 0)
+ continue;
+ if (isrc->isrc_flags & ARM_ISRCF_BOUND) {
+ if (CPU_ISSET(PCPU_GET(cpuid), &isrc->isrc_cpu))
+ gic_irq_unmask(sc, irq);
+ } else {
+ CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
+ gic_irq_unmask(sc, irq);
+ }
+ }
+}
+#else
static void
arm_gic_init_secondary(device_t dev)
{
@@ -189,7 +283,10 @@
gic_d_write_4(sc, GICD_ISENABLER(29 >> 5), (1UL << (29 & 0x1F)));
gic_d_write_4(sc, GICD_ISENABLER(30 >> 5), (1UL << (30 & 0x1F)));
}
-
+#endif /* ARM_INTRNG */
+#endif /* SMP */
+
+#ifndef ARM_INTRNG
int
gic_decode_fdt(uint32_t iparent, uint32_t *intr, int *interrupt,
int *trig, int *pol)
@@ -234,6 +331,19 @@
}
return (0);
}
+#endif
+
+#ifdef ARM_INTRNG
+static inline intptr_t
+gic_xref(device_t dev)
+{
+#ifdef FDT
+ return (OF_xref_from_node(ofw_bus_get_node(dev)));
+#else
+ return (0);
+#endif
+}
+#endif
static int
arm_gic_attach(device_t dev)
@@ -241,8 +351,11 @@
struct arm_gic_softc *sc;
int i;
uint32_t icciidr;
+#ifdef ARM_INTRNG
+ intptr_t xref = gic_xref(dev);
+#endif
- if (arm_gic_sc)
+ if (gic_sc)
return (ENXIO);
sc = device_get_softc(dev);
@@ -253,7 +366,7 @@
}
sc->gic_dev = dev;
- arm_gic_sc = sc;
+ gic_sc = sc;
/* Initialize mutex */
mtx_init(&sc->mutex, "GIC lock", "", MTX_SPIN);
@@ -273,9 +386,14 @@
sc->nirqs = gic_d_read_4(sc, GICD_TYPER);
sc->nirqs = 32 * ((sc->nirqs & 0x1f) + 1);
+#ifdef ARM_INTRNG
+ sc->gic_irqs = malloc(sc->nirqs * sizeof (*sc->gic_irqs), M_DEVBUF,
+ M_WAITOK | M_ZERO);
+#else
/* Set up function pointers */
arm_post_filter = gic_post_filter;
arm_config_irq = gic_config_irq;
+#endif
icciidr = gic_c_read_4(sc, GICC_IIDR);
device_printf(dev,"pn 0x%x, arch 0x%x, rev 0x%x, implementer 0x%x irqs %u\n",
@@ -311,11 +429,454 @@
/* Enable interrupt distribution */
gic_d_write_4(sc, GICD_CTLR, 0x01);
+#ifndef ARM_INTRNG
+ return (0);
+#else
+ /*
+ * Now, when everything is initialized, it's right time to
+ * register interrupt controller to interrupt framefork.
+ */
+ if (arm_pic_register(dev, xref) != 0) {
+ device_printf(dev, "could not register PIC\n");
+ goto cleanup;
+ }
+
+ if (sc->gic_res[2] == NULL) {
+ if (arm_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");
+ arm_pic_unregister(dev, xref);
+ goto cleanup;
+ }
+ } else {
+ if (bus_setup_intr(dev, sc->gic_res[2], INTR_TYPE_MISC |
+ INTR_SOLO, (void*)arm_gic_intr, NULL, sc,
+ &sc->gic_intrhand)) {
+ device_printf(dev, "could not setup irq handler\n");
+ arm_pic_unregister(dev, xref);
+ goto cleanup;
+ }
+ }
+
+ return (0);
+
+cleanup:
+ /*
+ * XXX - not implemented arm_gic_detach() should be called !
+ */
+ if (sc->gic_irqs != NULL)
+ free(sc->gic_irqs, M_DEVBUF);
+ bus_release_resources(dev, arm_gic_spec, sc->gic_res);
+ return(ENXIO);
+#endif
+}
+
+#ifdef ARM_INTRNG
+static int
+arm_gic_intr(void *arg, struct trapframe *tf)
+{
+ struct arm_gic_softc *sc = arg;
+ struct arm_irqsrc *isrc;
+ uint32_t irq_active_reg, irq;
+
+ irq_active_reg = gic_c_read_4(sc, GICC_IAR);
+ irq = irq_active_reg & 0x3FF;
+
+ /*
+ * 1. We do EOI here because recent read value from active interrupt
+ * register must be used for it. Another approach is to save this
+ * value into associated interrupt source.
+ * 2. EOI must be done on same CPU where interrupt has fired. Thus
+ * we must ensure that interrupted thread does not migrate to
+ * another CPU.
+ * 3. EOI cannot be delayed by any preemption which could happen on
+ * critical_exit() used in MI intr code, when interrupt thread is
+ * scheduled. See next point.
+ * 4. IPI_RENDEZVOUS assumes that no preemption is permitted during
+ * an action and any use of critical_exit() could break this
+ * assumption. See comments within smp_rendezvous_action().
+ * 5. We always return FILTER_HANDLED as this is an interrupt
+ * controller dispatch function. Otherwise, in cascaded interrupt
+ * case, the whole interrupt subtree would be masked.
+ */
+
+ if (irq >= sc->nirqs) {
+ device_printf(sc->gic_dev, "Spurious interrupt detected\n");
+ gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
+ return (FILTER_HANDLED);
+ }
+
+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;
+ }
+
+ /*
+ * 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.
+ */
+ if (irq <= GIC_LAST_SGI) {
+#ifdef SMP
+ /* Call EOI for all IPI before dispatch. */
+ gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
+ arm_ipi_dispatch(isrc, tf);
+ goto next_irq;
+#else
+ printf("SGI %u on UP system detected\n", irq - GIC_FIRST_SGI);
+ gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
+ goto next_irq;
+#endif
+ }
+
+ if (isrc->isrc_trig == INTR_TRIGGER_LEVEL) {
+ critical_enter();
+ arm_irq_dispatch(isrc, tf);
+ gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
+ critical_exit();
+ } else if (isrc->isrc_trig == INTR_TRIGGER_EDGE) {
+ gic_c_write_4(sc, GICC_EOIR, irq_active_reg);
+ arm_irq_dispatch(isrc, tf);
+ } else {
+ panic("%s: unknown trigger", __func__);
+ }
+
+next_irq:
+ arm_irq_memory_barrier(irq); /* XXX */
+ irq_active_reg = gic_c_read_4(sc, GICC_IAR);
+ irq = irq_active_reg & 0x3FF;
+ if (irq < sc->nirqs)
+ goto dispatch_irq;
+
+ return (FILTER_HANDLED);
+}
+
+static int
+gic_attach_isrc(struct arm_gic_softc *sc, struct arm_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)
+ arm_irq_set_name(isrc, "%s,i%u", name, irq - GIC_FIRST_SGI);
+ else if (irq <= GIC_LAST_PPI)
+ arm_irq_set_name(isrc, "%s,p%u", name, irq - GIC_FIRST_PPI);
+ else
+ arm_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 arm_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);
+
+ arm_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)
+{
+ uint32_t reg;
+ uint32_t mask;
+
+ if (irq < GIC_FIRST_SPI)
+ return;
+
+ mtx_lock_spin(&sc->mutex);
+
+ reg = gic_d_read_4(sc, GICD_ICFGR(irq >> 4));
+ mask = (reg >> 2*(irq % 16)) & 0x3;
+
+ if (pol == INTR_POLARITY_LOW) {
+ mask &= ~GICD_ICFGR_POL_MASK;
+ mask |= GICD_ICFGR_POL_LOW;
+ } else if (pol == INTR_POLARITY_HIGH) {
+ mask &= ~GICD_ICFGR_POL_MASK;
+ mask |= GICD_ICFGR_POL_HIGH;
+ }
+
+ if (trig == INTR_TRIGGER_LEVEL) {
+ mask &= ~GICD_ICFGR_TRIG_MASK;
+ mask |= GICD_ICFGR_TRIG_LVL;
+ } else if (trig == INTR_TRIGGER_EDGE) {
+ mask &= ~GICD_ICFGR_TRIG_MASK;
+ mask |= GICD_ICFGR_TRIG_EDGE;
+ }
+
+ /* Set mask */
+ reg = reg & ~(0x3 << 2*(irq % 16));
+ reg = reg | (mask << 2*(irq % 16));
+ gic_d_write_4(sc, GICD_ICFGR(irq >> 4), reg);
+
+ mtx_unlock_spin(&sc->mutex);
+}
+
+static int
+gic_bind(struct arm_gic_softc *sc, u_int irq, cpuset_t *cpus)
+{
+ uint32_t cpu, end, mask;
+ end = min(mp_ncpus, 8);
+ for (cpu = end; cpu < MAXCPU; cpu++)
+ if (CPU_ISSET(cpu, cpus))
+ return (EINVAL);
+
+ for (mask = 0, cpu = 0; cpu < end; cpu++)
+ if (CPU_ISSET(cpu, cpus))
+ mask |= 1 << cpu;
+
+ gic_d_write_1(sc, GICD_ITARGETSR(0) + irq, mask);
return (0);
}
static int
+gic_irq_from_nspc(struct arm_gic_softc *sc, u_int type, u_int num, u_int *irqp)
+{
+
+ switch (type) {
+ case ARM_IRQ_NSPC_PLAIN:
+ *irqp = num;
+ return (*irqp < sc->nirqs ? 0 : EINVAL);
+
+ case ARM_IRQ_NSPC_IRQ:
+ *irqp = num + GIC_FIRST_PPI;
+ return (*irqp < sc->nirqs ? 0 : EINVAL);
+
+ case ARM_IRQ_NSPC_IPI:
+ *irqp = num + GIC_FIRST_SGI;
+ return (*irqp < GIC_LAST_SGI ? 0 : EINVAL);
+
+ default:
+ return (EINVAL);
+ }
+}
+
+static int
+gic_map_nspc(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int *irqp)
+{
+ int error;
+
+ 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));
+}
+
+#ifdef FDT
+static int
+gic_map_fdt(struct arm_gic_softc *sc, struct arm_irqsrc *isrc, u_int *irqp)
+{
+ u_int irq, tripol;
+ enum intr_trigger trig;
+ 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;
+
+ /*
+ * 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) {
+ printf("unsupported trigger/polarity configuration "
+ "0x%2x\n", tripol & 0x0f);
+ return (ENOTSUP);
+ }
+ pol = INTR_POLARITY_CONFORM;
+ if (tripol & 0x01)
+ trig = INTR_TRIGGER_EDGE;
+ else
+ trig = INTR_TRIGGER_LEVEL;
+ } else
+ return (EINVAL);
+
+ if (irq >= sc->nirqs)
+ return (EINVAL);
+
+ error = gic_attach_isrc(sc, isrc, irq);
+ if (error != 0)
+ return (error);
+
+ isrc->isrc_nspc_type = ARM_IRQ_NSPC_PLAIN;
+ isrc->isrc_nspc_num = irq;
+ isrc->isrc_trig = trig;
+ isrc->isrc_pol = pol;
+
+ *irqp = irq;
+ return (0);
+}
+#endif
+
+static int
+arm_gic_register(device_t dev, struct arm_irqsrc *isrc, boolean_t *is_percpu)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ u_int irq;
+ int error;
+
+ if (isrc->isrc_type == ARM_ISRCT_NAMESPACE)
+ error = gic_map_nspc(sc, isrc, &irq);
+#ifdef FDT
+ else if (isrc->isrc_type == ARM_ISRCT_FDT)
+ error = gic_map_fdt(sc, isrc, &irq);
+#endif
+ else
+ return (EINVAL);
+
+ if (error == 0)
+ *is_percpu = irq < GIC_FIRST_SPI ? TRUE : FALSE;
+ return (error);
+}
+
+static void
+arm_gic_enable_intr(device_t dev, struct arm_irqsrc *isrc)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ u_int irq = isrc->isrc_data;
+
+ if (isrc->isrc_trig == INTR_TRIGGER_CONFORM)
+ isrc->isrc_trig = INTR_TRIGGER_LEVEL;
+
+ /*
+ * XXX - In case that per CPU interrupt is going to be enabled in time
+ * when SMP is already started, we need some IPI call which
+ * enables it on others CPUs. Further, it's more complicated as
+ * 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 & ARM_ISRCF_PERCPU)
+ CPU_SET(PCPU_GET(cpuid), &isrc->isrc_cpu);
+
+ gic_config(sc, irq, isrc->isrc_trig, isrc->isrc_pol);
+ arm_gic_bind(dev, isrc);
+}
+
+static void
+arm_gic_enable_source(device_t dev, struct arm_irqsrc *isrc)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ u_int irq = isrc->isrc_data;
+
+ arm_irq_memory_barrier(irq);
+ gic_irq_unmask(sc, irq);
+}
+
+static void
+arm_gic_disable_source(device_t dev, struct arm_irqsrc *isrc)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ u_int irq = isrc->isrc_data;
+
+ gic_irq_mask(sc, irq);
+}
+
+static int
+arm_gic_unregister(device_t dev, struct arm_irqsrc *isrc)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ u_int irq = isrc->isrc_data;
+
+ return (gic_detach_isrc(sc, isrc, irq));
+}
+
+static void
+arm_gic_pre_ithread(device_t dev, struct arm_irqsrc *isrc)
+{
+
+ arm_gic_disable_source(dev, isrc);
+ /* EOI must be done in controller's interrupt routine. */
+}
+
+static void
+arm_gic_post_ithread(device_t dev, struct arm_irqsrc *isrc)
+{
+
+ arm_gic_enable_source(dev, isrc);
+}
+
+static void
+arm_gic_post_filter(device_t dev, struct arm_irqsrc *isrc)
+{
+
+ /* EOI must be done in controller's interrupt routine. */
+}
+
+#ifdef SMP
+static int
+arm_gic_bind(device_t dev, struct arm_irqsrc *isrc)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ uint32_t irq = isrc->isrc_data;
+
+ if (irq < GIC_FIRST_SPI)
+ return (EINVAL);
+
+ if (CPU_EMPTY(&isrc->isrc_cpu)) {
+ gic_irq_cpu = arm_irq_next_cpu(gic_irq_cpu, &all_cpus);
+ CPU_SETOF(gic_irq_cpu, &isrc->isrc_cpu);
+ }
+ return (gic_bind(sc, irq, &isrc->isrc_cpu));
+}
+
+static void
+arm_gic_ipi_send(device_t dev, struct arm_irqsrc *isrc, cpuset_t cpus)
+{
+ struct arm_gic_softc *sc = device_get_softc(dev);
+ uint32_t irq, val = 0, i;
+
+ irq = isrc->isrc_data;
+
+ 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);
+}
+#endif
+#else
+static int
arm_gic_next_irq(struct arm_gic_softc *sc, int last_irq)
{
uint32_t active_irq;
@@ -327,7 +888,7 @@
* bits (ie CPU number), not just the IRQ number, and we do not
* have this information later.
*/
- if ((active_irq & 0x3ff) <= GIC_LAST_IPI)
+ if ((active_irq & 0x3ff) <= GIC_LAST_SGI)
gic_c_write_4(sc, GICC_EOIR, active_irq);
active_irq &= 0x3FF;
@@ -400,7 +961,7 @@
struct arm_gic_softc *sc = device_get_softc(dev);
gic_d_write_4(sc, GICD_ICENABLER(irq >> 5), (1UL << (irq & 0x1F)));
- gic_c_write_4(sc, GICC_EOIR, irq);
+ gic_c_write_4(sc, GICC_EOIR, irq); /* XXX - not allowed */
}
static void
@@ -408,7 +969,7 @@
{
struct arm_gic_softc *sc = device_get_softc(dev);
- if (irq > GIC_LAST_IPI)
+ if (irq > GIC_LAST_SGI)
arm_irq_memory_barrier(irq);
gic_d_write_4(sc, GICD_ISENABLER(irq >> 5), (1UL << (irq & 0x1F)));
@@ -455,10 +1016,10 @@
static void
gic_post_filter(void *arg)
{
- struct arm_gic_softc *sc = arm_gic_sc;
+ struct arm_gic_softc *sc = gic_sc;
uintptr_t irq = (uintptr_t) arg;
- if (irq > GIC_LAST_IPI)
+ if (irq > GIC_LAST_SGI)
arm_irq_memory_barrier(irq);
gic_c_write_4(sc, GICC_EOIR, irq);
}
@@ -467,64 +1028,81 @@
gic_config_irq(int irq, enum intr_trigger trig, enum intr_polarity pol)
{
- return (arm_gic_config(arm_gic_sc->gic_dev, irq, trig, pol));
+ return (arm_gic_config(gic_sc->gic_dev, irq, trig, pol));
}
void
arm_mask_irq(uintptr_t nb)
{
- arm_gic_mask(arm_gic_sc->gic_dev, nb);
+ arm_gic_mask(gic_sc->gic_dev, nb);
}
void
arm_unmask_irq(uintptr_t nb)
{
- arm_gic_unmask(arm_gic_sc->gic_dev, nb);
+ arm_gic_unmask(gic_sc->gic_dev, nb);
}
int
arm_get_next_irq(int last_irq)
{
- return (arm_gic_next_irq(arm_gic_sc, last_irq));
+ return (arm_gic_next_irq(gic_sc, last_irq));
}
+#ifdef SMP
void
arm_init_secondary_ic(void)
{
- arm_gic_init_secondary(arm_gic_sc->gic_dev);
+ arm_gic_init_secondary(gic_sc->gic_dev);
}
-#ifdef SMP
void
pic_ipi_send(cpuset_t cpus, u_int ipi)
{
- arm_gic_ipi_send(arm_gic_sc->gic_dev, cpus, ipi);
+ arm_gic_ipi_send(gic_sc->gic_dev, cpus, ipi);
}
int
pic_ipi_read(int i)
{
- return (arm_gic_ipi_read(arm_gic_sc->gic_dev, i));
+ return (arm_gic_ipi_read(gic_sc->gic_dev, i));
}
void
pic_ipi_clear(int ipi)
{
- arm_gic_ipi_clear(arm_gic_sc->gic_dev, ipi);
+ arm_gic_ipi_clear(gic_sc->gic_dev, ipi);
}
#endif
+#endif /* ARM_INTRNG */
static device_method_t arm_gic_methods[] = {
/* Device interface */
DEVMETHOD(device_probe, arm_gic_probe),
DEVMETHOD(device_attach, arm_gic_attach),
+#ifdef ARM_INTRNG
+ /* Interrupt controller interface */
+ DEVMETHOD(pic_disable_source, arm_gic_disable_source),
+ DEVMETHOD(pic_enable_intr, arm_gic_enable_intr),
+ DEVMETHOD(pic_enable_source, arm_gic_enable_source),
+ 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_init_secondary, arm_gic_init_secondary),
+ DEVMETHOD(pic_ipi_send, arm_gic_ipi_send),
+#endif
+#endif
{ 0, 0 }
};
Index: sys/arm/conf/PANDABOARD
===================================================================
--- sys/arm/conf/PANDABOARD
+++ sys/arm/conf/PANDABOARD
@@ -30,6 +30,8 @@
include "std.armv6"
include "../ti/omap4/pandaboard/std.pandaboard"
+options ARM_INTRNG # new interrupt framework
+
options HZ=100
options SCHED_ULE # ULE scheduler
options PLATFORM
Index: sys/arm/ti/omap4/omap4_mp.c
===================================================================
--- sys/arm/ti/omap4/omap4_mp.c
+++ sys/arm/ti/omap4/omap4_mp.c
@@ -44,7 +44,8 @@
void
platform_mp_init_secondary(void)
{
- arm_init_secondary_ic();
+
+ arm_pic_init_secondary();
}
void
@@ -62,7 +63,7 @@
return (1);
}
-void
+void
platform_mp_start_ap(void)
{
bus_addr_t scu_addr;
Index: sys/arm/ti/omap4/std.omap4
===================================================================
--- sys/arm/ti/omap4/std.omap4
+++ sys/arm/ti/omap4/std.omap4
@@ -17,7 +17,3 @@
options SOC_OMAP4
options ARM_L2_PIPT
-
-options IPI_IRQ_START=0
-options IPI_IRQ_END=15
-

File Metadata

Mime Type
text/plain
Expires
Sat, Mar 21, 11:38 PM (9 h, 48 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
30096961
Default Alt Text
D2048.id7985.diff (21 KB)

Event Timeline