1*94673892Sjsg /* $OpenBSD: simplebus.c,v 1.20 2023/09/22 01:10:43 jsg Exp $ */
279645871Spatrick /*
379645871Spatrick * Copyright (c) 2016 Patrick Wildt <patrick@blueri.se>
479645871Spatrick *
579645871Spatrick * Permission to use, copy, modify, and distribute this software for any
679645871Spatrick * purpose with or without fee is hereby granted, provided that the above
779645871Spatrick * copyright notice and this permission notice appear in all copies.
879645871Spatrick *
979645871Spatrick * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
1079645871Spatrick * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
1179645871Spatrick * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
1279645871Spatrick * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
1379645871Spatrick * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
1479645871Spatrick * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
1579645871Spatrick * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
1679645871Spatrick */
1779645871Spatrick
1879645871Spatrick #include <sys/param.h>
1979645871Spatrick #include <sys/systm.h>
2079645871Spatrick #include <sys/kernel.h>
2179645871Spatrick #include <sys/device.h>
22442e1276Skettenis #include <sys/malloc.h>
2379645871Spatrick
2479645871Spatrick #include <dev/ofw/openfirm.h>
25ac7c670eSpatrick #include <dev/ofw/fdt.h>
26eb366b01Sjsg #include <dev/ofw/ofw_clock.h>
27eb366b01Sjsg #include <dev/ofw/ofw_power.h>
2879645871Spatrick
29*94673892Sjsg #include <machine/fdt.h>
30*94673892Sjsg #include <machine/simplebusvar.h>
3179645871Spatrick
3279645871Spatrick int simplebus_match(struct device *, void *, void *);
3379645871Spatrick void simplebus_attach(struct device *, struct device *, void *);
3479645871Spatrick
3579645871Spatrick void simplebus_attach_node(struct device *, int);
36ed541e3aSpatrick int simplebus_bs_map(void *, uint64_t, bus_size_t, int, bus_space_handle_t *);
3737084e1eSkettenis int simplebus_dmamap_load_buffer(bus_dma_tag_t, bus_dmamap_t, void *,
3837084e1eSkettenis bus_size_t, struct proc *, int, paddr_t *, int *, int);
394c89fce1Skettenis int simplebus_dmamap_load_raw(bus_dma_tag_t, bus_dmamap_t,
404c89fce1Skettenis bus_dma_segment_t *, int, bus_size_t, int);
4179645871Spatrick
42e3ee5e84Smpi const struct cfattach simplebus_ca = {
43fc955b36Skettenis sizeof(struct simplebus_softc), simplebus_match, simplebus_attach
4479645871Spatrick };
4579645871Spatrick
4679645871Spatrick struct cfdriver simplebus_cd = {
4779645871Spatrick NULL, "simplebus", DV_DULL
4879645871Spatrick };
4979645871Spatrick
5079645871Spatrick /*
5179645871Spatrick * Simplebus is a generic bus with no special casings.
5279645871Spatrick */
5379645871Spatrick int
simplebus_match(struct device * parent,void * cfdata,void * aux)5479645871Spatrick simplebus_match(struct device *parent, void *cfdata, void *aux)
5579645871Spatrick {
5679645871Spatrick struct fdt_attach_args *fa = (struct fdt_attach_args *)aux;
5779645871Spatrick
5879645871Spatrick if (fa->fa_node == 0)
5979645871Spatrick return (0);
6079645871Spatrick
61eb366b01Sjsg return (OF_is_compatible(fa->fa_node, "simple-bus") ||
62eb366b01Sjsg OF_is_compatible(fa->fa_node, "simple-pm-bus"));
6379645871Spatrick }
6479645871Spatrick
6579645871Spatrick void
simplebus_attach(struct device * parent,struct device * self,void * aux)6679645871Spatrick simplebus_attach(struct device *parent, struct device *self, void *aux)
6779645871Spatrick {
6879645871Spatrick struct simplebus_softc *sc = (struct simplebus_softc *)self;
6979645871Spatrick struct fdt_attach_args *fa = (struct fdt_attach_args *)aux;
70c5eaa1e6Skettenis char name[32];
7179645871Spatrick int node;
7279645871Spatrick
7379645871Spatrick sc->sc_node = fa->fa_node;
7479645871Spatrick sc->sc_iot = fa->fa_iot;
7579645871Spatrick sc->sc_dmat = fa->fa_dmat;
765586125eSpatrick sc->sc_acells = OF_getpropint(sc->sc_node, "#address-cells",
775586125eSpatrick fa->fa_acells);
785586125eSpatrick sc->sc_scells = OF_getpropint(sc->sc_node, "#size-cells",
795586125eSpatrick fa->fa_scells);
8039d0e1dcSpatrick sc->sc_pacells = fa->fa_acells;
8139d0e1dcSpatrick sc->sc_pscells = fa->fa_scells;
8279645871Spatrick
83c5eaa1e6Skettenis if (OF_getprop(sc->sc_node, "name", name, sizeof(name)) > 0) {
84c5eaa1e6Skettenis name[sizeof(name) - 1] = 0;
85c5eaa1e6Skettenis printf(": \"%s\"", name);
86c5eaa1e6Skettenis }
87c5eaa1e6Skettenis
8879645871Spatrick printf("\n");
8979645871Spatrick
9039d0e1dcSpatrick memcpy(&sc->sc_bus, sc->sc_iot, sizeof(sc->sc_bus));
9139d0e1dcSpatrick sc->sc_bus.bs_cookie = sc;
9239d0e1dcSpatrick sc->sc_bus.bs_map = simplebus_bs_map;
9339d0e1dcSpatrick
9439d0e1dcSpatrick sc->sc_rangeslen = OF_getproplen(sc->sc_node, "ranges");
9537084e1eSkettenis if (sc->sc_rangeslen > 0 &&
9637084e1eSkettenis (sc->sc_rangeslen % sizeof(uint32_t)) == 0) {
9739d0e1dcSpatrick sc->sc_ranges = malloc(sc->sc_rangeslen, M_TEMP, M_WAITOK);
9839d0e1dcSpatrick OF_getpropintarray(sc->sc_node, "ranges", sc->sc_ranges,
9939d0e1dcSpatrick sc->sc_rangeslen);
10039d0e1dcSpatrick }
10139d0e1dcSpatrick
10237084e1eSkettenis memcpy(&sc->sc_dma, sc->sc_dmat, sizeof(sc->sc_dma));
10337084e1eSkettenis sc->sc_dma._dmamap_load_buffer = simplebus_dmamap_load_buffer;
1044c89fce1Skettenis sc->sc_dma._dmamap_load_raw = simplebus_dmamap_load_raw;
10537084e1eSkettenis sc->sc_dma._cookie = sc;
10637084e1eSkettenis
10737084e1eSkettenis sc->sc_dmarangeslen = OF_getproplen(sc->sc_node, "dma-ranges");
10837084e1eSkettenis if (sc->sc_dmarangeslen > 0 &&
10937084e1eSkettenis (sc->sc_dmarangeslen % sizeof(uint32_t)) == 0) {
11037084e1eSkettenis sc->sc_dmaranges = malloc(sc->sc_dmarangeslen,
11137084e1eSkettenis M_TEMP, M_WAITOK);
11237084e1eSkettenis OF_getpropintarray(sc->sc_node, "dma-ranges",
11337084e1eSkettenis sc->sc_dmaranges, sc->sc_dmarangeslen);
11437084e1eSkettenis }
11537084e1eSkettenis
116eb366b01Sjsg if (OF_is_compatible(sc->sc_node, "simple-pm-bus")) {
117eb366b01Sjsg power_domain_enable(sc->sc_node);
118eb366b01Sjsg clock_enable_all(sc->sc_node);
119eb366b01Sjsg }
120eb366b01Sjsg
12179645871Spatrick /* Scan the whole tree. */
122abc4f2a0Skettenis sc->sc_early = 1;
123abc4f2a0Skettenis for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
124abc4f2a0Skettenis simplebus_attach_node(self, node);
125abc4f2a0Skettenis
126abc4f2a0Skettenis sc->sc_early = 0;
127abc4f2a0Skettenis for (node = OF_child(sc->sc_node); node; node = OF_peer(node))
12879645871Spatrick simplebus_attach_node(self, node);
12979645871Spatrick }
130abc4f2a0Skettenis
131abc4f2a0Skettenis int
simplebus_submatch(struct device * self,void * match,void * aux)132abc4f2a0Skettenis simplebus_submatch(struct device *self, void *match, void *aux)
133abc4f2a0Skettenis {
134abc4f2a0Skettenis struct simplebus_softc *sc = (struct simplebus_softc *)self;
135abc4f2a0Skettenis struct cfdata *cf = match;
136abc4f2a0Skettenis
137abc4f2a0Skettenis if (cf->cf_loc[0] == sc->sc_early)
138abc4f2a0Skettenis return (*cf->cf_attach->ca_match)(self, match, aux);
139abc4f2a0Skettenis return 0;
14079645871Spatrick }
14179645871Spatrick
142ad434fd9Sjsg int
simplebus_print(void * aux,const char * pnp)143ad434fd9Sjsg simplebus_print(void *aux, const char *pnp)
144ad434fd9Sjsg {
145ad434fd9Sjsg struct fdt_attach_args *fa = aux;
146ad434fd9Sjsg char name[32];
147ad434fd9Sjsg
148ad434fd9Sjsg if (!pnp)
149ad434fd9Sjsg return (QUIET);
150ad434fd9Sjsg
151ad434fd9Sjsg if (OF_getprop(fa->fa_node, "name", name, sizeof(name)) > 0) {
152ad434fd9Sjsg name[sizeof(name) - 1] = 0;
153ad434fd9Sjsg printf("\"%s\"", name);
154ad434fd9Sjsg } else
155ad434fd9Sjsg printf("node %u", fa->fa_node);
156ad434fd9Sjsg
157ad434fd9Sjsg printf(" at %s", pnp);
158ad434fd9Sjsg
159ad434fd9Sjsg return (UNCONF);
160ad434fd9Sjsg }
161ad434fd9Sjsg
16279645871Spatrick /*
16379645871Spatrick * Look for a driver that wants to be attached to this node.
16479645871Spatrick */
16579645871Spatrick void
simplebus_attach_node(struct device * self,int node)16679645871Spatrick simplebus_attach_node(struct device *self, int node)
16779645871Spatrick {
16879645871Spatrick struct simplebus_softc *sc = (struct simplebus_softc *)self;
16979645871Spatrick struct fdt_attach_args fa;
17088a615dbSkettenis char buf[32];
171ac7c670eSpatrick int i, len, line;
172ac7c670eSpatrick uint32_t *cell, *reg;
1732a1245a1Skettenis struct device *child;
17479645871Spatrick
17588a615dbSkettenis if (OF_getproplen(node, "compatible") <= 0)
17679645871Spatrick return;
17779645871Spatrick
17888a615dbSkettenis if (OF_getprop(node, "status", buf, sizeof(buf)) > 0 &&
17988a615dbSkettenis strcmp(buf, "disabled") == 0)
18079645871Spatrick return;
18179645871Spatrick
1822a1245a1Skettenis /* Skip if already attached early. */
1832a1245a1Skettenis for (i = 0; i < nitems(sc->sc_early_nodes); i++) {
1842a1245a1Skettenis if (sc->sc_early_nodes[i] == node)
1852a1245a1Skettenis return;
1862a1245a1Skettenis if (sc->sc_early_nodes[i] == 0)
1872a1245a1Skettenis break;
1882a1245a1Skettenis }
1892a1245a1Skettenis
19079645871Spatrick memset(&fa, 0, sizeof(fa));
19179645871Spatrick fa.fa_name = "";
19279645871Spatrick fa.fa_node = node;
19339d0e1dcSpatrick fa.fa_iot = &sc->sc_bus;
19437084e1eSkettenis fa.fa_dmat = &sc->sc_dma;
1955586125eSpatrick fa.fa_acells = sc->sc_acells;
1965586125eSpatrick fa.fa_scells = sc->sc_scells;
19779645871Spatrick
198442e1276Skettenis len = OF_getproplen(node, "reg");
199ac7c670eSpatrick line = (sc->sc_acells + sc->sc_scells) * sizeof(uint32_t);
200ac7c670eSpatrick if (len > 0 && line > 0 && (len % line) == 0) {
201ac7c670eSpatrick reg = malloc(len, M_TEMP, M_WAITOK);
202ac7c670eSpatrick OF_getpropintarray(node, "reg", reg, len);
203442e1276Skettenis
204ac7c670eSpatrick fa.fa_reg = malloc((len / line) * sizeof(struct fdt_reg),
205ac7c670eSpatrick M_DEVBUF, M_WAITOK | M_ZERO);
206ac7c670eSpatrick fa.fa_nreg = (len / line);
207ac7c670eSpatrick
208ac7c670eSpatrick for (i = 0, cell = reg; i < len / line; i++) {
209ac7c670eSpatrick if (sc->sc_acells >= 1)
210ac7c670eSpatrick fa.fa_reg[i].addr = cell[0];
211ac7c670eSpatrick if (sc->sc_acells == 2) {
212ac7c670eSpatrick fa.fa_reg[i].addr <<= 32;
213ac7c670eSpatrick fa.fa_reg[i].addr |= cell[1];
214ac7c670eSpatrick }
215ac7c670eSpatrick cell += sc->sc_acells;
216ac7c670eSpatrick if (sc->sc_scells >= 1)
217ac7c670eSpatrick fa.fa_reg[i].size = cell[0];
218ac7c670eSpatrick if (sc->sc_scells == 2) {
219ac7c670eSpatrick fa.fa_reg[i].size <<= 32;
220ac7c670eSpatrick fa.fa_reg[i].size |= cell[1];
221ac7c670eSpatrick }
222ac7c670eSpatrick cell += sc->sc_scells;
223ac7c670eSpatrick }
224ac7c670eSpatrick
225ac7c670eSpatrick free(reg, M_TEMP, len);
226442e1276Skettenis }
227442e1276Skettenis
228442e1276Skettenis len = OF_getproplen(node, "interrupts");
229442e1276Skettenis if (len > 0 && (len % sizeof(uint32_t)) == 0) {
230442e1276Skettenis fa.fa_intr = malloc(len, M_DEVBUF, M_WAITOK);
231442e1276Skettenis fa.fa_nintr = len / sizeof(uint32_t);
232442e1276Skettenis
233f501cbd5Skettenis OF_getpropintarray(node, "interrupts", fa.fa_intr, len);
234442e1276Skettenis }
235442e1276Skettenis
2362a1245a1Skettenis child = config_found_sm(self, &fa, sc->sc_early ? NULL :
2372a1245a1Skettenis simplebus_print, simplebus_submatch);
2382a1245a1Skettenis
2392a1245a1Skettenis /* Record nodes that we attach early. */
2402a1245a1Skettenis if (child && sc->sc_early) {
2412a1245a1Skettenis for (i = 0; i < nitems(sc->sc_early_nodes); i++) {
2422a1245a1Skettenis if (sc->sc_early_nodes[i] != 0)
2432a1245a1Skettenis continue;
2442a1245a1Skettenis sc->sc_early_nodes[i] = node;
2452a1245a1Skettenis break;
2462a1245a1Skettenis }
2472a1245a1Skettenis }
248442e1276Skettenis
249ac7c670eSpatrick free(fa.fa_reg, M_DEVBUF, fa.fa_nreg * sizeof(struct fdt_reg));
250442e1276Skettenis free(fa.fa_intr, M_DEVBUF, fa.fa_nintr * sizeof(uint32_t));
25179645871Spatrick }
25239d0e1dcSpatrick
25339d0e1dcSpatrick /*
25439d0e1dcSpatrick * Translate memory address if needed.
25539d0e1dcSpatrick */
25639d0e1dcSpatrick int
simplebus_bs_map(void * t,uint64_t bpa,bus_size_t size,int flag,bus_space_handle_t * bshp)257ed541e3aSpatrick simplebus_bs_map(void *t, uint64_t bpa, bus_size_t size,
25839d0e1dcSpatrick int flag, bus_space_handle_t *bshp)
25939d0e1dcSpatrick {
26039d0e1dcSpatrick struct simplebus_softc *sc = (struct simplebus_softc *)t;
26139d0e1dcSpatrick uint64_t addr, rfrom, rto, rsize;
26239d0e1dcSpatrick uint32_t *range;
26339d0e1dcSpatrick int parent, rlen, rone;
26439d0e1dcSpatrick
26539d0e1dcSpatrick addr = bpa;
26639d0e1dcSpatrick parent = OF_parent(sc->sc_node);
26739d0e1dcSpatrick if (parent == 0)
26839d0e1dcSpatrick return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
26939d0e1dcSpatrick
27039d0e1dcSpatrick if (sc->sc_rangeslen < 0)
27139d0e1dcSpatrick return EINVAL;
27239d0e1dcSpatrick if (sc->sc_rangeslen == 0)
27339d0e1dcSpatrick return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
27439d0e1dcSpatrick
27539d0e1dcSpatrick rlen = sc->sc_rangeslen / sizeof(uint32_t);
27639d0e1dcSpatrick rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
27739d0e1dcSpatrick
27839d0e1dcSpatrick /* For each range. */
27939d0e1dcSpatrick for (range = sc->sc_ranges; rlen >= rone; rlen -= rone, range += rone) {
28039d0e1dcSpatrick /* Extract from and size, so we can see if we fit. */
28139d0e1dcSpatrick rfrom = range[0];
28239d0e1dcSpatrick if (sc->sc_acells == 2)
28339d0e1dcSpatrick rfrom = (rfrom << 32) + range[1];
28439d0e1dcSpatrick rsize = range[sc->sc_acells + sc->sc_pacells];
28539d0e1dcSpatrick if (sc->sc_scells == 2)
28639d0e1dcSpatrick rsize = (rsize << 32) +
28739d0e1dcSpatrick range[sc->sc_acells + sc->sc_pacells + 1];
28839d0e1dcSpatrick
28939d0e1dcSpatrick /* Try next, if we're not in the range. */
29039d0e1dcSpatrick if (addr < rfrom || (addr + size) > (rfrom + rsize))
29139d0e1dcSpatrick continue;
29239d0e1dcSpatrick
29339d0e1dcSpatrick /* All good, extract to address and translate. */
29439d0e1dcSpatrick rto = range[sc->sc_acells];
29539d0e1dcSpatrick if (sc->sc_pacells == 2)
29639d0e1dcSpatrick rto = (rto << 32) + range[sc->sc_acells + 1];
29739d0e1dcSpatrick
29839d0e1dcSpatrick addr -= rfrom;
29939d0e1dcSpatrick addr += rto;
30039d0e1dcSpatrick
30139d0e1dcSpatrick return bus_space_map(sc->sc_iot, addr, size, flag, bshp);
30239d0e1dcSpatrick }
30339d0e1dcSpatrick
30439d0e1dcSpatrick return ESRCH;
30539d0e1dcSpatrick }
30637084e1eSkettenis
30737084e1eSkettenis 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)30837084e1eSkettenis simplebus_dmamap_load_buffer(bus_dma_tag_t t, bus_dmamap_t map, void *buf,
30937084e1eSkettenis bus_size_t buflen, struct proc *p, int flags, paddr_t *lastaddrp,
31037084e1eSkettenis int *segp, int first)
31137084e1eSkettenis {
31237084e1eSkettenis struct simplebus_softc *sc = t->_cookie;
31337084e1eSkettenis int rlen, rone, seg;
31437084e1eSkettenis int firstseg = *segp;
31537084e1eSkettenis int error;
31637084e1eSkettenis
31737084e1eSkettenis error = sc->sc_dmat->_dmamap_load_buffer(sc->sc_dmat, map, buf, buflen,
31837084e1eSkettenis p, flags, lastaddrp, segp, first);
31937084e1eSkettenis if (error)
32037084e1eSkettenis return error;
32137084e1eSkettenis
32237084e1eSkettenis if (sc->sc_dmaranges == NULL)
32337084e1eSkettenis return 0;
32437084e1eSkettenis
32537084e1eSkettenis rlen = sc->sc_dmarangeslen / sizeof(uint32_t);
32637084e1eSkettenis rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
32737084e1eSkettenis
32837084e1eSkettenis /* For each segment. */
32937084e1eSkettenis for (seg = firstseg; seg <= *segp; seg++) {
33037084e1eSkettenis uint64_t addr, size, rfrom, rto, rsize;
33137084e1eSkettenis uint32_t *range;
33237084e1eSkettenis
33337084e1eSkettenis addr = map->dm_segs[seg].ds_addr;
33437084e1eSkettenis size = map->dm_segs[seg].ds_len;
33537084e1eSkettenis
33637084e1eSkettenis /* For each range. */
33737084e1eSkettenis for (range = sc->sc_dmaranges; rlen >= rone;
33837084e1eSkettenis rlen -= rone, range += rone) {
33937084e1eSkettenis /* Extract from and size, so we can see if we fit. */
34037084e1eSkettenis rfrom = range[sc->sc_acells];
34137084e1eSkettenis if (sc->sc_pacells == 2)
34237084e1eSkettenis rfrom = (rfrom << 32) + range[sc->sc_acells + 1];
34337084e1eSkettenis
34437084e1eSkettenis rsize = range[sc->sc_acells + sc->sc_pacells];
34537084e1eSkettenis if (sc->sc_scells == 2)
34637084e1eSkettenis rsize = (rsize << 32) +
34737084e1eSkettenis range[sc->sc_acells + sc->sc_pacells + 1];
34837084e1eSkettenis
34937084e1eSkettenis /* Try next, if we're not in the range. */
35037084e1eSkettenis if (addr < rfrom || (addr + size) > (rfrom + rsize))
35137084e1eSkettenis continue;
35237084e1eSkettenis
35337084e1eSkettenis /* All good, extract to address and translate. */
35437084e1eSkettenis rto = range[0];
35537084e1eSkettenis if (sc->sc_acells == 2)
35637084e1eSkettenis rto = (rto << 32) + range[1];
35737084e1eSkettenis
35837084e1eSkettenis map->dm_segs[seg].ds_addr -= rfrom;
35937084e1eSkettenis map->dm_segs[seg].ds_addr += rto;
36037084e1eSkettenis break;
36137084e1eSkettenis }
36237084e1eSkettenis }
36337084e1eSkettenis
36437084e1eSkettenis return 0;
36537084e1eSkettenis }
3664c89fce1Skettenis
3674c89fce1Skettenis 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)3684c89fce1Skettenis simplebus_dmamap_load_raw(bus_dma_tag_t t, bus_dmamap_t map,
3694c89fce1Skettenis bus_dma_segment_t *segs, int nsegs, bus_size_t size, int flags)
3704c89fce1Skettenis {
3714c89fce1Skettenis struct simplebus_softc *sc = t->_cookie;
3724c89fce1Skettenis int rlen, rone, seg;
3734c89fce1Skettenis int error;
3744c89fce1Skettenis
3754c89fce1Skettenis error = sc->sc_dmat->_dmamap_load_raw(sc->sc_dmat, map,
3764c89fce1Skettenis segs, nsegs, size, flags);
3774c89fce1Skettenis if (error)
3784c89fce1Skettenis return error;
3794c89fce1Skettenis
3804c89fce1Skettenis if (sc->sc_dmaranges == NULL)
3814c89fce1Skettenis return 0;
3824c89fce1Skettenis
3834c89fce1Skettenis rlen = sc->sc_dmarangeslen / sizeof(uint32_t);
3844c89fce1Skettenis rone = sc->sc_pacells + sc->sc_acells + sc->sc_scells;
3854c89fce1Skettenis
3864c89fce1Skettenis /* For each segment. */
3874c89fce1Skettenis for (seg = 0; seg < map->dm_nsegs; seg++) {
3884c89fce1Skettenis uint64_t addr, size, rfrom, rto, rsize;
3894c89fce1Skettenis uint32_t *range;
3904c89fce1Skettenis
3914c89fce1Skettenis addr = map->dm_segs[seg].ds_addr;
3924c89fce1Skettenis size = map->dm_segs[seg].ds_len;
3934c89fce1Skettenis
3944c89fce1Skettenis /* For each range. */
3954c89fce1Skettenis for (range = sc->sc_dmaranges; rlen >= rone;
3964c89fce1Skettenis rlen -= rone, range += rone) {
3974c89fce1Skettenis /* Extract from and size, so we can see if we fit. */
3984c89fce1Skettenis rfrom = range[sc->sc_acells];
3994c89fce1Skettenis if (sc->sc_pacells == 2)
4004c89fce1Skettenis rfrom = (rfrom << 32) + range[sc->sc_acells + 1];
4014c89fce1Skettenis
4024c89fce1Skettenis rsize = range[sc->sc_acells + sc->sc_pacells];
4034c89fce1Skettenis if (sc->sc_scells == 2)
4044c89fce1Skettenis rsize = (rsize << 32) +
4054c89fce1Skettenis range[sc->sc_acells + sc->sc_pacells + 1];
4064c89fce1Skettenis
4074c89fce1Skettenis /* Try next, if we're not in the range. */
4084c89fce1Skettenis if (addr < rfrom || (addr + size) > (rfrom + rsize))
4094c89fce1Skettenis continue;
4104c89fce1Skettenis
4114c89fce1Skettenis /* All good, extract to address and translate. */
4124c89fce1Skettenis rto = range[0];
4134c89fce1Skettenis if (sc->sc_acells == 2)
4144c89fce1Skettenis rto = (rto << 32) + range[1];
4154c89fce1Skettenis
4164c89fce1Skettenis map->dm_segs[seg].ds_addr -= rfrom;
4174c89fce1Skettenis map->dm_segs[seg].ds_addr += rto;
4184c89fce1Skettenis break;
4194c89fce1Skettenis }
4204c89fce1Skettenis }
4214c89fce1Skettenis
4224c89fce1Skettenis return 0;
4234c89fce1Skettenis }
424