summaryrefslogtreecommitdiffstats
path: root/sys/arm/mv
diff options
context:
space:
mode:
authorgber <gber@FreeBSD.org>2012-09-14 10:05:01 +0000
committergber <gber@FreeBSD.org>2012-09-14 10:05:01 +0000
commite05458327787f58be689168dd8c70b873ac0e15f (patch)
treed085f84f3aa930d6e281896a4641da981be799ac /sys/arm/mv
parent1afc7a0a6c1ed154001ee92c0e4b26eb057205d5 (diff)
downloadFreeBSD-src-e05458327787f58be689168dd8c70b873ac0e15f.zip
FreeBSD-src-e05458327787f58be689168dd8c70b873ac0e15f.tar.gz
Add support for MSI in interrupt controlller.
MSI are implemented via software interrupt. PCIe cards will write into software interrupt register which will cause inbound shared interrupt which will be interpreted as a MSI. Obtained from: Marvell, Semihalf
Diffstat (limited to 'sys/arm/mv')
-rw-r--r--sys/arm/mv/mpic.c129
-rw-r--r--sys/arm/mv/mvvar.h2
2 files changed, 113 insertions, 18 deletions
diff --git a/sys/arm/mv/mpic.c b/sys/arm/mv/mpic.c
index ba8dde0..0a1be1d 100644
--- a/sys/arm/mv/mpic.c
+++ b/sys/arm/mv/mpic.c
@@ -1,6 +1,7 @@
/*-
* Copyright (c) 2006 Benno Rice.
* Copyright (C) 2007-2011 MARVELL INTERNATIONAL LTD.
+ * Copyright (c) 2012 Semihalf.
* All rights reserved.
*
* Developed by Semihalf.
@@ -46,23 +47,34 @@ __FBSDID("$FreeBSD$");
#include <machine/cpufunc.h>
#include <machine/smp.h>
+#include <arm/mv/mvvar.h>
+
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/fdt/fdt_common.h>
+
+#ifdef DEBUG
+#define debugf(fmt, args...) do { printf("%s(): ", __func__); \
+ printf(fmt,##args); } while (0)
+#else
+#define debugf(fmt, args...)
+#endif
-#define IRQ_ERR 4
-#define MAIN_IRQS 116
+#define MPIC_INT_ERR 4
+#define MPIC_INT_MSI 96
#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_IN_DOORBELL 0x78
-#define MPIC_IN_DOORBELL_MASK 0x7c
+#define MPIC_IN_DRBL 0x78
+#define MPIC_IN_DRBL_MASK 0x7c
#define MPIC_CTP 0xb0
#define MPIC_CTP 0xb0
#define MPIC_IIACK 0xb4
@@ -71,16 +83,20 @@ __FBSDID("$FreeBSD$");
#define MPIC_ERR_MASK 0xec0
struct mv_mpic_softc {
- struct resource * mpic_res[2];
+ device_t sc_dev;
+ struct resource * mpic_res[3];
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;
};
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 },
{ -1, 0 }
};
@@ -92,14 +108,21 @@ static int mv_mpic_probe(device_t);
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 arm_mask_irq_err(uintptr_t);
static void arm_unmask_irq_err(uintptr_t);
+static void arm_unmask_msi(void);
#define MPIC_CPU_WRITE(softc, reg, val) \
bus_space_write_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg), (val))
#define MPIC_CPU_READ(softc, reg) \
bus_space_read_4((softc)->cpu_bst, (softc)->cpu_bsh, (reg))
+#define MPIC_DRBL_WRITE(softc, reg, val) \
+ bus_space_write_4((softc)->drbl_bst, (softc)->drbl_bsh, (reg), (val))
+#define MPIC_DRBL_READ(softc, reg) \
+ bus_space_read_4((softc)->drbl_bst, (softc)->drbl_bsh, (reg))
+
static int
mv_mpic_probe(device_t dev)
{
@@ -123,6 +146,8 @@ mv_mpic_attach(device_t dev)
return (ENXIO);
mv_mpic_sc = sc;
+ sc->sc_dev = dev;
+
error = bus_alloc_resources(dev, mv_mpic_spec, sc->mpic_res);
if (error) {
device_printf(dev, "could not allocate resources\n");
@@ -135,10 +160,15 @@ 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]);
+
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();
+
return (0);
}
@@ -167,8 +197,10 @@ arm_get_next_irq(int last)
CTR2(KTR_INTR, "%s: irq:%#x", __func__, irq);
if (irq != IRQ_MASK) {
- if (irq == IRQ_ERR)
+ if (irq == MPIC_INT_ERR)
irq = mv_mpic_get_cause_err();
+ if (irq == MPIC_INT_MSI)
+ irq = mv_mpic_get_msi();
next = irq;
}
@@ -186,11 +218,11 @@ arm_mask_irq(uintptr_t nb)
MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 1);
- if (nb < MAIN_IRQS) {
+ 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
+ } else if (nb < MSI_IRQ)
arm_mask_irq_err(nb);
}
@@ -201,7 +233,7 @@ arm_mask_irq_err(uintptr_t nb)
uint32_t mask;
uint8_t bit_off;
- bit_off = nb - MAIN_IRQS;
+ 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);
@@ -213,15 +245,15 @@ arm_unmask_irq(uintptr_t nb)
MPIC_CPU_WRITE(mv_mpic_sc, MPIC_CTP, 0);
- if (nb < MAIN_IRQS) {
+ 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
+ } else if (nb < MSI_IRQ)
arm_unmask_irq_err(nb);
if (nb == 0)
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DOORBELL_MASK, 0xffffffff);
+ MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL_MASK, 0xffffffff);
}
void
@@ -231,15 +263,22 @@ arm_unmask_irq_err(uintptr_t nb)
uint8_t bit_off;
bus_space_write_4(mv_mpic_sc->mpic_bst, mv_mpic_sc->mpic_bsh,
- MPIC_ISE, IRQ_ERR);
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, IRQ_ERR);
+ MPIC_ISE, MPIC_INT_ERR);
+ MPIC_CPU_WRITE(mv_mpic_sc, MPIC_ICM, MPIC_INT_ERR);
- bit_off = nb - MAIN_IRQS;
+ 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
+arm_unmask_msi(void)
+{
+
+ arm_unmask_irq(MPIC_INT_MSI);
+}
+
uint32_t
mv_mpic_get_cause(void)
{
@@ -260,7 +299,61 @@ mv_mpic_get_cause_err(void)
bit_off = ffs(err_cause) - 1;
else
return (-1);
- return (MAIN_IRQS + bit_off);
+
+ debugf("%s: irq:%x cause:%x\n", __func__, bit_off, err_cause);
+ return (ERR_IRQ + bit_off);
+}
+
+uint32_t
+mv_mpic_get_msi(void)
+{
+ uint32_t cause;
+ uint8_t bit_off;
+
+ cause = MPIC_DRBL_READ(mv_mpic_sc, 0);
+
+ if (cause)
+ bit_off = ffs(cause) - 1;
+ else
+ return (-1);
+
+ debugf("%s: irq:%x cause:%x\n", __func__, bit_off, cause);
+
+ cause &= ~(1 << bit_off);
+ MPIC_DRBL_WRITE(mv_mpic_sc, 0, cause);
+
+ return (MSI_IRQ + bit_off);
+}
+
+int
+mv_msi_data(int irq, uint64_t *addr, uint32_t *data)
+{
+ u_long phys, base, size;
+ phandle_t node;
+ int error;
+
+ node = ofw_bus_get_node(mv_mpic_sc->sc_dev);
+
+ /* Get physical addres of register space */
+ error = fdt_get_range(OF_parent(node), 0, &phys, &size);
+ if (error) {
+ printf("%s: Cannot get register physical address, err:%d",
+ __func__, error);
+ return (error);
+ }
+
+ /* Get offset of MPIC register space */
+ error = fdt_regsize(node, &base, &size);
+ if (error) {
+ printf("%s: Cannot get MPIC register offset, err:%d",
+ __func__, error);
+ return (error);
+ }
+
+ *addr = phys + base + MPIC_SOFT_INT;
+ *data = MPIC_SOFT_INT_DRBL1 | irq;
+
+ return (0);
}
#if defined(SMP)
@@ -283,7 +376,7 @@ pic_ipi_get(int i __unused)
{
uint32_t val;
- val = MPIC_CPU_READ(mv_mpic_sc, MPIC_IN_DOORBELL);
+ val = MPIC_CPU_READ(mv_mpic_sc, MPIC_IN_DRBL);
if (val)
return (ffs(val) - 1);
@@ -296,7 +389,7 @@ pic_ipi_clear(int ipi)
uint32_t val;
val = ~(1 << ipi);
- MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DOORBELL, val);
+ MPIC_CPU_WRITE(mv_mpic_sc, MPIC_IN_DRBL, val);
}
#endif
diff --git a/sys/arm/mv/mvvar.h b/sys/arm/mv/mvvar.h
index 4a2c87d..002640c 100644
--- a/sys/arm/mv/mvvar.h
+++ b/sys/arm/mv/mvvar.h
@@ -134,4 +134,6 @@ uint32_t mv_drbl_get_cause(int dir, int unit);
void mv_drbl_set_msg(uint32_t val, int mnr, int dir, int unit);
uint32_t mv_drbl_get_msg(int mnr, int dir, int unit);
+int mv_msi_data(int irq, uint64_t *addr, uint32_t *data);
+
#endif /* _MVVAR_H_ */
OpenPOWER on IntegriCloud