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