14f027abdSMarcel Moolenaar /*-
2*9f011bcaSMarcel Moolenaar * Copyright (c) 2015, 2019 Marcel Moolenaar
34f027abdSMarcel Moolenaar * All rights reserved.
44f027abdSMarcel Moolenaar *
54f027abdSMarcel Moolenaar * Redistribution and use in source and binary forms, with or without
64f027abdSMarcel Moolenaar * modification, are permitted provided that the following conditions
74f027abdSMarcel Moolenaar * are met:
84f027abdSMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright
94f027abdSMarcel Moolenaar * notice, this list of conditions and the following disclaimer.
104f027abdSMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright
114f027abdSMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the
124f027abdSMarcel Moolenaar * documentation and/or other materials provided with the distribution.
134f027abdSMarcel Moolenaar *
144f027abdSMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
154f027abdSMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
164f027abdSMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
174f027abdSMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
184f027abdSMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
194f027abdSMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
204f027abdSMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
214f027abdSMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
224f027abdSMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
234f027abdSMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
244f027abdSMarcel Moolenaar */
254f027abdSMarcel Moolenaar
264f027abdSMarcel Moolenaar #include <sys/param.h>
274f027abdSMarcel Moolenaar #include <sys/systm.h>
284f027abdSMarcel Moolenaar #include <machine/bus.h>
294f027abdSMarcel Moolenaar #include <machine/bus_dma.h>
304f027abdSMarcel Moolenaar #include <machine/resource.h>
314f027abdSMarcel Moolenaar #include <sys/bus.h>
324f027abdSMarcel Moolenaar #include <sys/conf.h>
334f027abdSMarcel Moolenaar #include <sys/kernel.h>
344f027abdSMarcel Moolenaar #include <sys/malloc.h>
354f027abdSMarcel Moolenaar #include <sys/module.h>
3689abdea8SMarcel Moolenaar #include <sys/proc.h>
374f027abdSMarcel Moolenaar #include <sys/queue.h>
384f027abdSMarcel Moolenaar #include <sys/rman.h>
394f027abdSMarcel Moolenaar #include <sys/sbuf.h>
40*9f011bcaSMarcel Moolenaar #include <sys/sx.h>
4189abdea8SMarcel Moolenaar #include <sys/uio.h>
425dcca8e8SMarcel Moolenaar #include <vm/vm.h>
435dcca8e8SMarcel Moolenaar #include <vm/pmap.h>
4489abdea8SMarcel Moolenaar #include <vm/vm_map.h>
454f027abdSMarcel Moolenaar
464f027abdSMarcel Moolenaar #include <dev/proto/proto.h>
474f027abdSMarcel Moolenaar #include <dev/proto/proto_dev.h>
484f027abdSMarcel Moolenaar #include <dev/proto/proto_busdma.h>
494f027abdSMarcel Moolenaar
504f027abdSMarcel Moolenaar MALLOC_DEFINE(M_PROTO_BUSDMA, "proto_busdma", "DMA management data");
514f027abdSMarcel Moolenaar
52b2ce196cSMarcel Moolenaar #define BNDRY_MIN(a, b) \
53b2ce196cSMarcel Moolenaar (((a) == 0) ? (b) : (((b) == 0) ? (a) : MIN((a), (b))))
54b2ce196cSMarcel Moolenaar
5589abdea8SMarcel Moolenaar struct proto_callback_bundle {
5689abdea8SMarcel Moolenaar struct proto_busdma *busdma;
5789abdea8SMarcel Moolenaar struct proto_md *md;
5889abdea8SMarcel Moolenaar struct proto_ioc_busdma *ioc;
5989abdea8SMarcel Moolenaar };
6089abdea8SMarcel Moolenaar
614f027abdSMarcel Moolenaar static int
proto_busdma_tag_create(struct proto_busdma * busdma,struct proto_tag * parent,struct proto_ioc_busdma * ioc)625dcca8e8SMarcel Moolenaar proto_busdma_tag_create(struct proto_busdma *busdma, struct proto_tag *parent,
635dcca8e8SMarcel Moolenaar struct proto_ioc_busdma *ioc)
644f027abdSMarcel Moolenaar {
654f027abdSMarcel Moolenaar struct proto_tag *tag;
664f027abdSMarcel Moolenaar
67b2ce196cSMarcel Moolenaar /* Make sure that when a boundary is specified, it's a power of 2 */
68b2ce196cSMarcel Moolenaar if (ioc->u.tag.bndry != 0 &&
69b2ce196cSMarcel Moolenaar (ioc->u.tag.bndry & (ioc->u.tag.bndry - 1)) != 0)
70b2ce196cSMarcel Moolenaar return (EINVAL);
71b2ce196cSMarcel Moolenaar
725dcca8e8SMarcel Moolenaar /*
735dcca8e8SMarcel Moolenaar * If nsegs is 1, ignore maxsegsz. What this means is that if we have
745dcca8e8SMarcel Moolenaar * just 1 segment, then maxsz should be equal to maxsegsz. To keep it
755dcca8e8SMarcel Moolenaar * simple for us, limit maxsegsz to maxsz in any case.
765dcca8e8SMarcel Moolenaar */
775dcca8e8SMarcel Moolenaar if (ioc->u.tag.maxsegsz > ioc->u.tag.maxsz || ioc->u.tag.nsegs == 1)
785dcca8e8SMarcel Moolenaar ioc->u.tag.maxsegsz = ioc->u.tag.maxsz;
795dcca8e8SMarcel Moolenaar
804f027abdSMarcel Moolenaar tag = malloc(sizeof(*tag), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
815dcca8e8SMarcel Moolenaar if (parent != NULL) {
825dcca8e8SMarcel Moolenaar tag->parent = parent;
835dcca8e8SMarcel Moolenaar LIST_INSERT_HEAD(&parent->children, tag, peers);
845dcca8e8SMarcel Moolenaar tag->align = MAX(ioc->u.tag.align, parent->align);
85b2ce196cSMarcel Moolenaar tag->bndry = BNDRY_MIN(ioc->u.tag.bndry, parent->bndry);
865dcca8e8SMarcel Moolenaar tag->maxaddr = MIN(ioc->u.tag.maxaddr, parent->maxaddr);
875dcca8e8SMarcel Moolenaar tag->maxsz = MIN(ioc->u.tag.maxsz, parent->maxsz);
885dcca8e8SMarcel Moolenaar tag->maxsegsz = MIN(ioc->u.tag.maxsegsz, parent->maxsegsz);
895dcca8e8SMarcel Moolenaar tag->nsegs = MIN(ioc->u.tag.nsegs, parent->nsegs);
905dcca8e8SMarcel Moolenaar tag->datarate = MIN(ioc->u.tag.datarate, parent->datarate);
915dcca8e8SMarcel Moolenaar /* Write constraints back */
925dcca8e8SMarcel Moolenaar ioc->u.tag.align = tag->align;
935dcca8e8SMarcel Moolenaar ioc->u.tag.bndry = tag->bndry;
945dcca8e8SMarcel Moolenaar ioc->u.tag.maxaddr = tag->maxaddr;
955dcca8e8SMarcel Moolenaar ioc->u.tag.maxsz = tag->maxsz;
965dcca8e8SMarcel Moolenaar ioc->u.tag.maxsegsz = tag->maxsegsz;
975dcca8e8SMarcel Moolenaar ioc->u.tag.nsegs = tag->nsegs;
985dcca8e8SMarcel Moolenaar ioc->u.tag.datarate = tag->datarate;
995dcca8e8SMarcel Moolenaar } else {
1005dcca8e8SMarcel Moolenaar tag->align = ioc->u.tag.align;
1015dcca8e8SMarcel Moolenaar tag->bndry = ioc->u.tag.bndry;
1025dcca8e8SMarcel Moolenaar tag->maxaddr = ioc->u.tag.maxaddr;
1035dcca8e8SMarcel Moolenaar tag->maxsz = ioc->u.tag.maxsz;
1045dcca8e8SMarcel Moolenaar tag->maxsegsz = ioc->u.tag.maxsegsz;
1055dcca8e8SMarcel Moolenaar tag->nsegs = ioc->u.tag.nsegs;
1065dcca8e8SMarcel Moolenaar tag->datarate = ioc->u.tag.datarate;
1075dcca8e8SMarcel Moolenaar }
1085dcca8e8SMarcel Moolenaar LIST_INSERT_HEAD(&busdma->tags, tag, tags);
1095dcca8e8SMarcel Moolenaar ioc->result = (uintptr_t)(void *)tag;
1104f027abdSMarcel Moolenaar return (0);
1114f027abdSMarcel Moolenaar }
1124f027abdSMarcel Moolenaar
1135dcca8e8SMarcel Moolenaar static int
proto_busdma_tag_destroy(struct proto_busdma * busdma,struct proto_tag * tag)1145dcca8e8SMarcel Moolenaar proto_busdma_tag_destroy(struct proto_busdma *busdma, struct proto_tag *tag)
1154f027abdSMarcel Moolenaar {
1164f027abdSMarcel Moolenaar
1175dcca8e8SMarcel Moolenaar if (!LIST_EMPTY(&tag->mds))
1185dcca8e8SMarcel Moolenaar return (EBUSY);
1195dcca8e8SMarcel Moolenaar if (!LIST_EMPTY(&tag->children))
1205dcca8e8SMarcel Moolenaar return (EBUSY);
1215dcca8e8SMarcel Moolenaar
1225dcca8e8SMarcel Moolenaar if (tag->parent != NULL) {
1235dcca8e8SMarcel Moolenaar LIST_REMOVE(tag, peers);
1245dcca8e8SMarcel Moolenaar tag->parent = NULL;
1255dcca8e8SMarcel Moolenaar }
1265dcca8e8SMarcel Moolenaar LIST_REMOVE(tag, tags);
1274f027abdSMarcel Moolenaar free(tag, M_PROTO_BUSDMA);
1285dcca8e8SMarcel Moolenaar return (0);
1294f027abdSMarcel Moolenaar }
1304f027abdSMarcel Moolenaar
1314f027abdSMarcel Moolenaar static struct proto_tag *
proto_busdma_tag_lookup(struct proto_busdma * busdma,u_long key)1324f027abdSMarcel Moolenaar proto_busdma_tag_lookup(struct proto_busdma *busdma, u_long key)
1334f027abdSMarcel Moolenaar {
1344f027abdSMarcel Moolenaar struct proto_tag *tag;
1354f027abdSMarcel Moolenaar
1365dcca8e8SMarcel Moolenaar LIST_FOREACH(tag, &busdma->tags, tags) {
1374f027abdSMarcel Moolenaar if ((void *)tag == (void *)key)
1384f027abdSMarcel Moolenaar return (tag);
1394f027abdSMarcel Moolenaar }
1404f027abdSMarcel Moolenaar return (NULL);
1414f027abdSMarcel Moolenaar }
1424f027abdSMarcel Moolenaar
14389abdea8SMarcel Moolenaar static int
proto_busdma_md_destroy_internal(struct proto_busdma * busdma,struct proto_md * md)14489abdea8SMarcel Moolenaar proto_busdma_md_destroy_internal(struct proto_busdma *busdma,
14589abdea8SMarcel Moolenaar struct proto_md *md)
14689abdea8SMarcel Moolenaar {
14789abdea8SMarcel Moolenaar
14889abdea8SMarcel Moolenaar LIST_REMOVE(md, mds);
14989abdea8SMarcel Moolenaar LIST_REMOVE(md, peers);
15089abdea8SMarcel Moolenaar if (md->physaddr)
15189abdea8SMarcel Moolenaar bus_dmamap_unload(md->bd_tag, md->bd_map);
15289abdea8SMarcel Moolenaar if (md->virtaddr != NULL)
15389abdea8SMarcel Moolenaar bus_dmamem_free(md->bd_tag, md->virtaddr, md->bd_map);
15489abdea8SMarcel Moolenaar else
15589abdea8SMarcel Moolenaar bus_dmamap_destroy(md->bd_tag, md->bd_map);
15689abdea8SMarcel Moolenaar bus_dma_tag_destroy(md->bd_tag);
15789abdea8SMarcel Moolenaar free(md, M_PROTO_BUSDMA);
15889abdea8SMarcel Moolenaar return (0);
15989abdea8SMarcel Moolenaar }
16089abdea8SMarcel Moolenaar
16190a1793cSMarcel Moolenaar static void
proto_busdma_mem_alloc_callback(void * arg,bus_dma_segment_t * segs,int nseg,int error)16290a1793cSMarcel Moolenaar proto_busdma_mem_alloc_callback(void *arg, bus_dma_segment_t *segs, int nseg,
16390a1793cSMarcel Moolenaar int error)
16490a1793cSMarcel Moolenaar {
16589abdea8SMarcel Moolenaar struct proto_callback_bundle *pcb = arg;
16690a1793cSMarcel Moolenaar
16789abdea8SMarcel Moolenaar pcb->ioc->u.md.bus_nsegs = nseg;
16889abdea8SMarcel Moolenaar pcb->ioc->u.md.bus_addr = segs[0].ds_addr;
16990a1793cSMarcel Moolenaar }
17090a1793cSMarcel Moolenaar
1715dcca8e8SMarcel Moolenaar static int
proto_busdma_mem_alloc(struct proto_busdma * busdma,struct proto_tag * tag,struct proto_ioc_busdma * ioc)1725dcca8e8SMarcel Moolenaar proto_busdma_mem_alloc(struct proto_busdma *busdma, struct proto_tag *tag,
1735dcca8e8SMarcel Moolenaar struct proto_ioc_busdma *ioc)
1745dcca8e8SMarcel Moolenaar {
17589abdea8SMarcel Moolenaar struct proto_callback_bundle pcb;
1765dcca8e8SMarcel Moolenaar struct proto_md *md;
1775dcca8e8SMarcel Moolenaar int error;
1785dcca8e8SMarcel Moolenaar
1795dcca8e8SMarcel Moolenaar md = malloc(sizeof(*md), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
1805dcca8e8SMarcel Moolenaar md->tag = tag;
1815dcca8e8SMarcel Moolenaar
1825dcca8e8SMarcel Moolenaar error = bus_dma_tag_create(busdma->bd_roottag, tag->align, tag->bndry,
1835dcca8e8SMarcel Moolenaar tag->maxaddr, BUS_SPACE_MAXADDR, NULL, NULL, tag->maxsz,
1845dcca8e8SMarcel Moolenaar tag->nsegs, tag->maxsegsz, 0, NULL, NULL, &md->bd_tag);
1855dcca8e8SMarcel Moolenaar if (error) {
1865dcca8e8SMarcel Moolenaar free(md, M_PROTO_BUSDMA);
1875dcca8e8SMarcel Moolenaar return (error);
1885dcca8e8SMarcel Moolenaar }
189cff0f135SMarcel Moolenaar error = bus_dmamem_alloc(md->bd_tag, &md->virtaddr, 0, &md->bd_map);
1905dcca8e8SMarcel Moolenaar if (error) {
1915dcca8e8SMarcel Moolenaar bus_dma_tag_destroy(md->bd_tag);
1925dcca8e8SMarcel Moolenaar free(md, M_PROTO_BUSDMA);
1935dcca8e8SMarcel Moolenaar return (error);
1945dcca8e8SMarcel Moolenaar }
195cff0f135SMarcel Moolenaar md->physaddr = pmap_kextract((uintptr_t)(md->virtaddr));
19689abdea8SMarcel Moolenaar pcb.busdma = busdma;
19789abdea8SMarcel Moolenaar pcb.md = md;
19889abdea8SMarcel Moolenaar pcb.ioc = ioc;
19990a1793cSMarcel Moolenaar error = bus_dmamap_load(md->bd_tag, md->bd_map, md->virtaddr,
20089abdea8SMarcel Moolenaar tag->maxsz, proto_busdma_mem_alloc_callback, &pcb, BUS_DMA_NOWAIT);
20190a1793cSMarcel Moolenaar if (error) {
20290a1793cSMarcel Moolenaar bus_dmamem_free(md->bd_tag, md->virtaddr, md->bd_map);
20390a1793cSMarcel Moolenaar bus_dma_tag_destroy(md->bd_tag);
20490a1793cSMarcel Moolenaar free(md, M_PROTO_BUSDMA);
20590a1793cSMarcel Moolenaar return (error);
20690a1793cSMarcel Moolenaar }
2075dcca8e8SMarcel Moolenaar LIST_INSERT_HEAD(&tag->mds, md, peers);
2085dcca8e8SMarcel Moolenaar LIST_INSERT_HEAD(&busdma->mds, md, mds);
20989abdea8SMarcel Moolenaar ioc->u.md.virt_addr = (uintptr_t)md->virtaddr;
21089abdea8SMarcel Moolenaar ioc->u.md.virt_size = tag->maxsz;
21189abdea8SMarcel Moolenaar ioc->u.md.phys_nsegs = 1;
21289abdea8SMarcel Moolenaar ioc->u.md.phys_addr = md->physaddr;
2135dcca8e8SMarcel Moolenaar ioc->result = (uintptr_t)(void *)md;
2145dcca8e8SMarcel Moolenaar return (0);
2155dcca8e8SMarcel Moolenaar }
2165dcca8e8SMarcel Moolenaar
2175dcca8e8SMarcel Moolenaar static int
proto_busdma_mem_free(struct proto_busdma * busdma,struct proto_md * md)2185dcca8e8SMarcel Moolenaar proto_busdma_mem_free(struct proto_busdma *busdma, struct proto_md *md)
2195dcca8e8SMarcel Moolenaar {
2205dcca8e8SMarcel Moolenaar
22189abdea8SMarcel Moolenaar if (md->virtaddr == NULL)
22289abdea8SMarcel Moolenaar return (ENXIO);
22389abdea8SMarcel Moolenaar return (proto_busdma_md_destroy_internal(busdma, md));
22489abdea8SMarcel Moolenaar }
22589abdea8SMarcel Moolenaar
22689abdea8SMarcel Moolenaar static int
proto_busdma_md_create(struct proto_busdma * busdma,struct proto_tag * tag,struct proto_ioc_busdma * ioc)22789abdea8SMarcel Moolenaar proto_busdma_md_create(struct proto_busdma *busdma, struct proto_tag *tag,
22889abdea8SMarcel Moolenaar struct proto_ioc_busdma *ioc)
22989abdea8SMarcel Moolenaar {
23089abdea8SMarcel Moolenaar struct proto_md *md;
23189abdea8SMarcel Moolenaar int error;
23289abdea8SMarcel Moolenaar
23389abdea8SMarcel Moolenaar md = malloc(sizeof(*md), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
23489abdea8SMarcel Moolenaar md->tag = tag;
23589abdea8SMarcel Moolenaar
23689abdea8SMarcel Moolenaar error = bus_dma_tag_create(busdma->bd_roottag, tag->align, tag->bndry,
23789abdea8SMarcel Moolenaar tag->maxaddr, BUS_SPACE_MAXADDR, NULL, NULL, tag->maxsz,
23889abdea8SMarcel Moolenaar tag->nsegs, tag->maxsegsz, 0, NULL, NULL, &md->bd_tag);
23989abdea8SMarcel Moolenaar if (error) {
24089abdea8SMarcel Moolenaar free(md, M_PROTO_BUSDMA);
24189abdea8SMarcel Moolenaar return (error);
24289abdea8SMarcel Moolenaar }
24389abdea8SMarcel Moolenaar error = bus_dmamap_create(md->bd_tag, 0, &md->bd_map);
24489abdea8SMarcel Moolenaar if (error) {
2455dcca8e8SMarcel Moolenaar bus_dma_tag_destroy(md->bd_tag);
2465dcca8e8SMarcel Moolenaar free(md, M_PROTO_BUSDMA);
24789abdea8SMarcel Moolenaar return (error);
24889abdea8SMarcel Moolenaar }
24989abdea8SMarcel Moolenaar
25089abdea8SMarcel Moolenaar LIST_INSERT_HEAD(&tag->mds, md, peers);
25189abdea8SMarcel Moolenaar LIST_INSERT_HEAD(&busdma->mds, md, mds);
25289abdea8SMarcel Moolenaar ioc->result = (uintptr_t)(void *)md;
25389abdea8SMarcel Moolenaar return (0);
25489abdea8SMarcel Moolenaar }
25589abdea8SMarcel Moolenaar
25689abdea8SMarcel Moolenaar static int
proto_busdma_md_destroy(struct proto_busdma * busdma,struct proto_md * md)25789abdea8SMarcel Moolenaar proto_busdma_md_destroy(struct proto_busdma *busdma, struct proto_md *md)
25889abdea8SMarcel Moolenaar {
25989abdea8SMarcel Moolenaar
26089abdea8SMarcel Moolenaar if (md->virtaddr != NULL)
26189abdea8SMarcel Moolenaar return (ENXIO);
26289abdea8SMarcel Moolenaar return (proto_busdma_md_destroy_internal(busdma, md));
26389abdea8SMarcel Moolenaar }
26489abdea8SMarcel Moolenaar
26589abdea8SMarcel Moolenaar static void
proto_busdma_md_load_callback(void * arg,bus_dma_segment_t * segs,int nseg,bus_size_t sz,int error)26689abdea8SMarcel Moolenaar proto_busdma_md_load_callback(void *arg, bus_dma_segment_t *segs, int nseg,
26789abdea8SMarcel Moolenaar bus_size_t sz, int error)
26889abdea8SMarcel Moolenaar {
26989abdea8SMarcel Moolenaar struct proto_callback_bundle *pcb = arg;
27089abdea8SMarcel Moolenaar
27189abdea8SMarcel Moolenaar pcb->ioc->u.md.bus_nsegs = nseg;
27289abdea8SMarcel Moolenaar pcb->ioc->u.md.bus_addr = segs[0].ds_addr;
27389abdea8SMarcel Moolenaar }
27489abdea8SMarcel Moolenaar
27589abdea8SMarcel Moolenaar static int
proto_busdma_md_load(struct proto_busdma * busdma,struct proto_md * md,struct proto_ioc_busdma * ioc,struct thread * td)27689abdea8SMarcel Moolenaar proto_busdma_md_load(struct proto_busdma *busdma, struct proto_md *md,
27789abdea8SMarcel Moolenaar struct proto_ioc_busdma *ioc, struct thread *td)
27889abdea8SMarcel Moolenaar {
27989abdea8SMarcel Moolenaar struct proto_callback_bundle pcb;
28089abdea8SMarcel Moolenaar struct iovec iov;
28189abdea8SMarcel Moolenaar struct uio uio;
28289abdea8SMarcel Moolenaar pmap_t pmap;
28389abdea8SMarcel Moolenaar int error;
28489abdea8SMarcel Moolenaar
28589abdea8SMarcel Moolenaar iov.iov_base = (void *)(uintptr_t)ioc->u.md.virt_addr;
28689abdea8SMarcel Moolenaar iov.iov_len = ioc->u.md.virt_size;
28789abdea8SMarcel Moolenaar uio.uio_iov = &iov;
28889abdea8SMarcel Moolenaar uio.uio_iovcnt = 1;
28989abdea8SMarcel Moolenaar uio.uio_offset = 0;
29089abdea8SMarcel Moolenaar uio.uio_resid = iov.iov_len;
29189abdea8SMarcel Moolenaar uio.uio_segflg = UIO_USERSPACE;
29289abdea8SMarcel Moolenaar uio.uio_rw = UIO_READ;
29389abdea8SMarcel Moolenaar uio.uio_td = td;
29489abdea8SMarcel Moolenaar
29589abdea8SMarcel Moolenaar pcb.busdma = busdma;
29689abdea8SMarcel Moolenaar pcb.md = md;
29789abdea8SMarcel Moolenaar pcb.ioc = ioc;
29889abdea8SMarcel Moolenaar error = bus_dmamap_load_uio(md->bd_tag, md->bd_map, &uio,
29989abdea8SMarcel Moolenaar proto_busdma_md_load_callback, &pcb, BUS_DMA_NOWAIT);
30089abdea8SMarcel Moolenaar if (error)
30189abdea8SMarcel Moolenaar return (error);
30289abdea8SMarcel Moolenaar
30389abdea8SMarcel Moolenaar /* XXX determine *all* physical memory segments */
30489abdea8SMarcel Moolenaar pmap = vmspace_pmap(td->td_proc->p_vmspace);
30589abdea8SMarcel Moolenaar md->physaddr = pmap_extract(pmap, ioc->u.md.virt_addr);
30689abdea8SMarcel Moolenaar ioc->u.md.phys_nsegs = 1; /* XXX */
30789abdea8SMarcel Moolenaar ioc->u.md.phys_addr = md->physaddr;
3085dcca8e8SMarcel Moolenaar return (0);
3095dcca8e8SMarcel Moolenaar }
3105dcca8e8SMarcel Moolenaar
31142d3ab5dSMarcel Moolenaar static int
proto_busdma_md_unload(struct proto_busdma * busdma,struct proto_md * md)31242d3ab5dSMarcel Moolenaar proto_busdma_md_unload(struct proto_busdma *busdma, struct proto_md *md)
31342d3ab5dSMarcel Moolenaar {
31442d3ab5dSMarcel Moolenaar
31542d3ab5dSMarcel Moolenaar if (!md->physaddr)
31642d3ab5dSMarcel Moolenaar return (ENXIO);
31742d3ab5dSMarcel Moolenaar bus_dmamap_unload(md->bd_tag, md->bd_map);
31842d3ab5dSMarcel Moolenaar md->physaddr = 0;
31942d3ab5dSMarcel Moolenaar return (0);
32042d3ab5dSMarcel Moolenaar }
32142d3ab5dSMarcel Moolenaar
32242d3ab5dSMarcel Moolenaar static int
proto_busdma_sync(struct proto_busdma * busdma,struct proto_md * md,struct proto_ioc_busdma * ioc)32342d3ab5dSMarcel Moolenaar proto_busdma_sync(struct proto_busdma *busdma, struct proto_md *md,
32442d3ab5dSMarcel Moolenaar struct proto_ioc_busdma *ioc)
32542d3ab5dSMarcel Moolenaar {
326f40c76d8SMarcel Moolenaar u_int ops;
32742d3ab5dSMarcel Moolenaar
328f40c76d8SMarcel Moolenaar ops = BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE |
329f40c76d8SMarcel Moolenaar BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE;
330f40c76d8SMarcel Moolenaar if (ioc->u.sync.op & ~ops)
331f40c76d8SMarcel Moolenaar return (EINVAL);
33242d3ab5dSMarcel Moolenaar if (!md->physaddr)
33342d3ab5dSMarcel Moolenaar return (ENXIO);
33442d3ab5dSMarcel Moolenaar bus_dmamap_sync(md->bd_tag, md->bd_map, ioc->u.sync.op);
33542d3ab5dSMarcel Moolenaar return (0);
33642d3ab5dSMarcel Moolenaar }
33742d3ab5dSMarcel Moolenaar
3385dcca8e8SMarcel Moolenaar static struct proto_md *
proto_busdma_md_lookup(struct proto_busdma * busdma,u_long key)3395dcca8e8SMarcel Moolenaar proto_busdma_md_lookup(struct proto_busdma *busdma, u_long key)
3405dcca8e8SMarcel Moolenaar {
3415dcca8e8SMarcel Moolenaar struct proto_md *md;
3425dcca8e8SMarcel Moolenaar
3435dcca8e8SMarcel Moolenaar LIST_FOREACH(md, &busdma->mds, mds) {
3445dcca8e8SMarcel Moolenaar if ((void *)md == (void *)key)
3455dcca8e8SMarcel Moolenaar return (md);
3465dcca8e8SMarcel Moolenaar }
3475dcca8e8SMarcel Moolenaar return (NULL);
3485dcca8e8SMarcel Moolenaar }
3495dcca8e8SMarcel Moolenaar
3504f027abdSMarcel Moolenaar struct proto_busdma *
proto_busdma_attach(struct proto_softc * sc)3514f027abdSMarcel Moolenaar proto_busdma_attach(struct proto_softc *sc)
3524f027abdSMarcel Moolenaar {
3534f027abdSMarcel Moolenaar struct proto_busdma *busdma;
3544f027abdSMarcel Moolenaar
3554f027abdSMarcel Moolenaar busdma = malloc(sizeof(*busdma), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
356*9f011bcaSMarcel Moolenaar sx_init(&busdma->sxlck, "proto-busdma");
3574f027abdSMarcel Moolenaar return (busdma);
3584f027abdSMarcel Moolenaar }
3594f027abdSMarcel Moolenaar
3604f027abdSMarcel Moolenaar int
proto_busdma_detach(struct proto_softc * sc,struct proto_busdma * busdma)3614f027abdSMarcel Moolenaar proto_busdma_detach(struct proto_softc *sc, struct proto_busdma *busdma)
3624f027abdSMarcel Moolenaar {
3634f027abdSMarcel Moolenaar
3644f027abdSMarcel Moolenaar proto_busdma_cleanup(sc, busdma);
365*9f011bcaSMarcel Moolenaar sx_destroy(&busdma->sxlck);
3664f027abdSMarcel Moolenaar free(busdma, M_PROTO_BUSDMA);
3674f027abdSMarcel Moolenaar return (0);
3684f027abdSMarcel Moolenaar }
3694f027abdSMarcel Moolenaar
3704f027abdSMarcel Moolenaar int
proto_busdma_cleanup(struct proto_softc * sc,struct proto_busdma * busdma)3714f027abdSMarcel Moolenaar proto_busdma_cleanup(struct proto_softc *sc, struct proto_busdma *busdma)
3724f027abdSMarcel Moolenaar {
3735dcca8e8SMarcel Moolenaar struct proto_md *md, *md1;
3744f027abdSMarcel Moolenaar struct proto_tag *tag, *tag1;
3754f027abdSMarcel Moolenaar
376*9f011bcaSMarcel Moolenaar sx_xlock(&busdma->sxlck);
3775dcca8e8SMarcel Moolenaar LIST_FOREACH_SAFE(md, &busdma->mds, mds, md1)
37889abdea8SMarcel Moolenaar proto_busdma_md_destroy_internal(busdma, md);
3795dcca8e8SMarcel Moolenaar LIST_FOREACH_SAFE(tag, &busdma->tags, tags, tag1)
3805dcca8e8SMarcel Moolenaar proto_busdma_tag_destroy(busdma, tag);
381*9f011bcaSMarcel Moolenaar sx_xunlock(&busdma->sxlck);
3824f027abdSMarcel Moolenaar return (0);
3834f027abdSMarcel Moolenaar }
3844f027abdSMarcel Moolenaar
3854f027abdSMarcel Moolenaar int
proto_busdma_ioctl(struct proto_softc * sc,struct proto_busdma * busdma,struct proto_ioc_busdma * ioc,struct thread * td)3864f027abdSMarcel Moolenaar proto_busdma_ioctl(struct proto_softc *sc, struct proto_busdma *busdma,
38789abdea8SMarcel Moolenaar struct proto_ioc_busdma *ioc, struct thread *td)
3884f027abdSMarcel Moolenaar {
3894f027abdSMarcel Moolenaar struct proto_tag *tag;
3905dcca8e8SMarcel Moolenaar struct proto_md *md;
3914f027abdSMarcel Moolenaar int error;
3924f027abdSMarcel Moolenaar
393*9f011bcaSMarcel Moolenaar sx_xlock(&busdma->sxlck);
394*9f011bcaSMarcel Moolenaar
3954f027abdSMarcel Moolenaar error = 0;
3964f027abdSMarcel Moolenaar switch (ioc->request) {
3974f027abdSMarcel Moolenaar case PROTO_IOC_BUSDMA_TAG_CREATE:
3985dcca8e8SMarcel Moolenaar busdma->bd_roottag = bus_get_dma_tag(sc->sc_dev);
3995dcca8e8SMarcel Moolenaar error = proto_busdma_tag_create(busdma, NULL, ioc);
4004f027abdSMarcel Moolenaar break;
4014f027abdSMarcel Moolenaar case PROTO_IOC_BUSDMA_TAG_DERIVE:
4024f027abdSMarcel Moolenaar tag = proto_busdma_tag_lookup(busdma, ioc->key);
4034f027abdSMarcel Moolenaar if (tag == NULL) {
4044f027abdSMarcel Moolenaar error = EINVAL;
4054f027abdSMarcel Moolenaar break;
4064f027abdSMarcel Moolenaar }
4075dcca8e8SMarcel Moolenaar error = proto_busdma_tag_create(busdma, tag, ioc);
4084f027abdSMarcel Moolenaar break;
4094f027abdSMarcel Moolenaar case PROTO_IOC_BUSDMA_TAG_DESTROY:
4104f027abdSMarcel Moolenaar tag = proto_busdma_tag_lookup(busdma, ioc->key);
4114f027abdSMarcel Moolenaar if (tag == NULL) {
4124f027abdSMarcel Moolenaar error = EINVAL;
4134f027abdSMarcel Moolenaar break;
4144f027abdSMarcel Moolenaar }
4155dcca8e8SMarcel Moolenaar error = proto_busdma_tag_destroy(busdma, tag);
4165dcca8e8SMarcel Moolenaar break;
4175dcca8e8SMarcel Moolenaar case PROTO_IOC_BUSDMA_MEM_ALLOC:
41889abdea8SMarcel Moolenaar tag = proto_busdma_tag_lookup(busdma, ioc->u.md.tag);
4195dcca8e8SMarcel Moolenaar if (tag == NULL) {
4205dcca8e8SMarcel Moolenaar error = EINVAL;
4215dcca8e8SMarcel Moolenaar break;
4225dcca8e8SMarcel Moolenaar }
4235dcca8e8SMarcel Moolenaar error = proto_busdma_mem_alloc(busdma, tag, ioc);
4245dcca8e8SMarcel Moolenaar break;
4255dcca8e8SMarcel Moolenaar case PROTO_IOC_BUSDMA_MEM_FREE:
4265dcca8e8SMarcel Moolenaar md = proto_busdma_md_lookup(busdma, ioc->key);
4275dcca8e8SMarcel Moolenaar if (md == NULL) {
4285dcca8e8SMarcel Moolenaar error = EINVAL;
4295dcca8e8SMarcel Moolenaar break;
4305dcca8e8SMarcel Moolenaar }
4315dcca8e8SMarcel Moolenaar error = proto_busdma_mem_free(busdma, md);
4324f027abdSMarcel Moolenaar break;
43389abdea8SMarcel Moolenaar case PROTO_IOC_BUSDMA_MD_CREATE:
43489abdea8SMarcel Moolenaar tag = proto_busdma_tag_lookup(busdma, ioc->u.md.tag);
43589abdea8SMarcel Moolenaar if (tag == NULL) {
43689abdea8SMarcel Moolenaar error = EINVAL;
43789abdea8SMarcel Moolenaar break;
43889abdea8SMarcel Moolenaar }
43989abdea8SMarcel Moolenaar error = proto_busdma_md_create(busdma, tag, ioc);
44089abdea8SMarcel Moolenaar break;
44189abdea8SMarcel Moolenaar case PROTO_IOC_BUSDMA_MD_DESTROY:
44289abdea8SMarcel Moolenaar md = proto_busdma_md_lookup(busdma, ioc->key);
44389abdea8SMarcel Moolenaar if (md == NULL) {
44489abdea8SMarcel Moolenaar error = EINVAL;
44589abdea8SMarcel Moolenaar break;
44689abdea8SMarcel Moolenaar }
44789abdea8SMarcel Moolenaar error = proto_busdma_md_destroy(busdma, md);
44889abdea8SMarcel Moolenaar break;
44989abdea8SMarcel Moolenaar case PROTO_IOC_BUSDMA_MD_LOAD:
45089abdea8SMarcel Moolenaar md = proto_busdma_md_lookup(busdma, ioc->key);
45189abdea8SMarcel Moolenaar if (md == NULL) {
45289abdea8SMarcel Moolenaar error = EINVAL;
45389abdea8SMarcel Moolenaar break;
45489abdea8SMarcel Moolenaar }
45589abdea8SMarcel Moolenaar error = proto_busdma_md_load(busdma, md, ioc, td);
45689abdea8SMarcel Moolenaar break;
45742d3ab5dSMarcel Moolenaar case PROTO_IOC_BUSDMA_MD_UNLOAD:
45842d3ab5dSMarcel Moolenaar md = proto_busdma_md_lookup(busdma, ioc->key);
45942d3ab5dSMarcel Moolenaar if (md == NULL) {
46042d3ab5dSMarcel Moolenaar error = EINVAL;
46142d3ab5dSMarcel Moolenaar break;
46242d3ab5dSMarcel Moolenaar }
46342d3ab5dSMarcel Moolenaar error = proto_busdma_md_unload(busdma, md);
46442d3ab5dSMarcel Moolenaar break;
46542d3ab5dSMarcel Moolenaar case PROTO_IOC_BUSDMA_SYNC:
46642d3ab5dSMarcel Moolenaar md = proto_busdma_md_lookup(busdma, ioc->key);
46742d3ab5dSMarcel Moolenaar if (md == NULL) {
46842d3ab5dSMarcel Moolenaar error = EINVAL;
46942d3ab5dSMarcel Moolenaar break;
47042d3ab5dSMarcel Moolenaar }
47142d3ab5dSMarcel Moolenaar error = proto_busdma_sync(busdma, md, ioc);
47242d3ab5dSMarcel Moolenaar break;
4734f027abdSMarcel Moolenaar default:
4744f027abdSMarcel Moolenaar error = EINVAL;
4754f027abdSMarcel Moolenaar break;
4764f027abdSMarcel Moolenaar }
477*9f011bcaSMarcel Moolenaar
478*9f011bcaSMarcel Moolenaar sx_xunlock(&busdma->sxlck);
479*9f011bcaSMarcel Moolenaar
4804f027abdSMarcel Moolenaar return (error);
4814f027abdSMarcel Moolenaar }
482cff0f135SMarcel Moolenaar
483cff0f135SMarcel Moolenaar int
proto_busdma_mmap_allowed(struct proto_busdma * busdma,vm_paddr_t physaddr)484cff0f135SMarcel Moolenaar proto_busdma_mmap_allowed(struct proto_busdma *busdma, vm_paddr_t physaddr)
485cff0f135SMarcel Moolenaar {
486cff0f135SMarcel Moolenaar struct proto_md *md;
487*9f011bcaSMarcel Moolenaar int result;
488cff0f135SMarcel Moolenaar
489*9f011bcaSMarcel Moolenaar sx_xlock(&busdma->sxlck);
490*9f011bcaSMarcel Moolenaar
491*9f011bcaSMarcel Moolenaar result = 0;
492cff0f135SMarcel Moolenaar LIST_FOREACH(md, &busdma->mds, mds) {
493cff0f135SMarcel Moolenaar if (physaddr >= trunc_page(md->physaddr) &&
494*9f011bcaSMarcel Moolenaar physaddr <= trunc_page(md->physaddr + md->tag->maxsz)) {
495*9f011bcaSMarcel Moolenaar result = 1;
496*9f011bcaSMarcel Moolenaar break;
497cff0f135SMarcel Moolenaar }
498*9f011bcaSMarcel Moolenaar }
499*9f011bcaSMarcel Moolenaar
500*9f011bcaSMarcel Moolenaar sx_xunlock(&busdma->sxlck);
501*9f011bcaSMarcel Moolenaar
502*9f011bcaSMarcel Moolenaar return (result);
503cff0f135SMarcel Moolenaar }
504