summaryrefslogtreecommitdiffstats
path: root/sys/arm/mv
diff options
context:
space:
mode:
authorwma <wma@FreeBSD.org>2016-03-14 07:05:41 +0000
committerwma <wma@FreeBSD.org>2016-03-14 07:05:41 +0000
commit5715f97c308d18a485f4faf6bb9c9051b18f8f59 (patch)
tree61f173746c08c86637dae811733827b7c8a9e2e4 /sys/arm/mv
parent42f0174557e14915d527a5cbba5bd40d9b6e7732 (diff)
downloadFreeBSD-src-5715f97c308d18a485f4faf6bb9c9051b18f8f59.zip
FreeBSD-src-5715f97c308d18a485f4faf6bb9c9051b18f8f59.tar.gz
Make MPIC compatible with ARM_INTRNG
After ARM_INTRNG introduction, MPIC code needed several modifications: - IRQ resource and its handler added - several DEVMETHODs of INTRNG interface implemented - defines enhanced to ensure code compiles as well for AXP as for A38X - added dummy MSI_IRQ, ERR_IRQ defines for Armada38x - MPIC driver was added to files.armada38x, ARM_INTRNG option enabled in kernconf file and regs of MPIC corrected in dts file. Instead of modifying Armada38X DTS, offsets to CPU registers defined in driver were changed. That required restoring 'reg' property of mpic node in ArmadaXP to state compliant with Linux DTS. Additionally, required ARM_INTRNG definitions were added to mv_common.c. Submitted by: Bartosz Szczepanek <bsz@semihalf.com> Obtained from: Semihalf Sponsored by: Stormshield Reviewed by: adrian, andrew, ian, skra Approved by: cognet (mentor) Differential Revision: https://reviews.freebsd.org/D5030
Diffstat (limited to 'sys/arm/mv')
-rw-r--r--sys/arm/mv/armada38x/files.armada38x1
-rw-r--r--sys/arm/mv/mpic.c346
-rw-r--r--sys/arm/mv/mvreg.h5
3 files changed, 298 insertions, 54 deletions
diff --git a/sys/arm/mv/armada38x/files.armada38x b/sys/arm/mv/armada38x/files.armada38x
index e246f58..599919d 100644
--- a/sys/arm/mv/armada38x/files.armada38x
+++ b/sys/arm/mv/armada38x/files.armada38x
@@ -1,4 +1,5 @@
# $FreeBSD$
+arm/mv/mpic.c standard
arm/mv/armada38x/armada38x.c standard
arm/mv/armada38x/armada38x_mp.c optional smp
diff --git a/sys/arm/mv/mpic.c b/sys/arm/mv/mpic.c
index ebd1477..e81820c 100644
--- a/sys/arm/mv/mpic.c
+++ b/sys/arm/mv/mpic.c
@@ -33,14 +33,20 @@
#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/cpuset.h>
#include <sys/ktr.h>
+#include <sys/kdb.h>
#include <sys/module.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
#include <sys/rman.h>
+#include <sys/proc.h>
#include <machine/bus.h>
#include <machine/intr.h>
@@ -48,11 +54,16 @@ __FBSDID("$FreeBSD$");
#include <machine/smp.h>
#include <arm/mv/mvvar.h>
+#include <arm/mv/mvreg.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
#include <dev/fdt/fdt_common.h>
+#ifdef ARM_INTRNG
+#include "pic_if.h"
+#endif
+
#ifdef DEBUG
#define debugf(fmt, args...) do { printf("%s(): ", __func__); \
printf(fmt,##args); } while (0)
@@ -60,46 +71,63 @@ __FBSDID("$FreeBSD$");
#define debugf(fmt, args...)
#endif
-#define MPIC_INT_ERR 4
-#define MPIC_INT_MSI 96
+#define MPIC_INT_ERR 4
+#define MPIC_INT_MSI 96
-#define IRQ_MASK 0x3ff
+#define IRQ_MASK 0x3ff
-#define MPIC_CTRL 0x0
-#define MPIC_SOFT_INT 0x4
-#define MPIC_SOFT_INT_DRBL1 (1 << 5)
-#define MPIC_ERR_CAUSE 0x20
-#define MPIC_ISE 0x30
-#define MPIC_ICE 0x34
+#define MPIC_CTRL 0x0
+#define MPIC_SOFT_INT 0x4
+#define MPIC_SOFT_INT_DRBL1 (1 << 5)
+#define MPIC_ERR_CAUSE 0x20
+#define MPIC_ISE 0x30
+#define MPIC_ICE 0x34
+#define MPIC_INT_CTL(irq) (0x100 + (irq)*4)
+#define MPIC_INT_IRQ_FIQ_MASK(cpuid) (0x101 << (cpuid))
+#define MPIC_CTRL_NIRQS(ctrl) (((ctrl) >> 2) & 0x3ff)
-#define MPIC_IN_DRBL 0x78
-#define MPIC_IN_DRBL_MASK 0x7c
-#define MPIC_CTP 0xb0
-#define MPIC_CTP 0xb0
-#define MPIC_IIACK 0xb4
-#define MPIC_ISM 0xb8
-#define MPIC_ICM 0xbc
-#define MPIC_ERR_MASK 0xec0
+#define MPIC_IN_DRBL 0x08
+#define MPIC_IN_DRBL_MASK 0x0c
+#define MPIC_PPI_CAUSE 0x10
+#define MPIC_CTP 0x40
+#define MPIC_IIACK 0x44
+#define MPIC_ISM 0x48
+#define MPIC_ICM 0x4c
+#define MPIC_ERR_MASK 0xe50
+
+#define MPIC_PPI 32
struct mv_mpic_softc {
device_t sc_dev;
- struct resource * mpic_res[3];
+ struct resource * mpic_res[4];
bus_space_tag_t mpic_bst;
bus_space_handle_t mpic_bsh;
bus_space_tag_t cpu_bst;
bus_space_handle_t cpu_bsh;
bus_space_tag_t drbl_bst;
bus_space_handle_t drbl_bsh;
+ struct mtx mtx;
+
+ struct intr_irqsrc ** mpic_isrcs;
+ int nirqs;
+ void * intr_hand;
};
static struct resource_spec mv_mpic_spec[] = {
{ SYS_RES_MEMORY, 0, RF_ACTIVE },
{ SYS_RES_MEMORY, 1, RF_ACTIVE },
- { SYS_RES_MEMORY, 2, RF_ACTIVE },
+ { SYS_RES_MEMORY, 2, RF_ACTIVE | RF_OPTIONAL },
+ { SYS_RES_IRQ, 0, RF_ACTIVE | RF_OPTIONAL },
{ -1, 0 }
};
+static struct ofw_compat_data compat_data[] = {
+ {"mrvl,mpic", true},
+ {"marvell,mpic", true},
+ {NULL, false}
+};
+
static struct mv_mpic_softc *mv_mpic_sc = NULL;
void mpic_send_ipi(int cpus, u_int ipi);
@@ -109,9 +137,21 @@ static int mv_mpic_attach(device_t);
uint32_t mv_mpic_get_cause(void);
uint32_t mv_mpic_get_cause_err(void);
uint32_t mv_mpic_get_msi(void);
+static void mpic_unmask_irq(uintptr_t nb);
+static void mpic_mask_irq(uintptr_t nb);
+static void mpic_mask_irq_err(uintptr_t nb);
+static void mpic_unmask_irq_err(uintptr_t nb);
+static int mpic_intr(void *arg);
+static void mpic_unmask_msi(void);
+#ifndef ARM_INTRNG
static void arm_mask_irq_err(uintptr_t);
static void arm_unmask_irq_err(uintptr_t);
-static void arm_unmask_msi(void);
+#endif
+
+#define MPIC_WRITE(softc, reg, val) \
+ bus_space_write_4((softc)->mpic_bst, (softc)->mpic_bsh, (reg), (val))
+#define MPIC_READ(softc, reg) \
+ bus_space_read_4((softc)->mpic_bst, (softc)->mpic_bsh, (reg))
#define MPIC_CPU_WRITE(softc, reg, val) \
bus_space_write_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg), (val))
@@ -130,7 +170,7 @@ mv_mpic_probe(device_t dev)
if (!ofw_bus_status_okay(dev))
return (ENXIO);
- if (!ofw_bus_is_compatible(dev, "mrvl,mpic"))
+ if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data)
return (ENXIO);
device_set_desc(dev, "Marvell Integrated Interrupt Controller");
@@ -142,6 +182,7 @@ mv_mpic_attach(device_t dev)
{
struct mv_mpic_softc *sc;
int error;
+ uint32_t val;
sc = (struct mv_mpic_softc *)device_get_softc(dev);
@@ -151,11 +192,20 @@ mv_mpic_attach(device_t dev)
sc->sc_dev = dev;
+ mtx_init(&sc->mtx, "MPIC lock", NULL, MTX_SPIN);
+
error = bus_alloc_resources(dev, mv_mpic_spec, sc->mpic_res);
if (error) {
device_printf(dev, "could not allocate resources\n");
return (ENXIO);
}
+#ifdef ARM_INTRNG
+ if (sc->mpic_res[3] == NULL)
+ device_printf(dev, "No interrupt to use.\n");
+ else
+ bus_setup_intr(dev, sc->mpic_res[3], INTR_TYPE_CLK,
+ mpic_intr, NULL, sc, &sc->intr_hand);
+#endif
sc->mpic_bst = rman_get_bustag(sc->mpic_res[0]);
sc->mpic_bsh = rman_get_bushandle(sc->mpic_res[0]);
@@ -163,21 +213,182 @@ mv_mpic_attach(device_t dev)
sc->cpu_bst = rman_get_bustag(sc->mpic_res[1]);
sc->cpu_bsh = rman_get_bushandle(sc->mpic_res[1]);
- sc->drbl_bst = rman_get_bustag(sc->mpic_res[2]);
- sc->drbl_bsh = rman_get_bushandle(sc->mpic_res[2]);
+ if (sc->mpic_res[2] != NULL) {
+ /* This is required only if MSIs are used. */
+ sc->drbl_bst = rman_get_bustag(sc->mpic_res[2]);
+ sc->drbl_bsh = rman_get_bushandle(sc->mpic_res[2]);
+ }
bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
MPIC_CTRL, 1);
MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0);
- arm_unmask_msi();
+ val = MPIC_READ(mv_mpic_sc, MPIC_CTRL);
+ 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 (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);
+ return (ENXIO);
+ }
+#endif
+
+ mpic_unmask_msi();
+
+ return (0);
+}
+
+#ifdef ARM_INTRNG
+static int
+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;
+
+ for (cause = MPIC_CPU_READ(sc, MPIC_PPI_CAUSE); cause > 0;
+ cause >>= 1, irq++) {
+ if (cause & 1) {
+ 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);
+ mpic_mask_irq(irq);
+ continue;
+ }
+ 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)
+{
+ 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);
+
+ return (0);
+}
+
+#ifdef FDT
+static int
+mpic_map_fdt(struct mv_mpic_softc *sc, struct intr_irqsrc *isrc, u_int *irqp)
+{
+ 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);
}
+#endif
+
+static int
+mpic_register(device_t dev, struct intr_irqsrc *isrc, boolean_t *is_percpu)
+{
+ 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;
+
+ irq = isrc->isrc_data;
+ mpic_mask_irq(irq);
+}
+
+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);
+}
+
+static void
+mpic_post_ithread(device_t dev, struct intr_irqsrc *isrc)
+{
+
+ mpic_enable_source(dev, isrc);
+}
+#endif
static device_method_t mv_mpic_methods[] = {
DEVMETHOD(device_probe, mv_mpic_probe),
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_post_ithread, mpic_post_ithread),
+ DEVMETHOD(pic_pre_ithread, mpic_pre_ithread),
+#endif
{ 0, 0 }
};
@@ -189,8 +400,10 @@ static driver_t mv_mpic_driver = {
static devclass_t mv_mpic_devclass;
-DRIVER_MODULE(mpic, simplebus, mv_mpic_driver, mv_mpic_devclass, 0, 0);
+EARLY_DRIVER_MODULE(mpic, simplebus, mv_mpic_driver, mv_mpic_devclass, 0, 0,
+ BUS_PASS_INTERRUPT);
+#ifndef ARM_INTRNG
int
arm_get_next_irq(int last)
{
@@ -219,49 +432,42 @@ void
arm_mask_irq(uintptr_t nb)
{
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 1);
-
- if (nb < ERR_IRQ) {
- bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
- MPIC_ICE, nb);
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ISM, nb);
- } else if (nb < MSI_IRQ)
- arm_mask_irq_err(nb);
+ mpic_mask_irq(nb);
}
static void
arm_mask_irq_err(uintptr_t nb)
{
- uint32_t mask;
- uint8_t bit_off;
- bit_off = nb - ERR_IRQ;
- mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK);
- mask &= ~(1 << bit_off);
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask);
+ mpic_mask_irq_err(nb);
}
void
arm_unmask_irq(uintptr_t nb)
{
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0);
-
- if (nb < ERR_IRQ) {
- bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
- MPIC_ISE, nb);
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, nb);
- } else if (nb < MSI_IRQ)
- arm_unmask_irq_err(nb);
-
- if (nb == 0)
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL_MASK, 0xffffffff);
+ mpic_unmask_irq(nb);
}
void
arm_unmask_irq_err(uintptr_t nb)
{
+
+ mpic_unmask_irq_err(nb);
+}
+#endif
+
+static void
+mpic_unmask_msi(void)
+{
+
+ mpic_unmask_irq(MPIC_INT_MSI);
+}
+
+static void
+mpic_unmask_irq_err(uintptr_t nb)
+{
uint32_t mask;
uint8_t bit_off;
@@ -276,10 +482,42 @@ arm_unmask_irq_err(uintptr_t nb)
}
static void
-arm_unmask_msi(void)
+mpic_mask_irq_err(uintptr_t nb)
+{
+ uint32_t mask;
+ uint8_t bit_off;
+
+ bit_off = nb - ERR_IRQ;
+ mask = MPIC_CPU_READ(mv_mpic_sc, MPIC_ERR_MASK);
+ mask &= ~(1 << bit_off);
+ MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ERR_MASK, mask);
+}
+
+static void
+mpic_unmask_irq(uintptr_t nb)
+{
+
+ if (nb < ERR_IRQ) {
+ bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
+ MPIC_ISE, nb);
+ MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, nb);
+ } else if (nb < MSI_IRQ)
+ mpic_unmask_irq_err(nb);
+
+ if (nb == 0)
+ MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL_MASK, 0xffffffff);
+}
+
+static void
+mpic_mask_irq(uintptr_t nb)
{
- arm_unmask_irq(MPIC_INT_MSI);
+ if (nb < ERR_IRQ) {
+ bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
+ MPIC_ICE, nb);
+ MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ISM, nb);
+ } else if (nb < MSI_IRQ)
+ mpic_mask_irq_err(nb);
}
uint32_t
@@ -313,6 +551,7 @@ mv_mpic_get_msi(void)
uint32_t cause;
uint8_t bit_off;
+ KASSERT(mv_mpic_sc->drbl_bst != NULL, ("No doorbell in mv_mpic_get_msi"));
cause = MPIC_DRBL_READ(mv_mpic_sc, 0);
if (cause)
@@ -359,7 +598,8 @@ mv_msi_data(int irq, uint64_t *addr, uint32_t *data)
return (0);
}
-#if defined(SMP)
+
+#if defined(SMP) && defined(SOC_MV_ARMADAXP)
void
intr_pic_init_secondary(void)
{
diff --git a/sys/arm/mv/mvreg.h b/sys/arm/mv/mvreg.h
index 65151c1..abfefc1 100644
--- a/sys/arm/mv/mvreg.h
+++ b/sys/arm/mv/mvreg.h
@@ -67,7 +67,10 @@
#elif defined (SOC_MV_ARMADAXP)
#define IRQ_CAUSE 0x18
#define IRQ_MASK 0x30
-#else /* !SOC_MV_DISCOVERY && !SOC_MV_LOKIPLUS */
+#elif defined (SOC_MV_ARMADA38X)
+#define MSI_IRQ 0x3ff
+#define ERR_IRQ 0x3ff
+#else
#define IRQ_CAUSE 0x0
#define IRQ_MASK 0x4
#define FIQ_MASK 0x8
OpenPOWER on IntegriCloud