summaryrefslogtreecommitdiff
path: root/sys/arch
diff options
context:
space:
mode:
authorMark Kettenis <kettenis@cvs.openbsd.org>2021-11-11 18:43:06 +0000
committerMark Kettenis <kettenis@cvs.openbsd.org>2021-11-11 18:43:06 +0000
commitef07fd323cc348b769804b91262bcc2efaa9119d (patch)
tree36af7928c3e9bf0acebebca996aa0a57828563c7 /sys/arch
parenta48bf2688d504bcc59d4475189cce51705493f3a (diff)
The Apple DART has a nifty feature that allows us protection of subranges
of a page with a granularity of 32-bit words. Use this to expose just those parts of memory to devices that we want the device to see. This means that handing down a small mbuf to a network card driver no longer gives the hardware access to other mbufs in the same page. It turns out that bge(4) always does aligned 64-bit access to memory though. So round up/down to the nearest 64-bit boundary to prevent triggering an IOMMU fault. ok patrick@
Diffstat (limited to 'sys/arch')
-rw-r--r--sys/arch/arm64/dev/apldart.c54
1 files changed, 42 insertions, 12 deletions
diff --git a/sys/arch/arm64/dev/apldart.c b/sys/arch/arm64/dev/apldart.c
index 3999406a01e..d6df9f42d77 100644
--- a/sys/arch/arm64/dev/apldart.c
+++ b/sys/arch/arm64/dev/apldart.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: apldart.c,v 1.7 2021/11/01 20:04:11 kettenis Exp $ */
+/* $OpenBSD: apldart.c,v 1.8 2021/11/11 18:43:05 kettenis Exp $ */
/*
* Copyright (c) 2021 Mark Kettenis <kettenis@openbsd.org>
*
@@ -31,11 +31,6 @@
#include <dev/ofw/fdt.h>
/*
- * This driver is based on preliminary device tree bindings and will
- * almost certainly need changes once the official bindings land in
- * mainline Linux. Support for these preliminary bindings will be
- * dropped as soon as official bindings are available.
- *
* This driver largely ignores stream IDs and simply uses a single
* translation table for all the devices that it serves. This is good
* enough for the PCIe host bridge that serves the on-board devices on
@@ -49,6 +44,9 @@
#define DART_TLB_OP_FLUSH (1 << 20)
#define DART_TLB_OP_BUSY (1 << 2)
#define DART_TLB_OP_SIDMASK 0x0034
+#define DART_ERROR 0x0040
+#define DART_ERROR_ADDR_LO 0x0050
+#define DART_ERROR_ADDR_HI 0x0054
#define DART_TCR(sid) (0x0100 + 4 *(sid))
#define DART_TCR_TRANSLATE_ENABLE (1 << 7)
#define DART_TCR_BYPASS_DART (1 << 8)
@@ -63,9 +61,19 @@
#define DART_PAGE_SIZE 16384
#define DART_PAGE_MASK (DART_PAGE_SIZE - 1)
+/*
+ * Some hardware (e.g. bge(4)) will always use (aligned) 64-bit memory
+ * access. To make sure this doesn't fault, round the subpage limits
+ * down and up accordingly.
+ */
+#define DART_OFFSET_MASK 7
+
#define DART_L1_TABLE 0xb
-#define DART_L2_INVAL 0x0
-#define DART_L2_PAGE 0x3
+#define DART_L2_INVAL 0
+#define DART_L2_VALID (1 << 0)
+#define DART_L2_FULL_PAGE (1 << 1)
+#define DART_L2_START(addr) ((((addr) & DART_PAGE_MASK) >> 2) << 52)
+#define DART_L2_END(addr) ((((addr) & DART_PAGE_MASK) >> 2) << 40)
static inline paddr_t
apldart_round_page(paddr_t pa)
@@ -73,12 +81,24 @@ apldart_round_page(paddr_t pa)
return ((pa + DART_PAGE_MASK) & ~DART_PAGE_MASK);
}
-inline paddr_t
-static apldart_trunc_page(paddr_t pa)
+static inline paddr_t
+apldart_trunc_page(paddr_t pa)
{
return (pa & ~DART_PAGE_MASK);
}
+static inline psize_t
+apldart_round_offset(psize_t off)
+{
+ return ((off + DART_OFFSET_MASK) & ~DART_OFFSET_MASK);
+}
+
+static inline psize_t
+apldart_trunc_offset(psize_t off)
+{
+ return (off & ~DART_OFFSET_MASK);
+}
+
#define HREAD4(sc, reg) \
(bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)))
#define HWRITE4(sc, reg, val) \
@@ -303,7 +323,9 @@ apldart_intr(void *arg)
{
struct apldart_softc *sc = arg;
- panic("%s: %s", sc->sc_dev.dv_xname, __func__);
+ panic("%s: error 0x%08x addr 0x%08x%08x\n", sc->sc_dev.dv_xname,
+ HREAD4(sc, DART_ERROR), HREAD4(sc, DART_ERROR_ADDR_HI),
+ HREAD4(sc, DART_ERROR_ADDR_LO));
}
void
@@ -340,6 +362,7 @@ apldart_load_map(struct apldart_softc *sc, bus_dmamap_t map)
for (seg = 0; seg < map->dm_nsegs; seg++) {
paddr_t pa = map->dm_segs[seg]._ds_paddr;
psize_t off = pa - apldart_trunc_page(pa);
+ psize_t start, end;
u_long len, dva;
len = apldart_round_page(map->dm_segs[seg].ds_len + off);
@@ -359,13 +382,20 @@ apldart_load_map(struct apldart_softc *sc, bus_dmamap_t map)
map->dm_segs[seg].ds_addr = dva + off;
pa = apldart_trunc_page(pa);
+ start = apldart_trunc_offset(off);
+ end = DART_PAGE_MASK;
while (len > 0) {
+ if (len < DART_PAGE_SIZE)
+ end = apldart_round_offset(len) - 1;
+
tte = apldart_lookup_tte(sc, dva);
- *tte = pa | DART_L2_PAGE;
+ *tte = pa | DART_L2_VALID |
+ DART_L2_START(start) | DART_L2_END(end);
pa += DART_PAGE_SIZE;
dva += DART_PAGE_SIZE;
len -= DART_PAGE_SIZE;
+ start = 0;
}
}