1/* $OpenBSD: drm_gem_dma_helper.c,v 1.3 2024/01/16 23:37:51 jsg Exp $ */ 2/* $NetBSD: drm_gem_dma_helper.c,v 1.9 2019/11/05 23:29:28 jmcneill Exp $ */ 3/*- 4 * Copyright (c) 2015-2017 Jared McNeill <jmcneill@invisible.ca> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/param.h> 30#include <linux/iosys-map.h> 31 32#include <drm/drm_device.h> 33#include <drm/drm_gem_dma_helper.h> 34 35#include <uvm/uvm.h> 36 37static const struct drm_gem_object_funcs drm_gem_dma_default_funcs = { 38 .free = drm_gem_dma_free_object, 39 .get_sg_table = drm_gem_dma_get_sg_table, 40 .vmap = drm_gem_dma_vmap, 41// .mmap = drm_gem_dma_mmap, 42}; 43 44static struct drm_gem_dma_object * 45drm_gem_dma_create_internal(struct drm_device *ddev, size_t size, 46 struct sg_table *sgt) 47{ 48 struct drm_gem_dma_object *obj; 49 int error, nsegs; 50 51 obj = malloc(sizeof(*obj), M_DRM, M_WAITOK | M_ZERO); 52 obj->dmat = ddev->dmat; 53 obj->dmasize = size; 54 obj->base.funcs = &drm_gem_dma_default_funcs; 55 56 if (sgt) { 57 STUB(); 58#ifdef notyet 59 error = -drm_prime_sg_to_bus_dmamem(obj->dmat, obj->dmasegs, 1, 60 &nsegs, sgt); 61#endif 62 error = -ENOMEM; 63 } else { 64 error = bus_dmamem_alloc(obj->dmat, obj->dmasize, 65 PAGE_SIZE, 0, obj->dmasegs, 1, &nsegs, 66 BUS_DMA_WAITOK); 67 } 68 if (error) 69 goto failed; 70 error = bus_dmamem_map(obj->dmat, obj->dmasegs, nsegs, 71 obj->dmasize, &obj->vaddr, 72 BUS_DMA_WAITOK | BUS_DMA_NOCACHE); 73 if (error) 74 goto free; 75 error = bus_dmamap_create(obj->dmat, obj->dmasize, 1, 76 obj->dmasize, 0, BUS_DMA_WAITOK, &obj->dmamap); 77 if (error) 78 goto unmap; 79 error = bus_dmamap_load(obj->dmat, obj->dmamap, obj->vaddr, 80 obj->dmasize, NULL, BUS_DMA_WAITOK); 81 if (error) 82 goto destroy; 83 84#ifdef notyet 85 if (!sgt) 86#endif 87 memset(obj->vaddr, 0, obj->dmasize); 88 89 error = drm_gem_object_init(ddev, &obj->base, size); 90 if (error) 91 goto unload; 92 93 obj->dma_addr = obj->dmamap->dm_segs[0].ds_addr; 94 return obj; 95 96unload: 97 bus_dmamap_unload(obj->dmat, obj->dmamap); 98destroy: 99 bus_dmamap_destroy(obj->dmat, obj->dmamap); 100unmap: 101 bus_dmamem_unmap(obj->dmat, obj->vaddr, obj->dmasize); 102free: 103#ifdef notyet 104 if (obj->sgt) 105 drm_prime_sg_free(obj->sgt); 106 else 107#endif 108 bus_dmamem_free(obj->dmat, obj->dmasegs, nsegs); 109failed: 110 free(obj, M_DRM, sizeof(*obj)); 111 112 return NULL; 113} 114 115struct drm_gem_dma_object * 116drm_gem_dma_create(struct drm_device *ddev, size_t size) 117{ 118 119 return drm_gem_dma_create_internal(ddev, size, NULL); 120} 121 122static void 123drm_gem_dma_obj_free(struct drm_gem_dma_object *obj) 124{ 125 126 bus_dmamap_unload(obj->dmat, obj->dmamap); 127 bus_dmamap_destroy(obj->dmat, obj->dmamap); 128 bus_dmamem_unmap(obj->dmat, obj->vaddr, obj->dmasize); 129#ifdef notyet 130 if (obj->sgt) 131 drm_prime_sg_free(obj->sgt); 132 else 133#endif 134 bus_dmamem_free(obj->dmat, obj->dmasegs, 1); 135 free(obj, M_DRM, sizeof(*obj)); 136} 137 138void 139drm_gem_dma_free_object(struct drm_gem_object *gem_obj) 140{ 141 struct drm_gem_dma_object *obj = to_drm_gem_dma_obj(gem_obj); 142 143 drm_gem_free_mmap_offset(gem_obj); 144 drm_gem_object_release(gem_obj); 145 drm_gem_dma_obj_free(obj); 146} 147 148int 149drm_gem_dma_dumb_create_internal(struct drm_file *file_priv, 150 struct drm_device *ddev, struct drm_mode_create_dumb *args) 151{ 152 struct drm_gem_dma_object *obj; 153 uint32_t handle; 154 int error; 155 156 args->handle = 0; 157 158 obj = drm_gem_dma_create(ddev, args->size); 159 if (obj == NULL) 160 return -ENOMEM; 161 162 error = drm_gem_handle_create(file_priv, &obj->base, &handle); 163 drm_gem_object_put(&obj->base); 164 if (error) { 165 drm_gem_dma_obj_free(obj); 166 return error; 167 } 168 169 args->handle = handle; 170 171 return 0; 172} 173 174int 175drm_gem_dma_dumb_create(struct drm_file *file_priv, struct drm_device *ddev, 176 struct drm_mode_create_dumb *args) 177{ 178 args->pitch = args->width * ((args->bpp + 7) / 8); 179 args->size = args->pitch * args->height; 180 args->size = roundup(args->size, PAGE_SIZE); 181 182 return drm_gem_dma_dumb_create_internal(file_priv, ddev, args); 183} 184 185int 186drm_gem_dma_fault(struct drm_gem_object *gem_obj, struct uvm_faultinfo *ufi, 187 off_t offset, vaddr_t vaddr, vm_page_t *pps, int npages, int centeridx, 188 vm_prot_t access_type, int flags) 189{ 190 struct drm_gem_dma_object *obj = to_drm_gem_dma_obj(gem_obj); 191 struct uvm_object *uobj = &obj->base.uobj; 192 paddr_t paddr; 193 int lcv, retval; 194 vm_prot_t mapprot; 195 196 offset -= drm_vma_node_offset_addr(&obj->base.vma_node); 197 mapprot = ufi->entry->protection; 198 199 retval = 0; 200 for (lcv = 0; lcv < npages; lcv++, offset += PAGE_SIZE, 201 vaddr += PAGE_SIZE) { 202 if ((flags & PGO_ALLPAGES) == 0 && lcv != centeridx) 203 continue; 204 205 if (pps[lcv] == PGO_DONTCARE) 206 continue; 207 208 paddr = bus_dmamem_mmap(obj->dmat, obj->dmasegs, 1, 209 offset, access_type, BUS_DMA_NOCACHE); 210 if (paddr == -1) { 211 retval = VM_PAGER_BAD; 212 break; 213 } 214 215 if (pmap_enter(ufi->orig_map->pmap, vaddr, paddr, 216 mapprot, PMAP_CANFAIL | mapprot) != 0) { 217 pmap_update(ufi->orig_map->pmap); 218 uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, 219 uobj); 220 uvm_wait("drm_gem_dma_fault"); 221 return VM_PAGER_REFAULT; 222 } 223 } 224 225 pmap_update(ufi->orig_map->pmap); 226 uvmfault_unlockall(ufi, ufi->entry->aref.ar_amap, uobj); 227 228 return retval; 229} 230 231struct sg_table * 232drm_gem_dma_get_sg_table(struct drm_gem_object *gem_obj) 233{ 234 return NULL; 235#ifdef notyet 236 struct drm_gem_dma_object *obj = to_drm_gem_dma_obj(gem_obj); 237 238 return drm_prime_bus_dmamem_to_sg(obj->dmat, obj->dmasegs, 1); 239#endif 240} 241 242struct drm_gem_object * 243drm_gem_dma_prime_import_sg_table(struct drm_device *ddev, 244 struct dma_buf_attachment *attach, struct sg_table *sgt) 245{ 246 return NULL; 247#ifdef notyet 248 size_t size = drm_prime_sg_size(sgt); 249 struct drm_gem_dma_object *obj; 250 251 obj = drm_gem_dma_create_internal(ddev, size, sgt); 252 if (obj == NULL) 253 return ERR_PTR(-ENOMEM); 254 255 return &obj->base; 256#endif 257} 258 259int 260drm_gem_dma_vmap(struct drm_gem_object *gem_obj, struct iosys_map *map) 261{ 262 struct drm_gem_dma_object *obj = to_drm_gem_dma_obj(gem_obj); 263 264 iosys_map_set_vaddr(map, obj->vaddr); 265 266 return 0; 267} 268