1037b3c26Smrg/* 2037b3c26Smrg * Copyright (C) 2014 Etnaviv Project 3037b3c26Smrg * 4037b3c26Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5037b3c26Smrg * copy of this software and associated documentation files (the "Software"), 6037b3c26Smrg * to deal in the Software without restriction, including without limitation 7037b3c26Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8037b3c26Smrg * and/or sell copies of the Software, and to permit persons to whom the 9037b3c26Smrg * Software is furnished to do so, subject to the following conditions: 10037b3c26Smrg * 11037b3c26Smrg * The above copyright notice and this permission notice (including the next 12037b3c26Smrg * paragraph) shall be included in all copies or substantial portions of the 13037b3c26Smrg * Software. 14037b3c26Smrg * 15037b3c26Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16037b3c26Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17037b3c26Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18037b3c26Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19037b3c26Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20037b3c26Smrg * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21037b3c26Smrg * SOFTWARE. 22037b3c26Smrg * 23037b3c26Smrg * Authors: 24037b3c26Smrg * Christian Gmeiner <christian.gmeiner@gmail.com> 25037b3c26Smrg */ 26037b3c26Smrg 27037b3c26Smrg#include "etnaviv_priv.h" 28037b3c26Smrg#include "etnaviv_drmif.h" 29037b3c26Smrg 30037b3c26Smrgdrm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; 31037b3c26Smrgdrm_private void bo_del(struct etna_bo *bo); 32037b3c26Smrg 33037b3c26Smrg/* set buffer name, and add to table, call w/ table_lock held: */ 34037b3c26Smrgstatic void set_name(struct etna_bo *bo, uint32_t name) 35037b3c26Smrg{ 36037b3c26Smrg bo->name = name; 37037b3c26Smrg /* add ourself into the name table: */ 38037b3c26Smrg drmHashInsert(bo->dev->name_table, name, bo); 39037b3c26Smrg} 40037b3c26Smrg 41037b3c26Smrg/* Called under table_lock */ 42037b3c26Smrgdrm_private void bo_del(struct etna_bo *bo) 43037b3c26Smrg{ 44037b3c26Smrg if (bo->map) 45037b3c26Smrg drm_munmap(bo->map, bo->size); 46037b3c26Smrg 47037b3c26Smrg if (bo->name) 48037b3c26Smrg drmHashDelete(bo->dev->name_table, bo->name); 49037b3c26Smrg 50037b3c26Smrg if (bo->handle) { 51037b3c26Smrg drmHashDelete(bo->dev->handle_table, bo->handle); 5249ef06a4Smrg drmCloseBufferHandle(bo->dev->fd, bo->handle); 53037b3c26Smrg } 54037b3c26Smrg 55037b3c26Smrg free(bo); 56037b3c26Smrg} 57037b3c26Smrg 58037b3c26Smrg/* lookup a buffer from it's handle, call w/ table_lock held: */ 59037b3c26Smrgstatic struct etna_bo *lookup_bo(void *tbl, uint32_t handle) 60037b3c26Smrg{ 61037b3c26Smrg struct etna_bo *bo = NULL; 62037b3c26Smrg 63037b3c26Smrg if (!drmHashLookup(tbl, handle, (void **)&bo)) { 64037b3c26Smrg /* found, incr refcnt and return: */ 65037b3c26Smrg bo = etna_bo_ref(bo); 66037b3c26Smrg 67037b3c26Smrg /* don't break the bucket if this bo was found in one */ 68037b3c26Smrg list_delinit(&bo->list); 69037b3c26Smrg } 70037b3c26Smrg 71037b3c26Smrg return bo; 72037b3c26Smrg} 73037b3c26Smrg 74037b3c26Smrg/* allocate a new buffer object, call w/ table_lock held */ 75037b3c26Smrgstatic struct etna_bo *bo_from_handle(struct etna_device *dev, 76037b3c26Smrg uint32_t size, uint32_t handle, uint32_t flags) 77037b3c26Smrg{ 78037b3c26Smrg struct etna_bo *bo = calloc(sizeof(*bo), 1); 79037b3c26Smrg 80037b3c26Smrg if (!bo) { 8149ef06a4Smrg drmCloseBufferHandle(dev->fd, handle); 82037b3c26Smrg return NULL; 83037b3c26Smrg } 84037b3c26Smrg 85037b3c26Smrg bo->dev = etna_device_ref(dev); 86037b3c26Smrg bo->size = size; 87037b3c26Smrg bo->handle = handle; 88037b3c26Smrg bo->flags = flags; 89037b3c26Smrg atomic_set(&bo->refcnt, 1); 90037b3c26Smrg list_inithead(&bo->list); 91037b3c26Smrg /* add ourselves to the handle table: */ 92037b3c26Smrg drmHashInsert(dev->handle_table, handle, bo); 93037b3c26Smrg 94037b3c26Smrg return bo; 95037b3c26Smrg} 96037b3c26Smrg 97037b3c26Smrg/* allocate a new (un-tiled) buffer object */ 987cdc0497Smrgdrm_public struct etna_bo *etna_bo_new(struct etna_device *dev, uint32_t size, 99037b3c26Smrg uint32_t flags) 100037b3c26Smrg{ 101037b3c26Smrg struct etna_bo *bo; 102037b3c26Smrg int ret; 103037b3c26Smrg struct drm_etnaviv_gem_new req = { 104037b3c26Smrg .flags = flags, 105037b3c26Smrg }; 106037b3c26Smrg 107037b3c26Smrg bo = etna_bo_cache_alloc(&dev->bo_cache, &size, flags); 108037b3c26Smrg if (bo) 109037b3c26Smrg return bo; 110037b3c26Smrg 111037b3c26Smrg req.size = size; 112037b3c26Smrg ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GEM_NEW, 113037b3c26Smrg &req, sizeof(req)); 114037b3c26Smrg if (ret) 115037b3c26Smrg return NULL; 116037b3c26Smrg 117037b3c26Smrg pthread_mutex_lock(&table_lock); 118037b3c26Smrg bo = bo_from_handle(dev, size, req.handle, flags); 119037b3c26Smrg bo->reuse = 1; 120037b3c26Smrg pthread_mutex_unlock(&table_lock); 121037b3c26Smrg 122037b3c26Smrg return bo; 123037b3c26Smrg} 124037b3c26Smrg 1257cdc0497Smrgdrm_public struct etna_bo *etna_bo_ref(struct etna_bo *bo) 126037b3c26Smrg{ 127037b3c26Smrg atomic_inc(&bo->refcnt); 128037b3c26Smrg 129037b3c26Smrg return bo; 130037b3c26Smrg} 131037b3c26Smrg 132037b3c26Smrg/* get buffer info */ 133037b3c26Smrgstatic int get_buffer_info(struct etna_bo *bo) 134037b3c26Smrg{ 135037b3c26Smrg int ret; 136037b3c26Smrg struct drm_etnaviv_gem_info req = { 137037b3c26Smrg .handle = bo->handle, 138037b3c26Smrg }; 139037b3c26Smrg 140037b3c26Smrg ret = drmCommandWriteRead(bo->dev->fd, DRM_ETNAVIV_GEM_INFO, 141037b3c26Smrg &req, sizeof(req)); 142037b3c26Smrg if (ret) { 143037b3c26Smrg return ret; 144037b3c26Smrg } 145037b3c26Smrg 146037b3c26Smrg /* really all we need for now is mmap offset */ 147037b3c26Smrg bo->offset = req.offset; 148037b3c26Smrg 149037b3c26Smrg return 0; 150037b3c26Smrg} 151037b3c26Smrg 152037b3c26Smrg/* import a buffer object from DRI2 name */ 1537cdc0497Smrgdrm_public struct etna_bo *etna_bo_from_name(struct etna_device *dev, 1547cdc0497Smrg uint32_t name) 155037b3c26Smrg{ 156037b3c26Smrg struct etna_bo *bo; 157037b3c26Smrg struct drm_gem_open req = { 158037b3c26Smrg .name = name, 159037b3c26Smrg }; 160037b3c26Smrg 161037b3c26Smrg pthread_mutex_lock(&table_lock); 162037b3c26Smrg 163037b3c26Smrg /* check name table first, to see if bo is already open: */ 164d8807b2fSmrg bo = lookup_bo(dev->name_table, name); 165037b3c26Smrg if (bo) 166037b3c26Smrg goto out_unlock; 167037b3c26Smrg 168037b3c26Smrg if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { 169037b3c26Smrg ERROR_MSG("gem-open failed: %s", strerror(errno)); 170037b3c26Smrg goto out_unlock; 171037b3c26Smrg } 172037b3c26Smrg 173037b3c26Smrg bo = lookup_bo(dev->handle_table, req.handle); 174037b3c26Smrg if (bo) 175037b3c26Smrg goto out_unlock; 176037b3c26Smrg 177037b3c26Smrg bo = bo_from_handle(dev, req.size, req.handle, 0); 178037b3c26Smrg if (bo) 179037b3c26Smrg set_name(bo, name); 180037b3c26Smrg 181037b3c26Smrgout_unlock: 182037b3c26Smrg pthread_mutex_unlock(&table_lock); 183037b3c26Smrg 184037b3c26Smrg return bo; 185037b3c26Smrg} 186037b3c26Smrg 187037b3c26Smrg/* import a buffer from dmabuf fd, does not take ownership of the 188037b3c26Smrg * fd so caller should close() the fd when it is otherwise done 189037b3c26Smrg * with it (even if it is still using the 'struct etna_bo *') 190037b3c26Smrg */ 1917cdc0497Smrgdrm_public struct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd) 192037b3c26Smrg{ 193037b3c26Smrg struct etna_bo *bo; 194037b3c26Smrg int ret, size; 195037b3c26Smrg uint32_t handle; 196037b3c26Smrg 19700a23bdaSmrg /* take the lock before calling drmPrimeFDToHandle to avoid 19800a23bdaSmrg * racing against etna_bo_del, which might invalidate the 19900a23bdaSmrg * returned handle. 20000a23bdaSmrg */ 201037b3c26Smrg pthread_mutex_lock(&table_lock); 202037b3c26Smrg 203037b3c26Smrg ret = drmPrimeFDToHandle(dev->fd, fd, &handle); 204037b3c26Smrg if (ret) { 20500a23bdaSmrg pthread_mutex_unlock(&table_lock); 206037b3c26Smrg return NULL; 207037b3c26Smrg } 208037b3c26Smrg 209037b3c26Smrg bo = lookup_bo(dev->handle_table, handle); 210037b3c26Smrg if (bo) 211037b3c26Smrg goto out_unlock; 212037b3c26Smrg 213037b3c26Smrg /* lseek() to get bo size */ 214037b3c26Smrg size = lseek(fd, 0, SEEK_END); 215037b3c26Smrg lseek(fd, 0, SEEK_CUR); 216037b3c26Smrg 217037b3c26Smrg bo = bo_from_handle(dev, size, handle, 0); 218037b3c26Smrg 219037b3c26Smrgout_unlock: 220037b3c26Smrg pthread_mutex_unlock(&table_lock); 221037b3c26Smrg 222037b3c26Smrg return bo; 223037b3c26Smrg} 224037b3c26Smrg 225037b3c26Smrg/* destroy a buffer object */ 2267cdc0497Smrgdrm_public void etna_bo_del(struct etna_bo *bo) 227037b3c26Smrg{ 228037b3c26Smrg struct etna_device *dev = bo->dev; 229037b3c26Smrg 230037b3c26Smrg if (!bo) 231037b3c26Smrg return; 232037b3c26Smrg 233037b3c26Smrg if (!atomic_dec_and_test(&bo->refcnt)) 234037b3c26Smrg return; 235037b3c26Smrg 236037b3c26Smrg pthread_mutex_lock(&table_lock); 237037b3c26Smrg 238037b3c26Smrg if (bo->reuse && (etna_bo_cache_free(&dev->bo_cache, bo) == 0)) 239037b3c26Smrg goto out; 240037b3c26Smrg 241037b3c26Smrg bo_del(bo); 242037b3c26Smrg etna_device_del_locked(dev); 243037b3c26Smrgout: 244037b3c26Smrg pthread_mutex_unlock(&table_lock); 245037b3c26Smrg} 246037b3c26Smrg 247037b3c26Smrg/* get the global flink/DRI2 buffer name */ 2487cdc0497Smrgdrm_public int etna_bo_get_name(struct etna_bo *bo, uint32_t *name) 249037b3c26Smrg{ 250037b3c26Smrg if (!bo->name) { 251037b3c26Smrg struct drm_gem_flink req = { 252037b3c26Smrg .handle = bo->handle, 253037b3c26Smrg }; 254037b3c26Smrg int ret; 255037b3c26Smrg 256037b3c26Smrg ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); 257037b3c26Smrg if (ret) { 258037b3c26Smrg return ret; 259037b3c26Smrg } 260037b3c26Smrg 261037b3c26Smrg pthread_mutex_lock(&table_lock); 262037b3c26Smrg set_name(bo, req.name); 263037b3c26Smrg pthread_mutex_unlock(&table_lock); 264037b3c26Smrg bo->reuse = 0; 265037b3c26Smrg } 266037b3c26Smrg 267037b3c26Smrg *name = bo->name; 268037b3c26Smrg 269037b3c26Smrg return 0; 270037b3c26Smrg} 271037b3c26Smrg 2727cdc0497Smrgdrm_public uint32_t etna_bo_handle(struct etna_bo *bo) 273037b3c26Smrg{ 274037b3c26Smrg return bo->handle; 275037b3c26Smrg} 276037b3c26Smrg 277037b3c26Smrg/* caller owns the dmabuf fd that is returned and is responsible 278037b3c26Smrg * to close() it when done 279037b3c26Smrg */ 2807cdc0497Smrgdrm_public int etna_bo_dmabuf(struct etna_bo *bo) 281037b3c26Smrg{ 282037b3c26Smrg int ret, prime_fd; 283037b3c26Smrg 284037b3c26Smrg ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC, 285037b3c26Smrg &prime_fd); 286037b3c26Smrg if (ret) { 287037b3c26Smrg ERROR_MSG("failed to get dmabuf fd: %d", ret); 288037b3c26Smrg return ret; 289037b3c26Smrg } 290037b3c26Smrg 291037b3c26Smrg bo->reuse = 0; 292037b3c26Smrg 293037b3c26Smrg return prime_fd; 294037b3c26Smrg} 295037b3c26Smrg 2967cdc0497Smrgdrm_public uint32_t etna_bo_size(struct etna_bo *bo) 297037b3c26Smrg{ 298037b3c26Smrg return bo->size; 299037b3c26Smrg} 300037b3c26Smrg 3017cdc0497Smrgdrm_public void *etna_bo_map(struct etna_bo *bo) 302037b3c26Smrg{ 303037b3c26Smrg if (!bo->map) { 304037b3c26Smrg if (!bo->offset) { 305037b3c26Smrg get_buffer_info(bo); 306037b3c26Smrg } 307037b3c26Smrg 308037b3c26Smrg bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, 309037b3c26Smrg MAP_SHARED, bo->dev->fd, bo->offset); 310037b3c26Smrg if (bo->map == MAP_FAILED) { 311037b3c26Smrg ERROR_MSG("mmap failed: %s", strerror(errno)); 312037b3c26Smrg bo->map = NULL; 313037b3c26Smrg } 314037b3c26Smrg } 315037b3c26Smrg 316037b3c26Smrg return bo->map; 317037b3c26Smrg} 318037b3c26Smrg 3197cdc0497Smrgdrm_public int etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op) 320037b3c26Smrg{ 321037b3c26Smrg struct drm_etnaviv_gem_cpu_prep req = { 322037b3c26Smrg .handle = bo->handle, 323037b3c26Smrg .op = op, 324037b3c26Smrg }; 325037b3c26Smrg 326037b3c26Smrg get_abs_timeout(&req.timeout, 5000000000); 327037b3c26Smrg 328037b3c26Smrg return drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_PREP, 329037b3c26Smrg &req, sizeof(req)); 330037b3c26Smrg} 331037b3c26Smrg 3327cdc0497Smrgdrm_public void etna_bo_cpu_fini(struct etna_bo *bo) 333037b3c26Smrg{ 334037b3c26Smrg struct drm_etnaviv_gem_cpu_fini req = { 335037b3c26Smrg .handle = bo->handle, 336037b3c26Smrg }; 337037b3c26Smrg 338037b3c26Smrg drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_FINI, 339037b3c26Smrg &req, sizeof(req)); 340037b3c26Smrg} 341