diff options
author | 2017-01-23 10:46:02 +0000 | |
---|---|---|
committer | 2017-01-23 10:46:02 +0000 | |
commit | 3e99d0b82503cf01f8f7b25288b454e353f89912 (patch) | |
tree | 51f952c6f459749df5c3e33f34aeda212aca165b /sys | |
parent | Fix format string mismatches (diff) | |
download | wireguard-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.c | 85 | ||||
-rw-r--r-- | sys/arch/arm64/dev/simplebusvar.h | 5 |
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; }; |