summaryrefslogtreecommitdiff
path: root/sys
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2019-08-02 10:05:00 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2019-08-02 10:05:00 +0000
commit0554b1c8ea9c12f972d9beb634434759b0f7c94b (patch)
tree8593732e9b29c712078bf9c6fc24fbd39ae4b09f /sys
parent58e0953f50ce9d1193bc1c073c8a81fd0d2d8818 (diff)
Add support for additional ITS page sizes and make sure we allocate
enough memory for the device table to cover the entire DeviceID space. ok patrick@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/arm64/dev/agintc.c69
1 files changed, 61 insertions, 8 deletions
diff --git a/sys/arch/arm64/dev/agintc.c b/sys/arch/arm64/dev/agintc.c
index a1a89bd4132..956c10ae315 100644
--- a/sys/arch/arm64/dev/agintc.c
+++ b/sys/arch/arm64/dev/agintc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: agintc.c,v 1.21 2019/07/30 19:03:58 kettenis Exp $ */
+/* $OpenBSD: agintc.c,v 1.22 2019/08/02 10:04:59 kettenis Exp $ */
/*
* Copyright (c) 2007, 2009, 2011, 2017 Dale Rahn <drahn@dalerahn.com>
* Copyright (c) 2018 Mark Kettenis <kettenis@openbsd.org>
@@ -1159,6 +1159,7 @@ agintc_send_ipi(struct cpu_info *ci, int id)
#define GITS_TYPER_CIL (1ULL << 36)
#define GITS_TYPER_HCC(x) (((x) >> 24) & 0xff)
#define GITS_TYPER_PTA (1ULL << 19)
+#define GITS_TYPER_DEVBITS(x) (((x) >> 13) & 0x1f)
#define GITS_TYPER_ITE_SZ(x) (((x) >> 4) & 0xf)
#define GITS_TYPER_PHYS (1ULL << 0)
#define GITS_CBASER 0x0080
@@ -1173,9 +1174,16 @@ agintc_send_ipi(struct cpu_info *ci, int id)
#define GITS_BASER_IC_NORM_NC (1ULL << 59)
#define GITS_BASER_TYPE_MASK (7ULL << 56)
#define GITS_BASER_TYPE_DEVICE (1ULL << 56)
-#define GITS_BASER_MASK 0x7ffffffff000ULL
+#define GITS_BASER_DTE_SZ(x) (((x) >> 48) & 0x1f)
+#define GITS_BASER_PGSZ_MASK (3ULL << 8)
+#define GITS_BASER_PGSZ_4K (0ULL << 8)
+#define GITS_BASER_PGSZ_16K (1ULL << 8)
+#define GITS_BASER_PGSZ_64K (2ULL << 8)
+#define GITS_BASER_PA_MASK 0x7ffffffff000ULL
#define GITS_TRANSLATER 0x10040
+#define GITS_NUM_BASER 8
+
struct gits_cmd {
uint8_t cmd;
uint32_t deviceid;
@@ -1196,8 +1204,6 @@ struct gits_cmd {
#define GITS_CMDQ_SIZE (64 * 1024)
#define GITS_CMDQ_NENTRIES (GITS_CMDQ_SIZE / sizeof(struct gits_cmd))
-#define GITS_DTT_SIZE (64 * 1024)
-
struct agintc_msi_device {
LIST_ENTRY(agintc_msi_device) md_list;
@@ -1226,7 +1232,11 @@ struct agintc_msi_softc {
struct agintc_dmamem *sc_cmdq;
uint16_t sc_cmdidx;
+
+ int sc_devbits;
struct agintc_dmamem *sc_dtt;
+ size_t sc_dtt_pgsz;
+ uint8_t sc_dte_sz;
uint8_t sc_ite_sz;
LIST_HEAD(, agintc_msi_device) sc_msi_devices;
@@ -1290,6 +1300,7 @@ agintc_msi_attach(struct device *parent, struct device *self, void *aux)
goto unmap;
}
sc->sc_ite_sz = GITS_TYPER_ITE_SZ(typer) + 1;
+ sc->sc_devbits = GITS_TYPER_DEVBITS(typer) + 1;
sc->sc_nlpi = agintc_sc->sc_nlpi;
sc->sc_lpi = mallocarray(sc->sc_nlpi, sizeof(void *), M_DEVBUF,
@@ -1307,22 +1318,64 @@ agintc_msi_attach(struct device *parent, struct device *self, void *aux)
(GITS_CMDQ_SIZE / PAGE_SIZE) - 1 | GITS_CBASER_VALID);
/* Set up device translation table. */
- for (i = 0; i < 8; i++) {
+ for (i = 0; i < GITS_NUM_BASER; i++) {
uint64_t baser;
+ paddr_t dtt_pa;
+ size_t size;
baser = bus_space_read_8(sc->sc_iot, sc->sc_ioh, GITS_BASER(i));
if ((baser & GITS_BASER_TYPE_MASK) != GITS_BASER_TYPE_DEVICE)
continue;
+ /* Determine the maximum supported page size. */
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, GITS_BASER(i),
+ (baser & ~GITS_BASER_PGSZ_MASK) | GITS_BASER_PGSZ_64K);
+ baser = bus_space_read_8(sc->sc_iot, sc->sc_ioh, GITS_BASER(i));
+ if ((baser & GITS_BASER_PGSZ_MASK) == GITS_BASER_PGSZ_64K)
+ goto found;
+
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, GITS_BASER(i),
+ (baser & ~GITS_BASER_PGSZ_MASK) | GITS_BASER_PGSZ_16K);
+ baser = bus_space_read_8(sc->sc_iot, sc->sc_ioh, GITS_BASER(i));
+ if ((baser & GITS_BASER_PGSZ_MASK) == GITS_BASER_PGSZ_16K)
+ goto found;
+
+ bus_space_write_8(sc->sc_iot, sc->sc_ioh, GITS_BASER(i),
+ (baser & ~GITS_BASER_PGSZ_MASK) | GITS_BASER_PGSZ_4K);
+ baser = bus_space_read_8(sc->sc_iot, sc->sc_ioh, GITS_BASER(i));
+
+ found:
+ switch (baser & GITS_BASER_PGSZ_MASK) {
+ case GITS_BASER_PGSZ_4K:
+ sc->sc_dtt_pgsz = PAGE_SIZE;
+ break;
+ case GITS_BASER_PGSZ_16K:
+ sc->sc_dtt_pgsz = 4 * PAGE_SIZE;
+ break;
+ case GITS_BASER_PGSZ_64K:
+ sc->sc_dtt_pgsz = 16 * PAGE_SIZE;
+ break;
+ }
+
+ /* Calculate table size. */
+ sc->sc_dte_sz = GITS_BASER_DTE_SZ(baser) + 1;
+ size = (1ULL << sc->sc_devbits) * sc->sc_dte_sz;
+ size = roundup(size, sc->sc_dtt_pgsz);
+
+ /* Allocate table. */
sc->sc_dtt = agintc_dmamem_alloc(sc->sc_dmat,
- GITS_DTT_SIZE, GITS_DTT_SIZE);
+ size, sc->sc_dtt_pgsz);
if (sc->sc_dtt == NULL) {
printf(": can't alloc translation table\n");
goto unmap;
}
+
+ /* Configure table. */
+ dtt_pa = AGINTC_DMA_DVA(sc->sc_dtt);
+ KASSERT((dtt_pa & GITS_BASER_PA_MASK) == dtt_pa);
bus_space_write_8(sc->sc_iot, sc->sc_ioh, GITS_BASER(i),
- AGINTC_DMA_DVA(sc->sc_dtt) | GITS_BASER_IC_NORM_NC |
- (GITS_DTT_SIZE / PAGE_SIZE) - 1 | GITS_BASER_VALID);
+ GITS_BASER_IC_NORM_NC | baser & GITS_BASER_PGSZ_MASK |
+ dtt_pa | (size / sc->sc_dtt_pgsz) - 1 | GITS_BASER_VALID);
}
/* Enable ITS. */