summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPatrick Wildt <patrick@cvs.openbsd.org>2017-02-25 17:04:20 +0000
committerPatrick Wildt <patrick@cvs.openbsd.org>2017-02-25 17:04:20 +0000
commit747b06d278acad22f1e6db603d48427ef63a8180 (patch)
treed6e914921c2fe61b4de0bb6db8d85d9653c8f742
parent3f9cdfb0e749a8ee3a5e441fb752b55bbec3509c (diff)
Implement ampintcmsi(4) in ampintc(4) to support MSI. The GICv2M is an
extension to the GIC controller, which is represented as subnode in the device tree. There can be multiple GICv2Ms, so it makes sense to attach those to ampintc(4) as some kind of simplebus. The GICv2M is simply an interrupt generator that can be used by PCIe devices to ring the door bell. There is no need for further configuration, we only need to find out which SPIs we are allowed to use for MSI and to register an edge triggered interrupt on a (randomly) allocated SPI. ok kettenis@
-rw-r--r--sys/arch/arm64/conf/files.arm648
-rw-r--r--sys/arch/arm64/dev/ampintc.c128
2 files changed, 129 insertions, 7 deletions
diff --git a/sys/arch/arm64/conf/files.arm64 b/sys/arch/arm64/conf/files.arm64
index 89a54d8f0d6..e2370431497 100644
--- a/sys/arch/arm64/conf/files.arm64
+++ b/sys/arch/arm64/conf/files.arm64
@@ -1,4 +1,4 @@
-# $OpenBSD: files.arm64,v 1.10 2017/02/24 10:13:13 patrick Exp $
+# $OpenBSD: files.arm64,v 1.11 2017/02/25 17:04:19 patrick Exp $
maxpartitions 16
maxusers 2 8 64
@@ -115,9 +115,11 @@ device pluart
attach pluart at fdt
file arch/arm64/dev/pluart.c pluart
-device ampintc
+device ampintc: fdt
attach ampintc at fdt
-file arch/arm64/dev/ampintc.c ampintc
+device ampintcmsi
+attach ampintcmsi at fdt
+file arch/arm64/dev/ampintc.c ampintc | ampintcmsi
device agtimer
attach agtimer at fdt
diff --git a/sys/arch/arm64/dev/ampintc.c b/sys/arch/arm64/dev/ampintc.c
index 5a2e127608b..11953200981 100644
--- a/sys/arch/arm64/dev/ampintc.c
+++ b/sys/arch/arm64/dev/ampintc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: ampintc.c,v 1.6 2017/02/25 13:19:57 patrick Exp $ */
+/* $OpenBSD: ampintc.c,v 1.7 2017/02/25 17:04:19 patrick Exp $ */
/*
* Copyright (c) 2007,2009,2011 Dale Rahn <drahn@openbsd.org>
*
@@ -27,12 +27,16 @@
#include <sys/device.h>
#include <sys/evcount.h>
+#include <uvm/uvm_extern.h>
+
#include <machine/bus.h>
#include <machine/fdt.h>
#include <dev/ofw/fdt.h>
#include <dev/ofw/openfirm.h>
+#include <arm64/dev/simplebusvar.h>
+
/* registers */
#define ICD_DCR 0x000
#define ICD_DCR_ES 0x00000001
@@ -129,7 +133,7 @@
#define IRQ_DISABLE 0
struct ampintc_softc {
- struct device sc_dev;
+ struct simplebus_softc sc_sbus;
struct intrq *sc_ampintc_handler;
int sc_nintr;
bus_space_tag_t sc_iot;
@@ -240,7 +244,7 @@ ampintc_attach(struct device *parent, struct device *self, void *aux)
ICD_ICTR) & ICD_ICTR_ITL_M);
nintr += 32; /* ICD_ICTR + 1, irq 0-31 is SGI, 32+ is PPI */
sc->sc_nintr = nintr;
- printf(" nirq %d\n", nintr);
+ printf(" nirq %d", nintr);
/* Disable all interrupts, clear all pending */
for (i = 0; i < nintr/32; i++) {
@@ -288,6 +292,9 @@ ampintc_attach(struct device *parent, struct device *self, void *aux)
sc->sc_ic.ic_establish = ampintc_intr_establish_fdt;
sc->sc_ic.ic_disestablish = ampintc_intr_disestablish;
arm_intr_register_fdt(&sc->sc_ic);
+
+ /* attach GICv2M frame controller */
+ simplebus_attach(parent, &sc->sc_sbus.sc_dev, faa);
}
void
@@ -558,7 +565,7 @@ ampintc_intr_establish_fdt(void *cookie, int *cell, int level,
else if (cell[0] == 1)
irq += 16;
else
- panic("%s: bogus interrupt type", sc->sc_dev.dv_xname);
+ panic("%s: bogus interrupt type", sc->sc_sbus.sc_dev.dv_xname);
/* SPIs are only active-high level or low-to-high edge */
if (cell[2] & 0x3)
@@ -640,3 +647,116 @@ ampintc_intr_string(void *cookie)
snprintf(irqstr, sizeof irqstr, "ampintc irq %d", ih->ih_irq);
return irqstr;
}
+
+/*
+ * GICv2m frame controller for MSI interrupts.
+ */
+#define GICV2M_TYPER 0x008
+#define GICV2M_TYPER_SPI_BASE(x) (((x) >> 16) & 0x3ff)
+#define GICV2M_TYPER_SPI_COUNT(x) (((x) >> 0) & 0x3ff)
+#define GICV2M_SETSPI_NS 0x040
+
+int ampintc_msi_match(struct device *, void *, void *);
+void ampintc_msi_attach(struct device *, struct device *, void *);
+void *ampintc_intr_establish_msi(void *, uint64_t *, uint64_t *,
+ int , int (*)(void *), void *, char *);
+void ampintc_intr_disestablish_msi(void *);
+
+struct ampintc_msi_softc {
+ struct device sc_dev;
+ bus_space_tag_t sc_iot;
+ bus_space_handle_t sc_ioh;
+ paddr_t sc_addr;
+ int sc_bspi;
+ int sc_nspi;
+ void **sc_spi;
+ struct interrupt_controller sc_ic;
+};
+
+struct cfattach ampintcmsi_ca = {
+ sizeof (struct ampintc_msi_softc), ampintc_msi_match, ampintc_msi_attach
+};
+
+struct cfdriver ampintcmsi_cd = {
+ NULL, "ampintcmsi", DV_DULL
+};
+
+int
+ampintc_msi_match(struct device *parent, void *cfdata, void *aux)
+{
+ struct fdt_attach_args *faa = aux;
+
+ return OF_is_compatible(faa->fa_node, "arm,gic-v2m-frame");
+}
+
+void
+ampintc_msi_attach(struct device *parent, struct device *self, void *aux)
+{
+ struct ampintc_msi_softc *sc = (struct ampintc_msi_softc *)self;
+ struct fdt_attach_args *faa = aux;
+ uint32_t typer;
+
+ sc->sc_iot = faa->fa_iot;
+ if (bus_space_map(sc->sc_iot, faa->fa_reg[0].addr,
+ faa->fa_reg[0].size, 0, &sc->sc_ioh))
+ panic("%s: bus_space_map failed!", __func__);
+
+ /* XXX: Hack to retrieve the physical address (from a CPU PoV). */
+ if (!pmap_extract(pmap_kernel(), sc->sc_ioh, &sc->sc_addr)) {
+ printf(": cannot retrieve msi addr\n");
+ return;
+ }
+
+ typer = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GICV2M_TYPER);
+ sc->sc_bspi = GICV2M_TYPER_SPI_BASE(typer);
+ sc->sc_nspi = GICV2M_TYPER_SPI_COUNT(typer);
+
+ sc->sc_bspi = OF_getpropint(faa->fa_node,
+ "arm,msi-base-spi", sc->sc_bspi);
+ sc->sc_nspi = OF_getpropint(faa->fa_node,
+ "arm,msi-num-spis", sc->sc_nspi);
+
+ printf(": nspi %d\n", sc->sc_nspi);
+
+ sc->sc_spi = mallocarray(sc->sc_nspi, sizeof(int), M_DEVBUF,
+ M_WAITOK|M_ZERO);
+
+ sc->sc_ic.ic_node = faa->fa_node;
+ sc->sc_ic.ic_cookie = sc;
+ sc->sc_ic.ic_establish_msi = ampintc_intr_establish_msi;
+ sc->sc_ic.ic_disestablish = ampintc_intr_disestablish_msi;
+ arm_intr_register_fdt(&sc->sc_ic);
+}
+
+void *
+ampintc_intr_establish_msi(void *self, uint64_t *addr, uint64_t *data,
+ int level, int (*func)(void *), void *arg, char *name)
+{
+ struct ampintc_msi_softc *sc = (struct ampintc_msi_softc *)self;
+ void *cookie;
+ int i;
+
+ for (i = 0; i < sc->sc_nspi; i++) {
+ if (sc->sc_spi[i] != NULL)
+ continue;
+
+ cookie = ampintc_intr_establish_ext(sc->sc_bspi + i,
+ IST_EDGE_RISING, level, func, arg, name);
+ if (cookie == NULL)
+ return NULL;
+
+ *addr = sc->sc_addr + GICV2M_SETSPI_NS;
+ *data = sc->sc_bspi + i + 32;
+ sc->sc_spi[i] = cookie;
+ return &sc->sc_spi[i];
+ }
+
+ return NULL;
+}
+
+void
+ampintc_intr_disestablish_msi(void *cookie)
+{
+ ampintc_intr_disestablish(*(void **)cookie);
+ *(void **)cookie = NULL;
+}