Module Name: src Committed By: jmcneill Date: Tue Dec 26 14:53:12 UTC 2017
Modified Files: src/sys/external/bsd/drm2/dist/include/drm: drm_gem_cma_helper.h src/sys/external/bsd/drm2/drm: files.drmkms Added Files: src/sys/external/bsd/drm2/drm: drm_gem_cma_helper.c Log Message: Implement the DRM GEM/CMA helpers. The implementation has been extracted from our tegra DRM driver, but generalized for use with other drivers. To generate a diff of this commit: cvs rdiff -u -r1.1.1.1 -r1.2 \ src/sys/external/bsd/drm2/dist/include/drm/drm_gem_cma_helper.h cvs rdiff -u -r0 -r1.1 src/sys/external/bsd/drm2/drm/drm_gem_cma_helper.c cvs rdiff -u -r1.13 -r1.14 src/sys/external/bsd/drm2/drm/files.drmkms Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/external/bsd/drm2/dist/include/drm/drm_gem_cma_helper.h diff -u src/sys/external/bsd/drm2/dist/include/drm/drm_gem_cma_helper.h:1.1.1.1 src/sys/external/bsd/drm2/dist/include/drm/drm_gem_cma_helper.h:1.2 --- src/sys/external/bsd/drm2/dist/include/drm/drm_gem_cma_helper.h:1.1.1.1 Wed Jul 16 19:35:30 2014 +++ src/sys/external/bsd/drm2/dist/include/drm/drm_gem_cma_helper.h Tue Dec 26 14:53:12 2017 @@ -5,8 +5,15 @@ struct drm_gem_cma_object { struct drm_gem_object base; +#ifdef __NetBSD__ + bus_dma_tag_t dmat; + bus_dma_segment_t dmasegs[1]; + bus_size_t dmasize; + bus_dmamap_t dmamap; +#else dma_addr_t paddr; struct sg_table *sgt; +#endif /* For objects with DMA memory allocated by GEM CMA */ void *vaddr; @@ -36,7 +43,11 @@ int drm_gem_cma_mmap(struct file *filp, struct drm_gem_cma_object *drm_gem_cma_create(struct drm_device *drm, unsigned int size); +#ifdef __NetBSD__ +extern const struct uvm_pagerops drm_gem_cma_uvm_ops; +#else extern const struct vm_operations_struct drm_gem_cma_vm_ops; +#endif #ifdef CONFIG_DEBUG_FS void drm_gem_cma_describe(struct drm_gem_cma_object *obj, struct seq_file *m); Index: src/sys/external/bsd/drm2/drm/files.drmkms diff -u src/sys/external/bsd/drm2/drm/files.drmkms:1.13 src/sys/external/bsd/drm2/drm/files.drmkms:1.14 --- src/sys/external/bsd/drm2/drm/files.drmkms:1.13 Wed Feb 24 22:04:15 2016 +++ src/sys/external/bsd/drm2/drm/files.drmkms Tue Dec 26 14:53:12 2017 @@ -1,4 +1,4 @@ -# $NetBSD: files.drmkms,v 1.13 2016/02/24 22:04:15 skrll Exp $ +# $NetBSD: files.drmkms,v 1.14 2017/12/26 14:53:12 jmcneill Exp $ include "external/bsd/drm2/linux/files.drmkms_linux" @@ -68,6 +68,7 @@ file external/bsd/drm2/drm/drm_vm.c dr file external/bsd/drm2/drm/drm_vma_manager.c drmkms file external/bsd/drm2/drm/drm_gem_vm.c drmkms +file external/bsd/drm2/drm/drm_gem_cma_helper.c drmkms file external/bsd/drm2/drm/drm_module.c drmkms file external/bsd/drm2/drm/drm_sysctl.c drmkms @@ -75,4 +76,4 @@ file external/bsd/drm2/drm/drm_sysctl.c define drmfb: genfb file external/bsd/drm2/drm/drmfb.c drmfb -include "external/bsd/drm2/ttm/files.ttm" +include "external/bsd/drm2/ttm/files.ttm" Added files: Index: src/sys/external/bsd/drm2/drm/drm_gem_cma_helper.c diff -u /dev/null src/sys/external/bsd/drm2/drm/drm_gem_cma_helper.c:1.1 --- /dev/null Tue Dec 26 14:53:12 2017 +++ src/sys/external/bsd/drm2/drm/drm_gem_cma_helper.c Tue Dec 26 14:53:12 2017 @@ -0,0 +1,221 @@ +/* $NetBSD: drm_gem_cma_helper.c,v 1.1 2017/12/26 14:53:12 jmcneill Exp $ */ + +/*- + * Copyright (c) 2015-2017 Jared McNeill <jmcne...@invisible.ca> + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR + * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES + * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. + * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, + * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, + * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; + * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED + * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +__KERNEL_RCSID(0, "$NetBSD: drm_gem_cma_helper.c,v 1.1 2017/12/26 14:53:12 jmcneill Exp $"); + +#include <drm/drmP.h> +#include <drm/drm_gem_cma_helper.h> + +#include <uvm/uvm.h> + +struct drm_gem_cma_object * +drm_gem_cma_create(struct drm_device *ddev, unsigned int size) +{ + struct drm_gem_cma_object *obj; + int error, nsegs; + + obj = kmem_zalloc(sizeof(*obj), KM_SLEEP); + obj->dmat = ddev->bus_dmat; + obj->dmasize = size; + + error = bus_dmamem_alloc(obj->dmat, obj->dmasize, PAGE_SIZE, 0, + obj->dmasegs, 1, &nsegs, BUS_DMA_WAITOK); + if (error) + goto failed; + error = bus_dmamem_map(obj->dmat, obj->dmasegs, nsegs, + obj->dmasize, &obj->vaddr, BUS_DMA_WAITOK | BUS_DMA_COHERENT); + if (error) + goto free; + error = bus_dmamap_create(obj->dmat, obj->dmasize, 1, + obj->dmasize, 0, BUS_DMA_WAITOK, &obj->dmamap); + if (error) + goto unmap; + error = bus_dmamap_load(obj->dmat, obj->dmamap, obj->vaddr, + obj->dmasize, NULL, BUS_DMA_WAITOK); + if (error) + goto destroy; + + memset(obj->vaddr, 0, obj->dmasize); + + drm_gem_private_object_init(ddev, &obj->base, size); + + return obj; + +destroy: + bus_dmamap_destroy(obj->dmat, obj->dmamap); +unmap: + bus_dmamem_unmap(obj->dmat, obj->vaddr, obj->dmasize); +free: + bus_dmamem_free(obj->dmat, obj->dmasegs, nsegs); +failed: + kmem_free(obj, sizeof(*obj)); + + return NULL; +} + +static void +drm_gem_cma_obj_free(struct drm_gem_cma_object *obj) +{ + bus_dmamap_unload(obj->dmat, obj->dmamap); + bus_dmamap_destroy(obj->dmat, obj->dmamap); + bus_dmamem_unmap(obj->dmat, obj->vaddr, obj->dmasize); + bus_dmamem_free(obj->dmat, obj->dmasegs, 1); + kmem_free(obj, sizeof(*obj)); +} + +void +drm_gem_cma_free_object(struct drm_gem_object *gem_obj) +{ + struct drm_gem_cma_object *obj = to_drm_gem_cma_obj(gem_obj); + + drm_gem_free_mmap_offset(gem_obj); + drm_gem_object_release(gem_obj); + drm_gem_cma_obj_free(obj); +} + +int +drm_gem_cma_dumb_create(struct drm_file *file_priv, struct drm_device *ddev, + struct drm_mode_create_dumb *args) +{ + struct drm_gem_cma_object *obj; + uint32_t handle; + int error; + + args->pitch = args->width * ((args->bpp + 7) / 8); + args->size = args->pitch * args->height; + args->size = roundup(args->size, PAGE_SIZE); + args->handle = 0; + + obj = drm_gem_cma_create(ddev, args->size); + if (obj == NULL) + return -ENOMEM; + + error = drm_gem_handle_create(file_priv, &obj->base, &handle); + drm_gem_object_unreference_unlocked(&obj->base); + if (error) { + drm_gem_cma_obj_free(obj); + return error; + } + + args->handle = handle; + + return 0; +} + +int +drm_gem_cma_dumb_map_offset(struct drm_file *file_priv, struct drm_device *ddev, + uint32_t handle, uint64_t *offset) +{ + struct drm_gem_object *gem_obj; + struct drm_gem_cma_object *obj; + int error; + + gem_obj = drm_gem_object_lookup(ddev, file_priv, handle); + if (gem_obj == NULL) + return -ENOENT; + + obj = to_drm_gem_cma_obj(gem_obj); + + if (drm_vma_node_has_offset(&obj->base.vma_node) == 0) { + error = drm_gem_create_mmap_offset(&obj->base); + if (error) + goto done; + } else { + error = 0; + } + + *offset = drm_vma_node_offset_addr(&obj->base.vma_node); + +done: + drm_gem_object_unreference_unlocked(&obj->base); + + return error; +} + +static int +drm_gem_cma_fault(struct uvm_faultinfo *ufi, vaddr_t vaddr, + struct vm_page **pps, int npages, int centeridx, vm_prot_t access_type, + int flags) +{ + struct vm_map_entry *entry = ufi->entry; + struct uvm_object *uobj = entry->object.uvm_obj; + struct drm_gem_object *gem_obj = + container_of(uobj, struct drm_gem_object, gemo_uvmobj); + struct drm_gem_cma_object *obj = to_drm_gem_cma_obj(gem_obj); + off_t curr_offset; + vaddr_t curr_va; + paddr_t paddr, mdpgno; + u_int mmapflags; + int lcv, retval; + vm_prot_t mapprot; + + if (UVM_ET_ISCOPYONWRITE(entry)) + return -EIO; + + curr_offset = entry->offset + (vaddr - entry->start); + curr_va = vaddr; + + retval = 0; + for (lcv = 0; lcv < npages; lcv++, curr_offset += PAGE_SIZE, + curr_va += PAGE_SIZE) { + if ((flags & PGO_ALLPAGES) == 0 && lcv != centeridx) + continue; + if (pps[lcv] == PGO_DONTCARE) + continue; + + mdpgno = bus_dmamem_mmap(obj->dmat, obj->dmasegs, 1, + curr_offset, access_type, BUS_DMA_PREFETCHABLE); + if (mdpgno == -1) { + retval = -EIO; + break; + } + paddr = pmap_phys_address(mdpgno); + mmapflags = pmap_mmap_flags(mdpgno); + mapprot = ufi->entry->protection; + + if (pmap_enter(ufi->orig_map->pmap, curr_va, paddr, mapprot, + PMAP_CANFAIL | mapprot | mmapflags) != 0) { + pmap_update(ufi->orig_map->pmap); + uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj); + uvm_wait("drm_gem_cma_fault"); + return -ERESTART; + } + } + + pmap_update(ufi->orig_map->pmap); + uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj); + + return retval; +} + +const struct uvm_pagerops drm_gem_cma_uvm_ops = { + .pgo_reference = drm_gem_pager_reference, + .pgo_detach = drm_gem_pager_detach, + .pgo_fault = drm_gem_cma_fault, +};