Date: Fri, 3 Jul 2015 01:52:23 +0000 (UTC) From: Marcel Moolenaar <marcel@FreeBSD.org> To: src-committers@freebsd.org, svn-src-all@freebsd.org, svn-src-head@freebsd.org Subject: svn commit: r285069 - head/sys/dev/proto Message-ID: <201507030152.t631qN6R042553@repo.freebsd.org>
next in thread | raw e-mail | index | archive | help
Author: marcel Date: Fri Jul 3 01:52:22 2015 New Revision: 285069 URL: https://svnweb.freebsd.org/changeset/base/285069 Log: Add create, destroy and load of memory descriptors. Modified: head/sys/dev/proto/proto_busdma.c head/sys/dev/proto/proto_busdma.h head/sys/dev/proto/proto_core.c head/sys/dev/proto/proto_dev.h Modified: head/sys/dev/proto/proto_busdma.c ============================================================================== --- head/sys/dev/proto/proto_busdma.c Fri Jul 3 01:50:26 2015 (r285068) +++ head/sys/dev/proto/proto_busdma.c Fri Jul 3 01:52:22 2015 (r285069) @@ -36,11 +36,14 @@ __FBSDID("$FreeBSD$"); #include <sys/kernel.h> #include <sys/malloc.h> #include <sys/module.h> +#include <sys/proc.h> #include <sys/queue.h> #include <sys/rman.h> #include <sys/sbuf.h> +#include <sys/uio.h> #include <vm/vm.h> #include <vm/pmap.h> +#include <vm/vm_map.h> #include <dev/proto/proto.h> #include <dev/proto/proto_dev.h> @@ -48,6 +51,12 @@ __FBSDID("$FreeBSD$"); MALLOC_DEFINE(M_PROTO_BUSDMA, "proto_busdma", "DMA management data"); +struct proto_callback_bundle { + struct proto_busdma *busdma; + struct proto_md *md; + struct proto_ioc_busdma *ioc; +}; + static int proto_busdma_tag_create(struct proto_busdma *busdma, struct proto_tag *parent, struct proto_ioc_busdma *ioc) @@ -129,26 +138,45 @@ proto_busdma_tag_lookup(struct proto_bus return (NULL); } +static int +proto_busdma_md_destroy_internal(struct proto_busdma *busdma, + struct proto_md *md) +{ + + LIST_REMOVE(md, mds); + LIST_REMOVE(md, peers); + if (md->physaddr) + bus_dmamap_unload(md->bd_tag, md->bd_map); + if (md->virtaddr != NULL) + bus_dmamem_free(md->bd_tag, md->virtaddr, md->bd_map); + else + bus_dmamap_destroy(md->bd_tag, md->bd_map); + bus_dma_tag_destroy(md->bd_tag); + free(md, M_PROTO_BUSDMA); + return (0); +} + static void proto_busdma_mem_alloc_callback(void *arg, bus_dma_segment_t *segs, int nseg, int error) { - struct proto_ioc_busdma *ioc = arg; + struct proto_callback_bundle *pcb = arg; - ioc->u.mem.bus_nsegs = nseg; - ioc->u.mem.bus_addr = segs[0].ds_addr; + pcb->ioc->u.md.bus_nsegs = nseg; + pcb->ioc->u.md.bus_addr = segs[0].ds_addr; } static int proto_busdma_mem_alloc(struct proto_busdma *busdma, struct proto_tag *tag, struct proto_ioc_busdma *ioc) { + struct proto_callback_bundle pcb; struct proto_md *md; int error; md = malloc(sizeof(*md), M_PROTO_BUSDMA, M_WAITOK | M_ZERO); md->tag = tag; - + error = bus_dma_tag_create(busdma->bd_roottag, tag->align, tag->bndry, tag->maxaddr, BUS_SPACE_MAXADDR, NULL, NULL, tag->maxsz, tag->nsegs, tag->maxsegsz, 0, NULL, NULL, &md->bd_tag); @@ -163,8 +191,11 @@ proto_busdma_mem_alloc(struct proto_busd return (error); } md->physaddr = pmap_kextract((uintptr_t)(md->virtaddr)); + pcb.busdma = busdma; + pcb.md = md; + pcb.ioc = ioc; error = bus_dmamap_load(md->bd_tag, md->bd_map, md->virtaddr, - tag->maxsz, proto_busdma_mem_alloc_callback, ioc, BUS_DMA_NOWAIT); + tag->maxsz, proto_busdma_mem_alloc_callback, &pcb, BUS_DMA_NOWAIT); if (error) { bus_dmamem_free(md->bd_tag, md->virtaddr, md->bd_map); bus_dma_tag_destroy(md->bd_tag); @@ -173,8 +204,10 @@ proto_busdma_mem_alloc(struct proto_busd } LIST_INSERT_HEAD(&tag->mds, md, peers); LIST_INSERT_HEAD(&busdma->mds, md, mds); - ioc->u.mem.phys_nsegs = 1; - ioc->u.mem.phys_addr = md->physaddr; + ioc->u.md.virt_addr = (uintptr_t)md->virtaddr; + ioc->u.md.virt_size = tag->maxsz; + ioc->u.md.phys_nsegs = 1; + ioc->u.md.phys_addr = md->physaddr; ioc->result = (uintptr_t)(void *)md; return (0); } @@ -183,11 +216,93 @@ static int proto_busdma_mem_free(struct proto_busdma *busdma, struct proto_md *md) { - LIST_REMOVE(md, mds); - LIST_REMOVE(md, peers); - bus_dmamem_free(md->bd_tag, md->virtaddr, md->bd_map); - bus_dma_tag_destroy(md->bd_tag); - free(md, M_PROTO_BUSDMA); + if (md->virtaddr == NULL) + return (ENXIO); + return (proto_busdma_md_destroy_internal(busdma, md)); +} + +static int +proto_busdma_md_create(struct proto_busdma *busdma, struct proto_tag *tag, + struct proto_ioc_busdma *ioc) +{ + struct proto_md *md; + int error; + + md = malloc(sizeof(*md), M_PROTO_BUSDMA, M_WAITOK | M_ZERO); + md->tag = tag; + + error = bus_dma_tag_create(busdma->bd_roottag, tag->align, tag->bndry, + tag->maxaddr, BUS_SPACE_MAXADDR, NULL, NULL, tag->maxsz, + tag->nsegs, tag->maxsegsz, 0, NULL, NULL, &md->bd_tag); + if (error) { + free(md, M_PROTO_BUSDMA); + return (error); + } + error = bus_dmamap_create(md->bd_tag, 0, &md->bd_map); + if (error) { + bus_dma_tag_destroy(md->bd_tag); + free(md, M_PROTO_BUSDMA); + return (error); + } + + LIST_INSERT_HEAD(&tag->mds, md, peers); + LIST_INSERT_HEAD(&busdma->mds, md, mds); + ioc->result = (uintptr_t)(void *)md; + return (0); +} + +static int +proto_busdma_md_destroy(struct proto_busdma *busdma, struct proto_md *md) +{ + + if (md->virtaddr != NULL) + return (ENXIO); + return (proto_busdma_md_destroy_internal(busdma, md)); +} + +static void +proto_busdma_md_load_callback(void *arg, bus_dma_segment_t *segs, int nseg, + bus_size_t sz, int error) +{ + struct proto_callback_bundle *pcb = arg; + + pcb->ioc->u.md.bus_nsegs = nseg; + pcb->ioc->u.md.bus_addr = segs[0].ds_addr; +} + +static int +proto_busdma_md_load(struct proto_busdma *busdma, struct proto_md *md, + struct proto_ioc_busdma *ioc, struct thread *td) +{ + struct proto_callback_bundle pcb; + struct iovec iov; + struct uio uio; + pmap_t pmap; + int error; + + iov.iov_base = (void *)(uintptr_t)ioc->u.md.virt_addr; + iov.iov_len = ioc->u.md.virt_size; + uio.uio_iov = &iov; + uio.uio_iovcnt = 1; + uio.uio_offset = 0; + uio.uio_resid = iov.iov_len; + uio.uio_segflg = UIO_USERSPACE; + uio.uio_rw = UIO_READ; + uio.uio_td = td; + + pcb.busdma = busdma; + pcb.md = md; + pcb.ioc = ioc; + error = bus_dmamap_load_uio(md->bd_tag, md->bd_map, &uio, + proto_busdma_md_load_callback, &pcb, BUS_DMA_NOWAIT); + if (error) + return (error); + + /* XXX determine *all* physical memory segments */ + pmap = vmspace_pmap(td->td_proc->p_vmspace); + md->physaddr = pmap_extract(pmap, ioc->u.md.virt_addr); + ioc->u.md.phys_nsegs = 1; /* XXX */ + ioc->u.md.phys_addr = md->physaddr; return (0); } @@ -228,7 +343,7 @@ proto_busdma_cleanup(struct proto_softc struct proto_tag *tag, *tag1; LIST_FOREACH_SAFE(md, &busdma->mds, mds, md1) - proto_busdma_mem_free(busdma, md); + proto_busdma_md_destroy_internal(busdma, md); LIST_FOREACH_SAFE(tag, &busdma->tags, tags, tag1) proto_busdma_tag_destroy(busdma, tag); return (0); @@ -236,7 +351,7 @@ proto_busdma_cleanup(struct proto_softc int proto_busdma_ioctl(struct proto_softc *sc, struct proto_busdma *busdma, - struct proto_ioc_busdma *ioc) + struct proto_ioc_busdma *ioc, struct thread *td) { struct proto_tag *tag; struct proto_md *md; @@ -265,7 +380,7 @@ proto_busdma_ioctl(struct proto_softc *s error = proto_busdma_tag_destroy(busdma, tag); break; case PROTO_IOC_BUSDMA_MEM_ALLOC: - tag = proto_busdma_tag_lookup(busdma, ioc->u.mem.tag); + tag = proto_busdma_tag_lookup(busdma, ioc->u.md.tag); if (tag == NULL) { error = EINVAL; break; @@ -280,6 +395,30 @@ proto_busdma_ioctl(struct proto_softc *s } error = proto_busdma_mem_free(busdma, md); break; + case PROTO_IOC_BUSDMA_MD_CREATE: + tag = proto_busdma_tag_lookup(busdma, ioc->u.md.tag); + if (tag == NULL) { + error = EINVAL; + break; + } + error = proto_busdma_md_create(busdma, tag, ioc); + break; + case PROTO_IOC_BUSDMA_MD_DESTROY: + md = proto_busdma_md_lookup(busdma, ioc->key); + if (md == NULL) { + error = EINVAL; + break; + } + error = proto_busdma_md_destroy(busdma, md); + break; + case PROTO_IOC_BUSDMA_MD_LOAD: + md = proto_busdma_md_lookup(busdma, ioc->key); + if (md == NULL) { + error = EINVAL; + break; + } + error = proto_busdma_md_load(busdma, md, ioc, td); + break; default: error = EINVAL; break; Modified: head/sys/dev/proto/proto_busdma.h ============================================================================== --- head/sys/dev/proto/proto_busdma.h Fri Jul 3 01:50:26 2015 (r285068) +++ head/sys/dev/proto/proto_busdma.h Fri Jul 3 01:52:22 2015 (r285069) @@ -68,7 +68,7 @@ int proto_busdma_detach(struct proto_sof int proto_busdma_cleanup(struct proto_softc *, struct proto_busdma *); int proto_busdma_ioctl(struct proto_softc *, struct proto_busdma *, - struct proto_ioc_busdma *); + struct proto_ioc_busdma *, struct thread *); int proto_busdma_mmap_allowed(struct proto_busdma *, vm_paddr_t); Modified: head/sys/dev/proto/proto_core.c ============================================================================== --- head/sys/dev/proto/proto_core.c Fri Jul 3 01:50:26 2015 (r285068) +++ head/sys/dev/proto/proto_core.c Fri Jul 3 01:52:22 2015 (r285069) @@ -396,7 +396,7 @@ proto_ioctl(struct cdev *cdev, u_long cm break; } busdma = (struct proto_ioc_busdma *)data; - error = proto_busdma_ioctl(sc, r->r_d.busdma, busdma); + error = proto_busdma_ioctl(sc, r->r_d.busdma, busdma, td); break; default: error = ENOIOCTL; Modified: head/sys/dev/proto/proto_dev.h ============================================================================== --- head/sys/dev/proto/proto_dev.h Fri Jul 3 01:50:26 2015 (r285068) +++ head/sys/dev/proto/proto_dev.h Fri Jul 3 01:52:22 2015 (r285069) @@ -47,6 +47,9 @@ struct proto_ioc_busdma { #define PROTO_IOC_BUSDMA_TAG_DESTROY 3 #define PROTO_IOC_BUSDMA_MEM_ALLOC 10 #define PROTO_IOC_BUSDMA_MEM_FREE 11 +#define PROTO_IOC_BUSDMA_MD_CREATE 20 +#define PROTO_IOC_BUSDMA_MD_DESTROY 21 +#define PROTO_IOC_BUSDMA_MD_LOAD 22 unsigned long key; union { struct { @@ -62,11 +65,13 @@ struct proto_ioc_busdma { struct { unsigned long tag; unsigned int flags; + unsigned long virt_addr; + unsigned long virt_size; unsigned int phys_nsegs; unsigned long phys_addr; unsigned long bus_addr; unsigned int bus_nsegs; - } mem; + } md; } u; unsigned long result; };
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?201507030152.t631qN6R042553>