summaryrefslogtreecommitdiffstats
path: root/sys
diff options
context:
space:
mode:
authorkettenis <kettenis@openbsd.org>2017-01-23 10:46:02 +0000
committerkettenis <kettenis@openbsd.org>2017-01-23 10:46:02 +0000
commit3e99d0b82503cf01f8f7b25288b454e353f89912 (patch)
tree51f952c6f459749df5c3e33f34aeda212aca165b /sys
parentFix format string mismatches (diff)
downloadwireguard-openbsd-3e99d0b82503cf01f8f7b25288b454e353f89912.tar.xz
wireguard-openbsd-3e99d0b82503cf01f8f7b25288b454e353f89912.zip
Parse and use "dma-ranges" property to do the appropriate dma address
translations on machines like the Raspberry Pi. ok jsg@
Diffstat (limited to 'sys')
-rw-r--r--sys/arch/arm64/dev/simplebus.c85
-rw-r--r--sys/arch/arm64/dev/simplebusvar.h5
2 files changed, 85 insertions, 5 deletions
diff --git a/sys/arch/arm64/dev/simplebus.c b/sys/arch/arm64/dev/simplebus.c
index 27c4376ce61..8d0660176d1 100644
--- a/sys/arch/arm64/dev/simplebus.c
+++ b/sys/arch/arm64/dev/simplebus.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: simplebus.c,v 1.3 2017/01/23 06:13:34 kettenis Exp $ */
+/* $OpenBSD: simplebus.c,v 1.4 2017/01/23 10:46:02 kettenis Exp $ */
/*
* Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
*
@@ -31,7 +31,10 @@ int simplebus_match(struct device *, void *, void *);
void simplebus_attach(struct device *, struct device *, void *);
void simplebus_attach_node(struct device *, int);
-int simplebus_bs_map(bus_space_tag_t, bus_addr_t, bus_size_t, int, bus_space_handle_t *);
+int simplebus_bs_map(bus_space_tag_t, bus_addr_t, bus_size_t, int,
+ bus_space_handle_t *);
+int simplebus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
+ bus_size_t, struct proc *, int, paddr_t *, int *, int);
struct cfattach simplebus_ca = {
sizeof(struct simplebus_softc), simplebus_match, simplebus_attach
@@ -88,12 +91,26 @@ simplebus_attach(struct device *parent, struct device *self, void *aux)
sc->sc_bus._space_map = simplebus_bs_map;
sc->sc_rangeslen = OF_getproplen(sc->sc_node, "ranges");
- if (sc->sc_rangeslen > 0 && !(sc->sc_rangeslen % sizeof(uint32_t))) {
+ if (sc->sc_rangeslen > 0 &&
+ (sc->sc_rangeslen % sizeof(uint32_t)) == 0) {
sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK);
OF_getpropintarray(sc->sc_node, "ranges", sc->sc_ranges,
sc->sc_rangeslen);
}
+ memcpy(&sc->sc_dma, sc->sc_dmat, sizeof(sc->sc_dma));
+ sc->sc_dma._dmamap_load_buffer = simplebus_dmamap_load_buffer;
+ sc->sc_dma._cookie = sc;
+
+ sc->sc_dmarangeslen = OF_getproplen(sc->sc_node, "dma-ranges");
+ if (sc->sc_dmarangeslen > 0 &&
+ (sc->sc_dmarangeslen % sizeof(uint32_t)) == 0) {
+ sc->sc_dmaranges = malloc(sc->sc_dmarangeslen,
+ M_TEMP, M_WAITOK);
+ OF_getpropintarray(sc->sc_node, "dma-ranges",
+ sc->sc_dmaranges, sc->sc_dmarangeslen);
+ }
+
/* Scan the whole tree. */
sc->sc_early = 1;
for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
@@ -138,7 +155,7 @@ simplebus_attach_node(struct device *self, int node)
fa.fa_name = "";
fa.fa_node = node;
fa.fa_iot = &sc->sc_bus;
- fa.fa_dmat = sc->sc_dmat;
+ fa.fa_dmat = &sc->sc_dma;
fa.fa_acells = sc->sc_acells;
fa.fa_scells = sc->sc_scells;
@@ -239,3 +256,63 @@ simplebus_bs_map(bus_space_tag_t t, bus_addr_t bpa, bus_size_t size,
return ESRCH;
}
+
+int
+simplebus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
+ bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp,
+ int *segp, int first)
+{
+ struct simplebus_softc *sc = t->_cookie;
+ int rlen, rone, seg;
+ int firstseg = *segp;
+ int error;
+
+ error = sc->sc_dmat->_dmamap_load_buffer(t, map, buf, buflen, p,
+ flags, lastaddrp, segp, first);
+ if (error)
+ return error;
+
+ if (sc->sc_dmaranges == NULL)
+ return 0;
+
+ rlen = sc->sc_dmarangeslen / sizeof(uint32_t);
+ rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
+
+ /* For each segment. */
+ for (seg = firstseg; seg <= *segp; seg++) {
+ uint64_t addr, size, rfrom, rto, rsize;
+ uint32_t *range;
+
+ addr = map->dm_segs[seg].ds_addr;
+ size = map->dm_segs[seg].ds_len;
+
+ /* For each range. */
+ for (range = sc->sc_dmaranges; rlen >= rone;
+ rlen -= rone, range += rone) {
+ /* Extract from and size, so we can see if we fit. */
+ rfrom = range[sc->sc_acells];
+ if (sc->sc_pacells == 2)
+ rfrom = (rfrom << 32) + range[sc->sc_acells + 1];
+
+ rsize = range[sc->sc_acells + sc->sc_pacells];
+ if (sc->sc_scells == 2)
+ rsize = (rsize << 32) +
+ range[sc->sc_acells + sc->sc_pacells + 1];
+
+ /* Try next, if we're not in the range. */
+ if (addr < rfrom || (addr + size) > (rfrom + rsize))
+ continue;
+
+ /* All good, extract to address and translate. */
+ rto = range[0];
+ if (sc->sc_pacells == 2)
+ rto = (rto << 32) + range[1];
+
+ map->dm_segs[seg].ds_addr -= rfrom;
+ map->dm_segs[seg].ds_addr += rto;
+ break;
+ }
+ }
+
+ return 0;
+}
diff --git a/sys/arch/arm64/dev/simplebusvar.h b/sys/arch/arm64/dev/simplebusvar.h
index 4bde6e92bd5..084c17bbfbe 100644
--- a/sys/arch/arm64/dev/simplebusvar.h
+++ b/sys/arch/arm64/dev/simplebusvar.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: simplebusvar.h,v 1.1 2016/12/17 23:38:33 patrick Exp $ */
+/* $OpenBSD: simplebusvar.h,v 1.2 2017/01/23 10:46:02 kettenis Exp $ */
/*
* Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
*
@@ -25,8 +25,11 @@ struct simplebus_softc {
int sc_pacells;
int sc_pscells;
struct bus_space sc_bus;
+ struct machine_bus_dma_tag sc_dma;
int *sc_ranges;
int sc_rangeslen;
+ int *sc_dmaranges;
+ int sc_dmarangeslen;
int sc_early;
};