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> 3989abdea8SMarcel Moolenaar #include <sys/proc.h> 404f027abdSMarcel Moolenaar #include <sys/queue.h> 414f027abdSMarcel Moolenaar #include <sys/rman.h> 424f027abdSMarcel Moolenaar #include <sys/sbuf.h> 4389abdea8SMarcel Moolenaar #include <sys/uio.h> 445dcca8e8SMarcel Moolenaar #include <vm/vm.h> 455dcca8e8SMarcel Moolenaar #include <vm/pmap.h> 4689abdea8SMarcel 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 54b2ce196cSMarcel Moolenaar #define BNDRY_MIN(a, b) \ 55b2ce196cSMarcel Moolenaar (((a) == 0) ? (b) : (((b) == 0) ? (a) : MIN((a), (b)))) 56b2ce196cSMarcel Moolenaar 5789abdea8SMarcel Moolenaar struct proto_callback_bundle { 5889abdea8SMarcel Moolenaar struct proto_busdma *busdma; 5989abdea8SMarcel Moolenaar struct proto_md *md; 6089abdea8SMarcel Moolenaar struct proto_ioc_busdma *ioc; 6189abdea8SMarcel Moolenaar }; 6289abdea8SMarcel Moolenaar 634f027abdSMarcel Moolenaar static int 645dcca8e8SMarcel Moolenaar proto_busdma_tag_create(struct proto_busdma *busdma, struct proto_tag *parent, 655dcca8e8SMarcel Moolenaar struct proto_ioc_busdma *ioc) 664f027abdSMarcel Moolenaar { 674f027abdSMarcel Moolenaar struct proto_tag *tag; 684f027abdSMarcel Moolenaar 69b2ce196cSMarcel Moolenaar /* Make sure that when a boundary is specified, it's a power of 2 */ 70b2ce196cSMarcel Moolenaar if (ioc->u.tag.bndry != 0 && 71b2ce196cSMarcel Moolenaar (ioc->u.tag.bndry & (ioc->u.tag.bndry - 1)) != 0) 72b2ce196cSMarcel Moolenaar return (EINVAL); 73b2ce196cSMarcel Moolenaar 745dcca8e8SMarcel Moolenaar /* 755dcca8e8SMarcel Moolenaar * If nsegs is 1, ignore maxsegsz. What this means is that if we have 765dcca8e8SMarcel Moolenaar * just 1 segment, then maxsz should be equal to maxsegsz. To keep it 775dcca8e8SMarcel Moolenaar * simple for us, limit maxsegsz to maxsz in any case. 785dcca8e8SMarcel Moolenaar */ 795dcca8e8SMarcel Moolenaar if (ioc->u.tag.maxsegsz > ioc->u.tag.maxsz || ioc->u.tag.nsegs == 1) 805dcca8e8SMarcel Moolenaar ioc->u.tag.maxsegsz = ioc->u.tag.maxsz; 815dcca8e8SMarcel Moolenaar 824f027abdSMarcel Moolenaar tag = malloc(sizeof(*tag), M_PROTO_BUSDMA, M_WAITOK | M_ZERO); 835dcca8e8SMarcel Moolenaar if (parent != NULL) { 845dcca8e8SMarcel Moolenaar tag->parent = parent; 855dcca8e8SMarcel Moolenaar LIST_INSERT_HEAD(&parent->children, tag, peers); 865dcca8e8SMarcel Moolenaar tag->align = MAX(ioc->u.tag.align, parent->align); 87b2ce196cSMarcel Moolenaar tag->bndry = BNDRY_MIN(ioc->u.tag.bndry, parent->bndry); 885dcca8e8SMarcel Moolenaar tag->maxaddr = MIN(ioc->u.tag.maxaddr, parent->maxaddr); 895dcca8e8SMarcel Moolenaar tag->maxsz = MIN(ioc->u.tag.maxsz, parent->maxsz); 905dcca8e8SMarcel Moolenaar tag->maxsegsz = MIN(ioc->u.tag.maxsegsz, parent->maxsegsz); 915dcca8e8SMarcel Moolenaar tag->nsegs = MIN(ioc->u.tag.nsegs, parent->nsegs); 925dcca8e8SMarcel Moolenaar tag->datarate = MIN(ioc->u.tag.datarate, parent->datarate); 935dcca8e8SMarcel Moolenaar /* Write constraints back */ 945dcca8e8SMarcel Moolenaar ioc->u.tag.align = tag->align; 955dcca8e8SMarcel Moolenaar ioc->u.tag.bndry = tag->bndry; 965dcca8e8SMarcel Moolenaar ioc->u.tag.maxaddr = tag->maxaddr; 975dcca8e8SMarcel Moolenaar ioc->u.tag.maxsz = tag->maxsz; 985dcca8e8SMarcel Moolenaar ioc->u.tag.maxsegsz = tag->maxsegsz; 995dcca8e8SMarcel Moolenaar ioc->u.tag.nsegs = tag->nsegs; 1005dcca8e8SMarcel Moolenaar ioc->u.tag.datarate = tag->datarate; 1015dcca8e8SMarcel Moolenaar } else { 1025dcca8e8SMarcel Moolenaar tag->align = ioc->u.tag.align; 1035dcca8e8SMarcel Moolenaar tag->bndry = ioc->u.tag.bndry; 1045dcca8e8SMarcel Moolenaar tag->maxaddr = ioc->u.tag.maxaddr; 1055dcca8e8SMarcel Moolenaar tag->maxsz = ioc->u.tag.maxsz; 1065dcca8e8SMarcel Moolenaar tag->maxsegsz = ioc->u.tag.maxsegsz; 1075dcca8e8SMarcel Moolenaar tag->nsegs = ioc->u.tag.nsegs; 1085dcca8e8SMarcel Moolenaar tag->datarate = ioc->u.tag.datarate; 1095dcca8e8SMarcel Moolenaar } 1105dcca8e8SMarcel Moolenaar LIST_INSERT_HEAD(&busdma->tags, tag, tags); 1115dcca8e8SMarcel Moolenaar ioc->result = (uintptr_t)(void *)tag; 1124f027abdSMarcel Moolenaar return (0); 1134f027abdSMarcel Moolenaar } 1144f027abdSMarcel Moolenaar 1155dcca8e8SMarcel Moolenaar static int 1165dcca8e8SMarcel Moolenaar proto_busdma_tag_destroy(struct proto_busdma *busdma, struct proto_tag *tag) 1174f027abdSMarcel Moolenaar { 1184f027abdSMarcel Moolenaar 1195dcca8e8SMarcel Moolenaar if (!LIST_EMPTY(&tag->mds)) 1205dcca8e8SMarcel Moolenaar return (EBUSY); 1215dcca8e8SMarcel Moolenaar if (!LIST_EMPTY(&tag->children)) 1225dcca8e8SMarcel Moolenaar return (EBUSY); 1235dcca8e8SMarcel Moolenaar 1245dcca8e8SMarcel Moolenaar if (tag->parent != NULL) { 1255dcca8e8SMarcel Moolenaar LIST_REMOVE(tag, peers); 1265dcca8e8SMarcel Moolenaar tag->parent = NULL; 1275dcca8e8SMarcel Moolenaar } 1285dcca8e8SMarcel Moolenaar LIST_REMOVE(tag, tags); 1294f027abdSMarcel Moolenaar free(tag, M_PROTO_BUSDMA); 1305dcca8e8SMarcel Moolenaar return (0); 1314f027abdSMarcel Moolenaar } 1324f027abdSMarcel Moolenaar 1334f027abdSMarcel Moolenaar static struct proto_tag * 1344f027abdSMarcel Moolenaar proto_busdma_tag_lookup(struct proto_busdma *busdma, u_long key) 1354f027abdSMarcel Moolenaar { 1364f027abdSMarcel Moolenaar struct proto_tag *tag; 1374f027abdSMarcel Moolenaar 1385dcca8e8SMarcel Moolenaar LIST_FOREACH(tag, &busdma->tags, tags) { 1394f027abdSMarcel Moolenaar if ((void *)tag == (void *)key) 1404f027abdSMarcel Moolenaar return (tag); 1414f027abdSMarcel Moolenaar } 1424f027abdSMarcel Moolenaar return (NULL); 1434f027abdSMarcel Moolenaar } 1444f027abdSMarcel Moolenaar 14589abdea8SMarcel Moolenaar static int 14689abdea8SMarcel Moolenaar proto_busdma_md_destroy_internal(struct proto_busdma *busdma, 14789abdea8SMarcel Moolenaar struct proto_md *md) 14889abdea8SMarcel Moolenaar { 14989abdea8SMarcel Moolenaar 15089abdea8SMarcel Moolenaar LIST_REMOVE(md, mds); 15189abdea8SMarcel Moolenaar LIST_REMOVE(md, peers); 15289abdea8SMarcel Moolenaar if (md->physaddr) 15389abdea8SMarcel Moolenaar bus_dmamap_unload(md->bd_tag, md->bd_map); 15489abdea8SMarcel Moolenaar if (md->virtaddr != NULL) 15589abdea8SMarcel Moolenaar bus_dmamem_free(md->bd_tag, md->virtaddr, md->bd_map); 15689abdea8SMarcel Moolenaar else 15789abdea8SMarcel Moolenaar bus_dmamap_destroy(md->bd_tag, md->bd_map); 15889abdea8SMarcel Moolenaar bus_dma_tag_destroy(md->bd_tag); 15989abdea8SMarcel Moolenaar free(md, M_PROTO_BUSDMA); 16089abdea8SMarcel Moolenaar return (0); 16189abdea8SMarcel Moolenaar } 16289abdea8SMarcel Moolenaar 16390a1793cSMarcel Moolenaar static void 16490a1793cSMarcel Moolenaar proto_busdma_mem_alloc_callback(void *arg, bus_dma_segment_t *segs, int nseg, 16590a1793cSMarcel Moolenaar int error) 16690a1793cSMarcel Moolenaar { 16789abdea8SMarcel Moolenaar struct proto_callback_bundle *pcb = arg; 16890a1793cSMarcel Moolenaar 16989abdea8SMarcel Moolenaar pcb->ioc->u.md.bus_nsegs = nseg; 17089abdea8SMarcel Moolenaar pcb->ioc->u.md.bus_addr = segs[0].ds_addr; 17190a1793cSMarcel Moolenaar } 17290a1793cSMarcel Moolenaar 1735dcca8e8SMarcel Moolenaar static int 1745dcca8e8SMarcel Moolenaar proto_busdma_mem_alloc(struct proto_busdma *busdma, struct proto_tag *tag, 1755dcca8e8SMarcel Moolenaar struct proto_ioc_busdma *ioc) 1765dcca8e8SMarcel Moolenaar { 17789abdea8SMarcel Moolenaar struct proto_callback_bundle pcb; 1785dcca8e8SMarcel Moolenaar struct proto_md *md; 1795dcca8e8SMarcel Moolenaar int error; 1805dcca8e8SMarcel Moolenaar 1815dcca8e8SMarcel Moolenaar md = malloc(sizeof(*md), M_PROTO_BUSDMA, M_WAITOK | M_ZERO); 1825dcca8e8SMarcel Moolenaar md->tag = tag; 1835dcca8e8SMarcel Moolenaar 1845dcca8e8SMarcel Moolenaar error = bus_dma_tag_create(busdma->bd_roottag, tag->align, tag->bndry, 1855dcca8e8SMarcel Moolenaar tag->maxaddr, BUS_SPACE_MAXADDR, NULL, NULL, tag->maxsz, 1865dcca8e8SMarcel Moolenaar tag->nsegs, tag->maxsegsz, 0, NULL, NULL, &md->bd_tag); 1875dcca8e8SMarcel Moolenaar if (error) { 1885dcca8e8SMarcel Moolenaar free(md, M_PROTO_BUSDMA); 1895dcca8e8SMarcel Moolenaar return (error); 1905dcca8e8SMarcel Moolenaar } 191cff0f135SMarcel Moolenaar error = bus_dmamem_alloc(md->bd_tag, &md->virtaddr, 0, &md->bd_map); 1925dcca8e8SMarcel Moolenaar if (error) { 1935dcca8e8SMarcel Moolenaar bus_dma_tag_destroy(md->bd_tag); 1945dcca8e8SMarcel Moolenaar free(md, M_PROTO_BUSDMA); 1955dcca8e8SMarcel Moolenaar return (error); 1965dcca8e8SMarcel Moolenaar } 197cff0f135SMarcel Moolenaar md->physaddr = pmap_kextract((uintptr_t)(md->virtaddr)); 19889abdea8SMarcel Moolenaar pcb.busdma = busdma; 19989abdea8SMarcel Moolenaar pcb.md = md; 20089abdea8SMarcel Moolenaar pcb.ioc = ioc; 20190a1793cSMarcel Moolenaar error = bus_dmamap_load(md->bd_tag, md->bd_map, md->virtaddr, 20289abdea8SMarcel Moolenaar tag->maxsz, proto_busdma_mem_alloc_callback, &pcb, BUS_DMA_NOWAIT); 20390a1793cSMarcel Moolenaar if (error) { 20490a1793cSMarcel Moolenaar bus_dmamem_free(md->bd_tag, md->virtaddr, md->bd_map); 20590a1793cSMarcel Moolenaar bus_dma_tag_destroy(md->bd_tag); 20690a1793cSMarcel Moolenaar free(md, M_PROTO_BUSDMA); 20790a1793cSMarcel Moolenaar return (error); 20890a1793cSMarcel Moolenaar } 2095dcca8e8SMarcel Moolenaar LIST_INSERT_HEAD(&tag->mds, md, peers); 2105dcca8e8SMarcel Moolenaar LIST_INSERT_HEAD(&busdma->mds, md, mds); 21189abdea8SMarcel Moolenaar ioc->u.md.virt_addr = (uintptr_t)md->virtaddr; 21289abdea8SMarcel Moolenaar ioc->u.md.virt_size = tag->maxsz; 21389abdea8SMarcel Moolenaar ioc->u.md.phys_nsegs = 1; 21489abdea8SMarcel Moolenaar ioc->u.md.phys_addr = md->physaddr; 2155dcca8e8SMarcel Moolenaar ioc->result = (uintptr_t)(void *)md; 2165dcca8e8SMarcel Moolenaar return (0); 2175dcca8e8SMarcel Moolenaar } 2185dcca8e8SMarcel Moolenaar 2195dcca8e8SMarcel Moolenaar static int 2205dcca8e8SMarcel Moolenaar proto_busdma_mem_free(struct proto_busdma *busdma, struct proto_md *md) 2215dcca8e8SMarcel Moolenaar { 2225dcca8e8SMarcel Moolenaar 22389abdea8SMarcel Moolenaar if (md->virtaddr == NULL) 22489abdea8SMarcel Moolenaar return (ENXIO); 22589abdea8SMarcel Moolenaar return (proto_busdma_md_destroy_internal(busdma, md)); 22689abdea8SMarcel Moolenaar } 22789abdea8SMarcel Moolenaar 22889abdea8SMarcel Moolenaar static int 22989abdea8SMarcel Moolenaar proto_busdma_md_create(struct proto_busdma *busdma, struct proto_tag *tag, 23089abdea8SMarcel Moolenaar struct proto_ioc_busdma *ioc) 23189abdea8SMarcel Moolenaar { 23289abdea8SMarcel Moolenaar struct proto_md *md; 23389abdea8SMarcel Moolenaar int error; 23489abdea8SMarcel Moolenaar 23589abdea8SMarcel Moolenaar md = malloc(sizeof(*md), M_PROTO_BUSDMA, M_WAITOK | M_ZERO); 23689abdea8SMarcel Moolenaar md->tag = tag; 23789abdea8SMarcel Moolenaar 23889abdea8SMarcel Moolenaar error = bus_dma_tag_create(busdma->bd_roottag, tag->align, tag->bndry, 23989abdea8SMarcel Moolenaar tag->maxaddr, BUS_SPACE_MAXADDR, NULL, NULL, tag->maxsz, 24089abdea8SMarcel Moolenaar tag->nsegs, tag->maxsegsz, 0, NULL, NULL, &md->bd_tag); 24189abdea8SMarcel Moolenaar if (error) { 24289abdea8SMarcel Moolenaar free(md, M_PROTO_BUSDMA); 24389abdea8SMarcel Moolenaar return (error); 24489abdea8SMarcel Moolenaar } 24589abdea8SMarcel Moolenaar error = bus_dmamap_create(md->bd_tag, 0, &md->bd_map); 24689abdea8SMarcel Moolenaar if (error) { 2475dcca8e8SMarcel Moolenaar bus_dma_tag_destroy(md->bd_tag); 2485dcca8e8SMarcel Moolenaar free(md, M_PROTO_BUSDMA); 24989abdea8SMarcel Moolenaar return (error); 25089abdea8SMarcel Moolenaar } 25189abdea8SMarcel Moolenaar 25289abdea8SMarcel Moolenaar LIST_INSERT_HEAD(&tag->mds, md, peers); 25389abdea8SMarcel Moolenaar LIST_INSERT_HEAD(&busdma->mds, md, mds); 25489abdea8SMarcel Moolenaar ioc->result = (uintptr_t)(void *)md; 25589abdea8SMarcel Moolenaar return (0); 25689abdea8SMarcel Moolenaar } 25789abdea8SMarcel Moolenaar 25889abdea8SMarcel Moolenaar static int 25989abdea8SMarcel Moolenaar proto_busdma_md_destroy(struct proto_busdma *busdma, struct proto_md *md) 26089abdea8SMarcel Moolenaar { 26189abdea8SMarcel Moolenaar 26289abdea8SMarcel Moolenaar if (md->virtaddr != NULL) 26389abdea8SMarcel Moolenaar return (ENXIO); 26489abdea8SMarcel Moolenaar return (proto_busdma_md_destroy_internal(busdma, md)); 26589abdea8SMarcel Moolenaar } 26689abdea8SMarcel Moolenaar 26789abdea8SMarcel Moolenaar static void 26889abdea8SMarcel Moolenaar proto_busdma_md_load_callback(void *arg, bus_dma_segment_t *segs, int nseg, 26989abdea8SMarcel Moolenaar bus_size_t sz, int error) 27089abdea8SMarcel Moolenaar { 27189abdea8SMarcel Moolenaar struct proto_callback_bundle *pcb = arg; 27289abdea8SMarcel Moolenaar 27389abdea8SMarcel Moolenaar pcb->ioc->u.md.bus_nsegs = nseg; 27489abdea8SMarcel Moolenaar pcb->ioc->u.md.bus_addr = segs[0].ds_addr; 27589abdea8SMarcel Moolenaar } 27689abdea8SMarcel Moolenaar 27789abdea8SMarcel Moolenaar static int 27889abdea8SMarcel Moolenaar proto_busdma_md_load(struct proto_busdma *busdma, struct proto_md *md, 27989abdea8SMarcel Moolenaar struct proto_ioc_busdma *ioc, struct thread *td) 28089abdea8SMarcel Moolenaar { 28189abdea8SMarcel Moolenaar struct proto_callback_bundle pcb; 28289abdea8SMarcel Moolenaar struct iovec iov; 28389abdea8SMarcel Moolenaar struct uio uio; 28489abdea8SMarcel Moolenaar pmap_t pmap; 28589abdea8SMarcel Moolenaar int error; 28689abdea8SMarcel Moolenaar 28789abdea8SMarcel Moolenaar iov.iov_base = (void *)(uintptr_t)ioc->u.md.virt_addr; 28889abdea8SMarcel Moolenaar iov.iov_len = ioc->u.md.virt_size; 28989abdea8SMarcel Moolenaar uio.uio_iov = &iov; 29089abdea8SMarcel Moolenaar uio.uio_iovcnt = 1; 29189abdea8SMarcel Moolenaar uio.uio_offset = 0; 29289abdea8SMarcel Moolenaar uio.uio_resid = iov.iov_len; 29389abdea8SMarcel Moolenaar uio.uio_segflg = UIO_USERSPACE; 29489abdea8SMarcel Moolenaar uio.uio_rw = UIO_READ; 29589abdea8SMarcel Moolenaar uio.uio_td = td; 29689abdea8SMarcel Moolenaar 29789abdea8SMarcel Moolenaar pcb.busdma = busdma; 29889abdea8SMarcel Moolenaar pcb.md = md; 29989abdea8SMarcel Moolenaar pcb.ioc = ioc; 30089abdea8SMarcel Moolenaar error = bus_dmamap_load_uio(md->bd_tag, md->bd_map, &uio, 30189abdea8SMarcel Moolenaar proto_busdma_md_load_callback, &pcb, BUS_DMA_NOWAIT); 30289abdea8SMarcel Moolenaar if (error) 30389abdea8SMarcel Moolenaar return (error); 30489abdea8SMarcel Moolenaar 30589abdea8SMarcel Moolenaar /* XXX determine *all* physical memory segments */ 30689abdea8SMarcel Moolenaar pmap = vmspace_pmap(td->td_proc->p_vmspace); 30789abdea8SMarcel Moolenaar md->physaddr = pmap_extract(pmap, ioc->u.md.virt_addr); 30889abdea8SMarcel Moolenaar ioc->u.md.phys_nsegs = 1; /* XXX */ 30989abdea8SMarcel Moolenaar ioc->u.md.phys_addr = md->physaddr; 3105dcca8e8SMarcel Moolenaar return (0); 3115dcca8e8SMarcel Moolenaar } 3125dcca8e8SMarcel Moolenaar 31342d3ab5dSMarcel Moolenaar static int 31442d3ab5dSMarcel Moolenaar proto_busdma_md_unload(struct proto_busdma *busdma, struct proto_md *md) 31542d3ab5dSMarcel Moolenaar { 31642d3ab5dSMarcel Moolenaar 31742d3ab5dSMarcel Moolenaar if (!md->physaddr) 31842d3ab5dSMarcel Moolenaar return (ENXIO); 31942d3ab5dSMarcel Moolenaar bus_dmamap_unload(md->bd_tag, md->bd_map); 32042d3ab5dSMarcel Moolenaar md->physaddr = 0; 32142d3ab5dSMarcel Moolenaar return (0); 32242d3ab5dSMarcel Moolenaar } 32342d3ab5dSMarcel Moolenaar 32442d3ab5dSMarcel Moolenaar static int 32542d3ab5dSMarcel Moolenaar proto_busdma_sync(struct proto_busdma *busdma, struct proto_md *md, 32642d3ab5dSMarcel Moolenaar struct proto_ioc_busdma *ioc) 32742d3ab5dSMarcel Moolenaar { 328*f40c76d8SMarcel Moolenaar u_int ops; 32942d3ab5dSMarcel Moolenaar 330*f40c76d8SMarcel Moolenaar ops = BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE | 331*f40c76d8SMarcel Moolenaar BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE; 332*f40c76d8SMarcel Moolenaar if (ioc->u.sync.op & ~ops) 333*f40c76d8SMarcel Moolenaar return (EINVAL); 33442d3ab5dSMarcel Moolenaar if (!md->physaddr) 33542d3ab5dSMarcel Moolenaar return (ENXIO); 33642d3ab5dSMarcel Moolenaar bus_dmamap_sync(md->bd_tag, md->bd_map, ioc->u.sync.op); 33742d3ab5dSMarcel Moolenaar return (0); 33842d3ab5dSMarcel Moolenaar } 33942d3ab5dSMarcel Moolenaar 3405dcca8e8SMarcel Moolenaar static struct proto_md * 3415dcca8e8SMarcel Moolenaar proto_busdma_md_lookup(struct proto_busdma *busdma, u_long key) 3425dcca8e8SMarcel Moolenaar { 3435dcca8e8SMarcel Moolenaar struct proto_md *md; 3445dcca8e8SMarcel Moolenaar 3455dcca8e8SMarcel Moolenaar LIST_FOREACH(md, &busdma->mds, mds) { 3465dcca8e8SMarcel Moolenaar if ((void *)md == (void *)key) 3475dcca8e8SMarcel Moolenaar return (md); 3485dcca8e8SMarcel Moolenaar } 3495dcca8e8SMarcel Moolenaar return (NULL); 3505dcca8e8SMarcel Moolenaar } 3515dcca8e8SMarcel Moolenaar 3524f027abdSMarcel Moolenaar struct proto_busdma * 3534f027abdSMarcel Moolenaar proto_busdma_attach(struct proto_softc *sc) 3544f027abdSMarcel Moolenaar { 3554f027abdSMarcel Moolenaar struct proto_busdma *busdma; 3564f027abdSMarcel Moolenaar 3574f027abdSMarcel Moolenaar busdma = malloc(sizeof(*busdma), M_PROTO_BUSDMA, M_WAITOK | M_ZERO); 3584f027abdSMarcel Moolenaar return (busdma); 3594f027abdSMarcel Moolenaar } 3604f027abdSMarcel Moolenaar 3614f027abdSMarcel Moolenaar int 3624f027abdSMarcel Moolenaar proto_busdma_detach(struct proto_softc *sc, struct proto_busdma *busdma) 3634f027abdSMarcel Moolenaar { 3644f027abdSMarcel Moolenaar 3654f027abdSMarcel Moolenaar proto_busdma_cleanup(sc, busdma); 3664f027abdSMarcel Moolenaar free(busdma, M_PROTO_BUSDMA); 3674f027abdSMarcel Moolenaar return (0); 3684f027abdSMarcel Moolenaar } 3694f027abdSMarcel Moolenaar 3704f027abdSMarcel Moolenaar int 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 3765dcca8e8SMarcel Moolenaar LIST_FOREACH_SAFE(md, &busdma->mds, mds, md1) 37789abdea8SMarcel Moolenaar proto_busdma_md_destroy_internal(busdma, md); 3785dcca8e8SMarcel Moolenaar LIST_FOREACH_SAFE(tag, &busdma->tags, tags, tag1) 3795dcca8e8SMarcel Moolenaar proto_busdma_tag_destroy(busdma, tag); 3804f027abdSMarcel Moolenaar return (0); 3814f027abdSMarcel Moolenaar } 3824f027abdSMarcel Moolenaar 3834f027abdSMarcel Moolenaar int 3844f027abdSMarcel Moolenaar proto_busdma_ioctl(struct proto_softc *sc, struct proto_busdma *busdma, 38589abdea8SMarcel Moolenaar struct proto_ioc_busdma *ioc, struct thread *td) 3864f027abdSMarcel Moolenaar { 3874f027abdSMarcel Moolenaar struct proto_tag *tag; 3885dcca8e8SMarcel Moolenaar struct proto_md *md; 3894f027abdSMarcel Moolenaar int error; 3904f027abdSMarcel Moolenaar 3914f027abdSMarcel Moolenaar error = 0; 3924f027abdSMarcel Moolenaar switch (ioc->request) { 3934f027abdSMarcel Moolenaar case PROTO_IOC_BUSDMA_TAG_CREATE: 3945dcca8e8SMarcel Moolenaar busdma->bd_roottag = bus_get_dma_tag(sc->sc_dev); 3955dcca8e8SMarcel Moolenaar error = proto_busdma_tag_create(busdma, NULL, ioc); 3964f027abdSMarcel Moolenaar break; 3974f027abdSMarcel Moolenaar case PROTO_IOC_BUSDMA_TAG_DERIVE: 3984f027abdSMarcel Moolenaar tag = proto_busdma_tag_lookup(busdma, ioc->key); 3994f027abdSMarcel Moolenaar if (tag == NULL) { 4004f027abdSMarcel Moolenaar error = EINVAL; 4014f027abdSMarcel Moolenaar break; 4024f027abdSMarcel Moolenaar } 4035dcca8e8SMarcel Moolenaar error = proto_busdma_tag_create(busdma, tag, ioc); 4044f027abdSMarcel Moolenaar break; 4054f027abdSMarcel Moolenaar case PROTO_IOC_BUSDMA_TAG_DESTROY: 4064f027abdSMarcel Moolenaar tag = proto_busdma_tag_lookup(busdma, ioc->key); 4074f027abdSMarcel Moolenaar if (tag == NULL) { 4084f027abdSMarcel Moolenaar error = EINVAL; 4094f027abdSMarcel Moolenaar break; 4104f027abdSMarcel Moolenaar } 4115dcca8e8SMarcel Moolenaar error = proto_busdma_tag_destroy(busdma, tag); 4125dcca8e8SMarcel Moolenaar break; 4135dcca8e8SMarcel Moolenaar case PROTO_IOC_BUSDMA_MEM_ALLOC: 41489abdea8SMarcel Moolenaar tag = proto_busdma_tag_lookup(busdma, ioc->u.md.tag); 4155dcca8e8SMarcel Moolenaar if (tag == NULL) { 4165dcca8e8SMarcel Moolenaar error = EINVAL; 4175dcca8e8SMarcel Moolenaar break; 4185dcca8e8SMarcel Moolenaar } 4195dcca8e8SMarcel Moolenaar error = proto_busdma_mem_alloc(busdma, tag, ioc); 4205dcca8e8SMarcel Moolenaar break; 4215dcca8e8SMarcel Moolenaar case PROTO_IOC_BUSDMA_MEM_FREE: 4225dcca8e8SMarcel Moolenaar md = proto_busdma_md_lookup(busdma, ioc->key); 4235dcca8e8SMarcel Moolenaar if (md == NULL) { 4245dcca8e8SMarcel Moolenaar error = EINVAL; 4255dcca8e8SMarcel Moolenaar break; 4265dcca8e8SMarcel Moolenaar } 4275dcca8e8SMarcel Moolenaar error = proto_busdma_mem_free(busdma, md); 4284f027abdSMarcel Moolenaar break; 42989abdea8SMarcel Moolenaar case PROTO_IOC_BUSDMA_MD_CREATE: 43089abdea8SMarcel Moolenaar tag = proto_busdma_tag_lookup(busdma, ioc->u.md.tag); 43189abdea8SMarcel Moolenaar if (tag == NULL) { 43289abdea8SMarcel Moolenaar error = EINVAL; 43389abdea8SMarcel Moolenaar break; 43489abdea8SMarcel Moolenaar } 43589abdea8SMarcel Moolenaar error = proto_busdma_md_create(busdma, tag, ioc); 43689abdea8SMarcel Moolenaar break; 43789abdea8SMarcel Moolenaar case PROTO_IOC_BUSDMA_MD_DESTROY: 43889abdea8SMarcel Moolenaar md = proto_busdma_md_lookup(busdma, ioc->key); 43989abdea8SMarcel Moolenaar if (md == NULL) { 44089abdea8SMarcel Moolenaar error = EINVAL; 44189abdea8SMarcel Moolenaar break; 44289abdea8SMarcel Moolenaar } 44389abdea8SMarcel Moolenaar error = proto_busdma_md_destroy(busdma, md); 44489abdea8SMarcel Moolenaar break; 44589abdea8SMarcel Moolenaar case PROTO_IOC_BUSDMA_MD_LOAD: 44689abdea8SMarcel Moolenaar md = proto_busdma_md_lookup(busdma, ioc->key); 44789abdea8SMarcel Moolenaar if (md == NULL) { 44889abdea8SMarcel Moolenaar error = EINVAL; 44989abdea8SMarcel Moolenaar break; 45089abdea8SMarcel Moolenaar } 45189abdea8SMarcel Moolenaar error = proto_busdma_md_load(busdma, md, ioc, td); 45289abdea8SMarcel Moolenaar break; 45342d3ab5dSMarcel Moolenaar case PROTO_IOC_BUSDMA_MD_UNLOAD: 45442d3ab5dSMarcel Moolenaar md = proto_busdma_md_lookup(busdma, ioc->key); 45542d3ab5dSMarcel Moolenaar if (md == NULL) { 45642d3ab5dSMarcel Moolenaar error = EINVAL; 45742d3ab5dSMarcel Moolenaar break; 45842d3ab5dSMarcel Moolenaar } 45942d3ab5dSMarcel Moolenaar error = proto_busdma_md_unload(busdma, md); 46042d3ab5dSMarcel Moolenaar break; 46142d3ab5dSMarcel Moolenaar case PROTO_IOC_BUSDMA_SYNC: 46242d3ab5dSMarcel Moolenaar md = proto_busdma_md_lookup(busdma, ioc->key); 46342d3ab5dSMarcel Moolenaar if (md == NULL) { 46442d3ab5dSMarcel Moolenaar error = EINVAL; 46542d3ab5dSMarcel Moolenaar break; 46642d3ab5dSMarcel Moolenaar } 46742d3ab5dSMarcel Moolenaar error = proto_busdma_sync(busdma, md, ioc); 46842d3ab5dSMarcel Moolenaar break; 4694f027abdSMarcel Moolenaar default: 4704f027abdSMarcel Moolenaar error = EINVAL; 4714f027abdSMarcel Moolenaar break; 4724f027abdSMarcel Moolenaar } 4734f027abdSMarcel Moolenaar return (error); 4744f027abdSMarcel Moolenaar } 475cff0f135SMarcel Moolenaar 476cff0f135SMarcel Moolenaar int 477cff0f135SMarcel Moolenaar proto_busdma_mmap_allowed(struct proto_busdma *busdma, vm_paddr_t physaddr) 478cff0f135SMarcel Moolenaar { 479cff0f135SMarcel Moolenaar struct proto_md *md; 480cff0f135SMarcel Moolenaar 481cff0f135SMarcel Moolenaar LIST_FOREACH(md, &busdma->mds, mds) { 482cff0f135SMarcel Moolenaar if (physaddr >= trunc_page(md->physaddr) && 483cff0f135SMarcel Moolenaar physaddr <= trunc_page(md->physaddr + md->tag->maxsz)) 484cff0f135SMarcel Moolenaar return (1); 485cff0f135SMarcel Moolenaar } 486cff0f135SMarcel Moolenaar return (0); 487cff0f135SMarcel Moolenaar } 488