diff options
-rw-r--r-- | sys/arch/arm/simplebus/simplebus.c | 63 |
1 files changed, 62 insertions, 1 deletions
diff --git a/sys/arch/arm/simplebus/simplebus.c b/sys/arch/arm/simplebus/simplebus.c index 846bec9e0df..b772cbe7e1b 100644 --- a/sys/arch/arm/simplebus/simplebus.c +++ b/sys/arch/arm/simplebus/simplebus.c @@ -1,4 +1,4 @@ -/* $OpenBSD: simplebus.c,v 1.17 2021/02/18 00:04:13 jsg Exp $ */ +/* $OpenBSD: simplebus.c,v 1.18 2021/12/06 20:01:54 kettenis Exp $ */ /* * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se> * @@ -36,6 +36,8 @@ void simplebus_attach_node(struct device *, int); int simplebus_bs_map(void *, uint64_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); +int simplebus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t, + bus_dma_segment_t *, int, bus_size_t, int); struct cfattach simplebus_ca = { sizeof(struct simplebus_softc), simplebus_match, simplebus_attach @@ -99,6 +101,7 @@ simplebus_attach(struct device *parent, struct device *self, void *aux) memcpy(&sc->sc_dma, sc->sc_dmat, sizeof(sc->sc_dma)); sc->sc_dma._dmamap_load_buffer = simplebus_dmamap_load_buffer; + sc->sc_dma._dmamap_load_raw = simplebus_dmamap_load_raw; sc->sc_dma._cookie = sc; sc->sc_dmarangeslen = OF_getproplen(sc->sc_node, "dma-ranges"); @@ -360,3 +363,61 @@ simplebus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf, return 0; } + +int +simplebus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map, + bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags) +{ + struct simplebus_softc *sc = t->_cookie; + int rlen, rone, seg; + int error; + + error = sc->sc_dmat->_dmamap_load_raw(sc->sc_dmat, map, + segs, nsegs, size, flags); + 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 = 0; seg < map->dm_nsegs; 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_acells == 2) + rto = (rto << 32) + range[1]; + + map->dm_segs[seg].ds_addr -= rfrom; + map->dm_segs[seg].ds_addr += rto; + break; + } + } + + return 0; +} |