xref: /freebsd/sys/dev/proto/proto_busdma.c (revision 89abdea8f020e3afd03227c7fa2d3ec20cb26689)
14f027abdSMarcel Moolenaar /*-
24f027abdSMarcel Moolenaar  * Copyright (c) 2015 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/cdefs.h>
274f027abdSMarcel Moolenaar __FBSDID("$FreeBSD$");
284f027abdSMarcel Moolenaar 
294f027abdSMarcel Moolenaar #include <sys/param.h>
304f027abdSMarcel Moolenaar #include <sys/systm.h>
314f027abdSMarcel Moolenaar #include <machine/bus.h>
324f027abdSMarcel Moolenaar #include <machine/bus_dma.h>
334f027abdSMarcel Moolenaar #include <machine/resource.h>
344f027abdSMarcel Moolenaar #include <sys/bus.h>
354f027abdSMarcel Moolenaar #include <sys/conf.h>
364f027abdSMarcel Moolenaar #include <sys/kernel.h>
374f027abdSMarcel Moolenaar #include <sys/malloc.h>
384f027abdSMarcel Moolenaar #include <sys/module.h>
39*89abdea8SMarcel Moolenaar #include <sys/proc.h>
404f027abdSMarcel Moolenaar #include <sys/queue.h>
414f027abdSMarcel Moolenaar #include <sys/rman.h>
424f027abdSMarcel Moolenaar #include <sys/sbuf.h>
43*89abdea8SMarcel Moolenaar #include <sys/uio.h>
445dcca8e8SMarcel Moolenaar #include <vm/vm.h>
455dcca8e8SMarcel Moolenaar #include <vm/pmap.h>
46*89abdea8SMarcel Moolenaar #include <vm/vm_map.h>
474f027abdSMarcel Moolenaar 
484f027abdSMarcel Moolenaar #include <dev/proto/proto.h>
494f027abdSMarcel Moolenaar #include <dev/proto/proto_dev.h>
504f027abdSMarcel Moolenaar #include <dev/proto/proto_busdma.h>
514f027abdSMarcel Moolenaar 
524f027abdSMarcel Moolenaar MALLOC_DEFINE(M_PROTO_BUSDMA, "proto_busdma", "DMA management data");
534f027abdSMarcel Moolenaar 
54*89abdea8SMarcel Moolenaar struct proto_callback_bundle {
55*89abdea8SMarcel Moolenaar 	struct proto_busdma *busdma;
56*89abdea8SMarcel Moolenaar 	struct proto_md *md;
57*89abdea8SMarcel Moolenaar 	struct proto_ioc_busdma *ioc;
58*89abdea8SMarcel Moolenaar };
59*89abdea8SMarcel Moolenaar 
604f027abdSMarcel Moolenaar static int
615dcca8e8SMarcel Moolenaar proto_busdma_tag_create(struct proto_busdma *busdma, struct proto_tag *parent,
625dcca8e8SMarcel Moolenaar     struct proto_ioc_busdma *ioc)
634f027abdSMarcel Moolenaar {
644f027abdSMarcel Moolenaar 	struct proto_tag *tag;
654f027abdSMarcel Moolenaar 
665dcca8e8SMarcel Moolenaar 	/*
675dcca8e8SMarcel Moolenaar 	 * If nsegs is 1, ignore maxsegsz. What this means is that if we have
685dcca8e8SMarcel Moolenaar 	 * just 1 segment, then maxsz should be equal to maxsegsz. To keep it
695dcca8e8SMarcel Moolenaar 	 * simple for us, limit maxsegsz to maxsz in any case.
705dcca8e8SMarcel Moolenaar 	 */
715dcca8e8SMarcel Moolenaar 	if (ioc->u.tag.maxsegsz > ioc->u.tag.maxsz || ioc->u.tag.nsegs == 1)
725dcca8e8SMarcel Moolenaar 		ioc->u.tag.maxsegsz = ioc->u.tag.maxsz;
735dcca8e8SMarcel Moolenaar 
745dcca8e8SMarcel Moolenaar 	/* A bndry of 0 really means ~0, or no boundary. */
755dcca8e8SMarcel Moolenaar 	if (ioc->u.tag.bndry == 0)
765dcca8e8SMarcel Moolenaar 		ioc->u.tag.bndry = ~0U;
774f027abdSMarcel Moolenaar 
784f027abdSMarcel Moolenaar 	tag = malloc(sizeof(*tag), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
795dcca8e8SMarcel Moolenaar 	if (parent != NULL) {
805dcca8e8SMarcel Moolenaar 		tag->parent = parent;
815dcca8e8SMarcel Moolenaar 		LIST_INSERT_HEAD(&parent->children, tag, peers);
825dcca8e8SMarcel Moolenaar 		tag->align = MAX(ioc->u.tag.align, parent->align);
835dcca8e8SMarcel Moolenaar 		tag->bndry = MIN(ioc->u.tag.bndry, parent->bndry);
845dcca8e8SMarcel Moolenaar 		tag->maxaddr = MIN(ioc->u.tag.maxaddr, parent->maxaddr);
855dcca8e8SMarcel Moolenaar 		tag->maxsz = MIN(ioc->u.tag.maxsz, parent->maxsz);
865dcca8e8SMarcel Moolenaar 		tag->maxsegsz = MIN(ioc->u.tag.maxsegsz, parent->maxsegsz);
875dcca8e8SMarcel Moolenaar 		tag->nsegs = MIN(ioc->u.tag.nsegs, parent->nsegs);
885dcca8e8SMarcel Moolenaar 		tag->datarate = MIN(ioc->u.tag.datarate, parent->datarate);
895dcca8e8SMarcel Moolenaar 		/* Write constraints back */
905dcca8e8SMarcel Moolenaar 		ioc->u.tag.align = tag->align;
915dcca8e8SMarcel Moolenaar 		ioc->u.tag.bndry = tag->bndry;
925dcca8e8SMarcel Moolenaar 		ioc->u.tag.maxaddr = tag->maxaddr;
935dcca8e8SMarcel Moolenaar 		ioc->u.tag.maxsz = tag->maxsz;
945dcca8e8SMarcel Moolenaar 		ioc->u.tag.maxsegsz = tag->maxsegsz;
955dcca8e8SMarcel Moolenaar 		ioc->u.tag.nsegs = tag->nsegs;
965dcca8e8SMarcel Moolenaar 		ioc->u.tag.datarate = tag->datarate;
975dcca8e8SMarcel Moolenaar 	} else {
985dcca8e8SMarcel Moolenaar 		tag->align = ioc->u.tag.align;
995dcca8e8SMarcel Moolenaar 		tag->bndry = ioc->u.tag.bndry;
1005dcca8e8SMarcel Moolenaar 		tag->maxaddr = ioc->u.tag.maxaddr;
1015dcca8e8SMarcel Moolenaar 		tag->maxsz = ioc->u.tag.maxsz;
1025dcca8e8SMarcel Moolenaar 		tag->maxsegsz = ioc->u.tag.maxsegsz;
1035dcca8e8SMarcel Moolenaar 		tag->nsegs = ioc->u.tag.nsegs;
1045dcca8e8SMarcel Moolenaar 		tag->datarate = ioc->u.tag.datarate;
1055dcca8e8SMarcel Moolenaar 	}
1065dcca8e8SMarcel Moolenaar 	LIST_INSERT_HEAD(&busdma->tags, tag, tags);
1075dcca8e8SMarcel Moolenaar 	ioc->result = (uintptr_t)(void *)tag;
1084f027abdSMarcel Moolenaar 	return (0);
1094f027abdSMarcel Moolenaar }
1104f027abdSMarcel Moolenaar 
1115dcca8e8SMarcel Moolenaar static int
1125dcca8e8SMarcel Moolenaar proto_busdma_tag_destroy(struct proto_busdma *busdma, struct proto_tag *tag)
1134f027abdSMarcel Moolenaar {
1144f027abdSMarcel Moolenaar 
1155dcca8e8SMarcel Moolenaar 	if (!LIST_EMPTY(&tag->mds))
1165dcca8e8SMarcel Moolenaar 		return (EBUSY);
1175dcca8e8SMarcel Moolenaar 	if (!LIST_EMPTY(&tag->children))
1185dcca8e8SMarcel Moolenaar 		return (EBUSY);
1195dcca8e8SMarcel Moolenaar 
1205dcca8e8SMarcel Moolenaar 	if (tag->parent != NULL) {
1215dcca8e8SMarcel Moolenaar 		LIST_REMOVE(tag, peers);
1225dcca8e8SMarcel Moolenaar 		tag->parent = NULL;
1235dcca8e8SMarcel Moolenaar 	}
1245dcca8e8SMarcel Moolenaar 	LIST_REMOVE(tag, tags);
1254f027abdSMarcel Moolenaar 	free(tag, M_PROTO_BUSDMA);
1265dcca8e8SMarcel Moolenaar 	return (0);
1274f027abdSMarcel Moolenaar }
1284f027abdSMarcel Moolenaar 
1294f027abdSMarcel Moolenaar static struct proto_tag *
1304f027abdSMarcel Moolenaar proto_busdma_tag_lookup(struct proto_busdma *busdma, u_long key)
1314f027abdSMarcel Moolenaar {
1324f027abdSMarcel Moolenaar 	struct proto_tag *tag;
1334f027abdSMarcel Moolenaar 
1345dcca8e8SMarcel Moolenaar 	LIST_FOREACH(tag, &busdma->tags, tags) {
1354f027abdSMarcel Moolenaar 		if ((void *)tag == (void *)key)
1364f027abdSMarcel Moolenaar 			return (tag);
1374f027abdSMarcel Moolenaar 	}
1384f027abdSMarcel Moolenaar 	return (NULL);
1394f027abdSMarcel Moolenaar }
1404f027abdSMarcel Moolenaar 
141*89abdea8SMarcel Moolenaar static int
142*89abdea8SMarcel Moolenaar proto_busdma_md_destroy_internal(struct proto_busdma *busdma,
143*89abdea8SMarcel Moolenaar     struct proto_md *md)
144*89abdea8SMarcel Moolenaar {
145*89abdea8SMarcel Moolenaar 
146*89abdea8SMarcel Moolenaar 	LIST_REMOVE(md, mds);
147*89abdea8SMarcel Moolenaar 	LIST_REMOVE(md, peers);
148*89abdea8SMarcel Moolenaar 	if (md->physaddr)
149*89abdea8SMarcel Moolenaar 		bus_dmamap_unload(md->bd_tag, md->bd_map);
150*89abdea8SMarcel Moolenaar 	if (md->virtaddr != NULL)
151*89abdea8SMarcel Moolenaar 		bus_dmamem_free(md->bd_tag, md->virtaddr, md->bd_map);
152*89abdea8SMarcel Moolenaar 	else
153*89abdea8SMarcel Moolenaar 		bus_dmamap_destroy(md->bd_tag, md->bd_map);
154*89abdea8SMarcel Moolenaar 	bus_dma_tag_destroy(md->bd_tag);
155*89abdea8SMarcel Moolenaar 	free(md, M_PROTO_BUSDMA);
156*89abdea8SMarcel Moolenaar 	return (0);
157*89abdea8SMarcel Moolenaar }
158*89abdea8SMarcel Moolenaar 
15990a1793cSMarcel Moolenaar static void
16090a1793cSMarcel Moolenaar proto_busdma_mem_alloc_callback(void *arg, bus_dma_segment_t *segs, int	nseg,
16190a1793cSMarcel Moolenaar     int error)
16290a1793cSMarcel Moolenaar {
163*89abdea8SMarcel Moolenaar 	struct proto_callback_bundle *pcb = arg;
16490a1793cSMarcel Moolenaar 
165*89abdea8SMarcel Moolenaar 	pcb->ioc->u.md.bus_nsegs = nseg;
166*89abdea8SMarcel Moolenaar 	pcb->ioc->u.md.bus_addr = segs[0].ds_addr;
16790a1793cSMarcel Moolenaar }
16890a1793cSMarcel Moolenaar 
1695dcca8e8SMarcel Moolenaar static int
1705dcca8e8SMarcel Moolenaar proto_busdma_mem_alloc(struct proto_busdma *busdma, struct proto_tag *tag,
1715dcca8e8SMarcel Moolenaar     struct proto_ioc_busdma *ioc)
1725dcca8e8SMarcel Moolenaar {
173*89abdea8SMarcel Moolenaar 	struct proto_callback_bundle pcb;
1745dcca8e8SMarcel Moolenaar 	struct proto_md *md;
1755dcca8e8SMarcel Moolenaar 	int error;
1765dcca8e8SMarcel Moolenaar 
1775dcca8e8SMarcel Moolenaar 	md = malloc(sizeof(*md), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
1785dcca8e8SMarcel Moolenaar 	md->tag = tag;
1795dcca8e8SMarcel Moolenaar 
1805dcca8e8SMarcel Moolenaar 	error = bus_dma_tag_create(busdma->bd_roottag, tag->align, tag->bndry,
1815dcca8e8SMarcel Moolenaar 	    tag->maxaddr, BUS_SPACE_MAXADDR, NULL, NULL, tag->maxsz,
1825dcca8e8SMarcel Moolenaar 	    tag->nsegs, tag->maxsegsz, 0, NULL, NULL, &md->bd_tag);
1835dcca8e8SMarcel Moolenaar 	if (error) {
1845dcca8e8SMarcel Moolenaar 		free(md, M_PROTO_BUSDMA);
1855dcca8e8SMarcel Moolenaar 		return (error);
1865dcca8e8SMarcel Moolenaar 	}
187cff0f135SMarcel Moolenaar 	error = bus_dmamem_alloc(md->bd_tag, &md->virtaddr, 0, &md->bd_map);
1885dcca8e8SMarcel Moolenaar 	if (error) {
1895dcca8e8SMarcel Moolenaar 		bus_dma_tag_destroy(md->bd_tag);
1905dcca8e8SMarcel Moolenaar 		free(md, M_PROTO_BUSDMA);
1915dcca8e8SMarcel Moolenaar 		return (error);
1925dcca8e8SMarcel Moolenaar 	}
193cff0f135SMarcel Moolenaar 	md->physaddr = pmap_kextract((uintptr_t)(md->virtaddr));
194*89abdea8SMarcel Moolenaar 	pcb.busdma = busdma;
195*89abdea8SMarcel Moolenaar 	pcb.md = md;
196*89abdea8SMarcel Moolenaar 	pcb.ioc = ioc;
19790a1793cSMarcel Moolenaar 	error = bus_dmamap_load(md->bd_tag, md->bd_map, md->virtaddr,
198*89abdea8SMarcel Moolenaar 	    tag->maxsz, proto_busdma_mem_alloc_callback, &pcb, BUS_DMA_NOWAIT);
19990a1793cSMarcel Moolenaar 	if (error) {
20090a1793cSMarcel Moolenaar 		bus_dmamem_free(md->bd_tag, md->virtaddr, md->bd_map);
20190a1793cSMarcel Moolenaar 		bus_dma_tag_destroy(md->bd_tag);
20290a1793cSMarcel Moolenaar 		free(md, M_PROTO_BUSDMA);
20390a1793cSMarcel Moolenaar 		return (error);
20490a1793cSMarcel Moolenaar 	}
2055dcca8e8SMarcel Moolenaar 	LIST_INSERT_HEAD(&tag->mds, md, peers);
2065dcca8e8SMarcel Moolenaar 	LIST_INSERT_HEAD(&busdma->mds, md, mds);
207*89abdea8SMarcel Moolenaar 	ioc->u.md.virt_addr = (uintptr_t)md->virtaddr;
208*89abdea8SMarcel Moolenaar 	ioc->u.md.virt_size = tag->maxsz;
209*89abdea8SMarcel Moolenaar 	ioc->u.md.phys_nsegs = 1;
210*89abdea8SMarcel Moolenaar 	ioc->u.md.phys_addr = md->physaddr;
2115dcca8e8SMarcel Moolenaar 	ioc->result = (uintptr_t)(void *)md;
2125dcca8e8SMarcel Moolenaar 	return (0);
2135dcca8e8SMarcel Moolenaar }
2145dcca8e8SMarcel Moolenaar 
2155dcca8e8SMarcel Moolenaar static int
2165dcca8e8SMarcel Moolenaar proto_busdma_mem_free(struct proto_busdma *busdma, struct proto_md *md)
2175dcca8e8SMarcel Moolenaar {
2185dcca8e8SMarcel Moolenaar 
219*89abdea8SMarcel Moolenaar 	if (md->virtaddr == NULL)
220*89abdea8SMarcel Moolenaar 		return (ENXIO);
221*89abdea8SMarcel Moolenaar 	return (proto_busdma_md_destroy_internal(busdma, md));
222*89abdea8SMarcel Moolenaar }
223*89abdea8SMarcel Moolenaar 
224*89abdea8SMarcel Moolenaar static int
225*89abdea8SMarcel Moolenaar proto_busdma_md_create(struct proto_busdma *busdma, struct proto_tag *tag,
226*89abdea8SMarcel Moolenaar     struct proto_ioc_busdma *ioc)
227*89abdea8SMarcel Moolenaar {
228*89abdea8SMarcel Moolenaar 	struct proto_md *md;
229*89abdea8SMarcel Moolenaar 	int error;
230*89abdea8SMarcel Moolenaar 
231*89abdea8SMarcel Moolenaar 	md = malloc(sizeof(*md), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
232*89abdea8SMarcel Moolenaar 	md->tag = tag;
233*89abdea8SMarcel Moolenaar 
234*89abdea8SMarcel Moolenaar 	error = bus_dma_tag_create(busdma->bd_roottag, tag->align, tag->bndry,
235*89abdea8SMarcel Moolenaar 	    tag->maxaddr, BUS_SPACE_MAXADDR, NULL, NULL, tag->maxsz,
236*89abdea8SMarcel Moolenaar 	    tag->nsegs, tag->maxsegsz, 0, NULL, NULL, &md->bd_tag);
237*89abdea8SMarcel Moolenaar 	if (error) {
238*89abdea8SMarcel Moolenaar 		free(md, M_PROTO_BUSDMA);
239*89abdea8SMarcel Moolenaar 		return (error);
240*89abdea8SMarcel Moolenaar 	}
241*89abdea8SMarcel Moolenaar 	error = bus_dmamap_create(md->bd_tag, 0, &md->bd_map);
242*89abdea8SMarcel Moolenaar 	if (error) {
2435dcca8e8SMarcel Moolenaar 		bus_dma_tag_destroy(md->bd_tag);
2445dcca8e8SMarcel Moolenaar 		free(md, M_PROTO_BUSDMA);
245*89abdea8SMarcel Moolenaar 		return (error);
246*89abdea8SMarcel Moolenaar 	}
247*89abdea8SMarcel Moolenaar 
248*89abdea8SMarcel Moolenaar 	LIST_INSERT_HEAD(&tag->mds, md, peers);
249*89abdea8SMarcel Moolenaar 	LIST_INSERT_HEAD(&busdma->mds, md, mds);
250*89abdea8SMarcel Moolenaar 	ioc->result = (uintptr_t)(void *)md;
251*89abdea8SMarcel Moolenaar 	return (0);
252*89abdea8SMarcel Moolenaar }
253*89abdea8SMarcel Moolenaar 
254*89abdea8SMarcel Moolenaar static int
255*89abdea8SMarcel Moolenaar proto_busdma_md_destroy(struct proto_busdma *busdma, struct proto_md *md)
256*89abdea8SMarcel Moolenaar {
257*89abdea8SMarcel Moolenaar 
258*89abdea8SMarcel Moolenaar 	if (md->virtaddr != NULL)
259*89abdea8SMarcel Moolenaar 		return (ENXIO);
260*89abdea8SMarcel Moolenaar 	return (proto_busdma_md_destroy_internal(busdma, md));
261*89abdea8SMarcel Moolenaar }
262*89abdea8SMarcel Moolenaar 
263*89abdea8SMarcel Moolenaar static void
264*89abdea8SMarcel Moolenaar proto_busdma_md_load_callback(void *arg, bus_dma_segment_t *segs, int nseg,
265*89abdea8SMarcel Moolenaar     bus_size_t sz, int error)
266*89abdea8SMarcel Moolenaar {
267*89abdea8SMarcel Moolenaar 	struct proto_callback_bundle *pcb = arg;
268*89abdea8SMarcel Moolenaar 
269*89abdea8SMarcel Moolenaar 	pcb->ioc->u.md.bus_nsegs = nseg;
270*89abdea8SMarcel Moolenaar 	pcb->ioc->u.md.bus_addr = segs[0].ds_addr;
271*89abdea8SMarcel Moolenaar }
272*89abdea8SMarcel Moolenaar 
273*89abdea8SMarcel Moolenaar static int
274*89abdea8SMarcel Moolenaar proto_busdma_md_load(struct proto_busdma *busdma, struct proto_md *md,
275*89abdea8SMarcel Moolenaar     struct proto_ioc_busdma *ioc, struct thread *td)
276*89abdea8SMarcel Moolenaar {
277*89abdea8SMarcel Moolenaar 	struct proto_callback_bundle pcb;
278*89abdea8SMarcel Moolenaar 	struct iovec iov;
279*89abdea8SMarcel Moolenaar 	struct uio uio;
280*89abdea8SMarcel Moolenaar 	pmap_t pmap;
281*89abdea8SMarcel Moolenaar 	int error;
282*89abdea8SMarcel Moolenaar 
283*89abdea8SMarcel Moolenaar 	iov.iov_base = (void *)(uintptr_t)ioc->u.md.virt_addr;
284*89abdea8SMarcel Moolenaar 	iov.iov_len = ioc->u.md.virt_size;
285*89abdea8SMarcel Moolenaar 	uio.uio_iov = &iov;
286*89abdea8SMarcel Moolenaar 	uio.uio_iovcnt = 1;
287*89abdea8SMarcel Moolenaar 	uio.uio_offset = 0;
288*89abdea8SMarcel Moolenaar 	uio.uio_resid = iov.iov_len;
289*89abdea8SMarcel Moolenaar 	uio.uio_segflg = UIO_USERSPACE;
290*89abdea8SMarcel Moolenaar 	uio.uio_rw = UIO_READ;
291*89abdea8SMarcel Moolenaar 	uio.uio_td = td;
292*89abdea8SMarcel Moolenaar 
293*89abdea8SMarcel Moolenaar 	pcb.busdma = busdma;
294*89abdea8SMarcel Moolenaar 	pcb.md = md;
295*89abdea8SMarcel Moolenaar 	pcb.ioc = ioc;
296*89abdea8SMarcel Moolenaar 	error = bus_dmamap_load_uio(md->bd_tag, md->bd_map, &uio,
297*89abdea8SMarcel Moolenaar 	    proto_busdma_md_load_callback, &pcb, BUS_DMA_NOWAIT);
298*89abdea8SMarcel Moolenaar 	if (error)
299*89abdea8SMarcel Moolenaar 		return (error);
300*89abdea8SMarcel Moolenaar 
301*89abdea8SMarcel Moolenaar 	/* XXX determine *all* physical memory segments */
302*89abdea8SMarcel Moolenaar 	pmap = vmspace_pmap(td->td_proc->p_vmspace);
303*89abdea8SMarcel Moolenaar 	md->physaddr = pmap_extract(pmap, ioc->u.md.virt_addr);
304*89abdea8SMarcel Moolenaar 	ioc->u.md.phys_nsegs = 1;	/* XXX */
305*89abdea8SMarcel Moolenaar 	ioc->u.md.phys_addr = md->physaddr;
3065dcca8e8SMarcel Moolenaar 	return (0);
3075dcca8e8SMarcel Moolenaar }
3085dcca8e8SMarcel Moolenaar 
3095dcca8e8SMarcel Moolenaar static struct proto_md *
3105dcca8e8SMarcel Moolenaar proto_busdma_md_lookup(struct proto_busdma *busdma, u_long key)
3115dcca8e8SMarcel Moolenaar {
3125dcca8e8SMarcel Moolenaar 	struct proto_md *md;
3135dcca8e8SMarcel Moolenaar 
3145dcca8e8SMarcel Moolenaar 	LIST_FOREACH(md, &busdma->mds, mds) {
3155dcca8e8SMarcel Moolenaar 		if ((void *)md == (void *)key)
3165dcca8e8SMarcel Moolenaar 			return (md);
3175dcca8e8SMarcel Moolenaar 	}
3185dcca8e8SMarcel Moolenaar 	return (NULL);
3195dcca8e8SMarcel Moolenaar }
3205dcca8e8SMarcel Moolenaar 
3214f027abdSMarcel Moolenaar struct proto_busdma *
3224f027abdSMarcel Moolenaar proto_busdma_attach(struct proto_softc *sc)
3234f027abdSMarcel Moolenaar {
3244f027abdSMarcel Moolenaar 	struct proto_busdma *busdma;
3254f027abdSMarcel Moolenaar 
3264f027abdSMarcel Moolenaar 	busdma = malloc(sizeof(*busdma), M_PROTO_BUSDMA, M_WAITOK | M_ZERO);
3274f027abdSMarcel Moolenaar 	return (busdma);
3284f027abdSMarcel Moolenaar }
3294f027abdSMarcel Moolenaar 
3304f027abdSMarcel Moolenaar int
3314f027abdSMarcel Moolenaar proto_busdma_detach(struct proto_softc *sc, struct proto_busdma *busdma)
3324f027abdSMarcel Moolenaar {
3334f027abdSMarcel Moolenaar 
3344f027abdSMarcel Moolenaar 	proto_busdma_cleanup(sc, busdma);
3354f027abdSMarcel Moolenaar 	free(busdma, M_PROTO_BUSDMA);
3364f027abdSMarcel Moolenaar 	return (0);
3374f027abdSMarcel Moolenaar }
3384f027abdSMarcel Moolenaar 
3394f027abdSMarcel Moolenaar int
3404f027abdSMarcel Moolenaar proto_busdma_cleanup(struct proto_softc *sc, struct proto_busdma *busdma)
3414f027abdSMarcel Moolenaar {
3425dcca8e8SMarcel Moolenaar 	struct proto_md *md, *md1;
3434f027abdSMarcel Moolenaar 	struct proto_tag *tag, *tag1;
3444f027abdSMarcel Moolenaar 
3455dcca8e8SMarcel Moolenaar 	LIST_FOREACH_SAFE(md, &busdma->mds, mds, md1)
346*89abdea8SMarcel Moolenaar 		proto_busdma_md_destroy_internal(busdma, md);
3475dcca8e8SMarcel Moolenaar 	LIST_FOREACH_SAFE(tag, &busdma->tags, tags, tag1)
3485dcca8e8SMarcel Moolenaar 		proto_busdma_tag_destroy(busdma, tag);
3494f027abdSMarcel Moolenaar 	return (0);
3504f027abdSMarcel Moolenaar }
3514f027abdSMarcel Moolenaar 
3524f027abdSMarcel Moolenaar int
3534f027abdSMarcel Moolenaar proto_busdma_ioctl(struct proto_softc *sc, struct proto_busdma *busdma,
354*89abdea8SMarcel Moolenaar     struct proto_ioc_busdma *ioc, struct thread *td)
3554f027abdSMarcel Moolenaar {
3564f027abdSMarcel Moolenaar 	struct proto_tag *tag;
3575dcca8e8SMarcel Moolenaar 	struct proto_md *md;
3584f027abdSMarcel Moolenaar 	int error;
3594f027abdSMarcel Moolenaar 
3604f027abdSMarcel Moolenaar 	error = 0;
3614f027abdSMarcel Moolenaar 	switch (ioc->request) {
3624f027abdSMarcel Moolenaar 	case PROTO_IOC_BUSDMA_TAG_CREATE:
3635dcca8e8SMarcel Moolenaar 		busdma->bd_roottag = bus_get_dma_tag(sc->sc_dev);
3645dcca8e8SMarcel Moolenaar 		error = proto_busdma_tag_create(busdma, NULL, ioc);
3654f027abdSMarcel Moolenaar 		break;
3664f027abdSMarcel Moolenaar 	case PROTO_IOC_BUSDMA_TAG_DERIVE:
3674f027abdSMarcel Moolenaar 		tag = proto_busdma_tag_lookup(busdma, ioc->key);
3684f027abdSMarcel Moolenaar 		if (tag == NULL) {
3694f027abdSMarcel Moolenaar 			error = EINVAL;
3704f027abdSMarcel Moolenaar 			break;
3714f027abdSMarcel Moolenaar 		}
3725dcca8e8SMarcel Moolenaar 		error = proto_busdma_tag_create(busdma, tag, ioc);
3734f027abdSMarcel Moolenaar 		break;
3744f027abdSMarcel Moolenaar 	case PROTO_IOC_BUSDMA_TAG_DESTROY:
3754f027abdSMarcel Moolenaar 		tag = proto_busdma_tag_lookup(busdma, ioc->key);
3764f027abdSMarcel Moolenaar 		if (tag == NULL) {
3774f027abdSMarcel Moolenaar 			error = EINVAL;
3784f027abdSMarcel Moolenaar 			break;
3794f027abdSMarcel Moolenaar 		}
3805dcca8e8SMarcel Moolenaar 		error = proto_busdma_tag_destroy(busdma, tag);
3815dcca8e8SMarcel Moolenaar 		break;
3825dcca8e8SMarcel Moolenaar 	case PROTO_IOC_BUSDMA_MEM_ALLOC:
383*89abdea8SMarcel Moolenaar 		tag = proto_busdma_tag_lookup(busdma, ioc->u.md.tag);
3845dcca8e8SMarcel Moolenaar 		if (tag == NULL) {
3855dcca8e8SMarcel Moolenaar 			error = EINVAL;
3865dcca8e8SMarcel Moolenaar 			break;
3875dcca8e8SMarcel Moolenaar 		}
3885dcca8e8SMarcel Moolenaar 		error = proto_busdma_mem_alloc(busdma, tag, ioc);
3895dcca8e8SMarcel Moolenaar 		break;
3905dcca8e8SMarcel Moolenaar 	case PROTO_IOC_BUSDMA_MEM_FREE:
3915dcca8e8SMarcel Moolenaar 		md = proto_busdma_md_lookup(busdma, ioc->key);
3925dcca8e8SMarcel Moolenaar 		if (md == NULL) {
3935dcca8e8SMarcel Moolenaar 			error = EINVAL;
3945dcca8e8SMarcel Moolenaar 			break;
3955dcca8e8SMarcel Moolenaar 		}
3965dcca8e8SMarcel Moolenaar 		error = proto_busdma_mem_free(busdma, md);
3974f027abdSMarcel Moolenaar 		break;
398*89abdea8SMarcel Moolenaar 	case PROTO_IOC_BUSDMA_MD_CREATE:
399*89abdea8SMarcel Moolenaar 		tag = proto_busdma_tag_lookup(busdma, ioc->u.md.tag);
400*89abdea8SMarcel Moolenaar 		if (tag == NULL) {
401*89abdea8SMarcel Moolenaar 			error = EINVAL;
402*89abdea8SMarcel Moolenaar 			break;
403*89abdea8SMarcel Moolenaar 		}
404*89abdea8SMarcel Moolenaar 		error = proto_busdma_md_create(busdma, tag, ioc);
405*89abdea8SMarcel Moolenaar 		break;
406*89abdea8SMarcel Moolenaar 	case PROTO_IOC_BUSDMA_MD_DESTROY:
407*89abdea8SMarcel Moolenaar 		md = proto_busdma_md_lookup(busdma, ioc->key);
408*89abdea8SMarcel Moolenaar 		if (md == NULL) {
409*89abdea8SMarcel Moolenaar 			error = EINVAL;
410*89abdea8SMarcel Moolenaar 			break;
411*89abdea8SMarcel Moolenaar 		}
412*89abdea8SMarcel Moolenaar 		error = proto_busdma_md_destroy(busdma, md);
413*89abdea8SMarcel Moolenaar 		break;
414*89abdea8SMarcel Moolenaar 	case PROTO_IOC_BUSDMA_MD_LOAD:
415*89abdea8SMarcel Moolenaar 		md = proto_busdma_md_lookup(busdma, ioc->key);
416*89abdea8SMarcel Moolenaar 		if (md == NULL) {
417*89abdea8SMarcel Moolenaar 			error = EINVAL;
418*89abdea8SMarcel Moolenaar 			break;
419*89abdea8SMarcel Moolenaar 		}
420*89abdea8SMarcel Moolenaar 		error = proto_busdma_md_load(busdma, md, ioc, td);
421*89abdea8SMarcel Moolenaar 		break;
4224f027abdSMarcel Moolenaar 	default:
4234f027abdSMarcel Moolenaar 		error = EINVAL;
4244f027abdSMarcel Moolenaar 		break;
4254f027abdSMarcel Moolenaar 	}
4264f027abdSMarcel Moolenaar 	return (error);
4274f027abdSMarcel Moolenaar }
428cff0f135SMarcel Moolenaar 
429cff0f135SMarcel Moolenaar int
430cff0f135SMarcel Moolenaar proto_busdma_mmap_allowed(struct proto_busdma *busdma, vm_paddr_t physaddr)
431cff0f135SMarcel Moolenaar {
432cff0f135SMarcel Moolenaar 	struct proto_md *md;
433cff0f135SMarcel Moolenaar 
434cff0f135SMarcel Moolenaar 	LIST_FOREACH(md, &busdma->mds, mds) {
435cff0f135SMarcel Moolenaar 		if (physaddr >= trunc_page(md->physaddr) &&
436cff0f135SMarcel Moolenaar 		    physaddr <= trunc_page(md->physaddr + md->tag->maxsz))
437cff0f135SMarcel Moolenaar 			return (1);
438cff0f135SMarcel Moolenaar 	}
439cff0f135SMarcel Moolenaar 	return (0);
440cff0f135SMarcel Moolenaar }
441