etnaviv_bo.c revision d8807b2f
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#ifdef HAVE_CONFIG_H 28037b3c26Smrg# include <config.h> 29037b3c26Smrg#endif 30037b3c26Smrg 31037b3c26Smrg#include "etnaviv_priv.h" 32037b3c26Smrg#include "etnaviv_drmif.h" 33037b3c26Smrg 34037b3c26Smrgdrm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; 35037b3c26Smrgdrm_private void bo_del(struct etna_bo *bo); 36037b3c26Smrg 37037b3c26Smrg/* set buffer name, and add to table, call w/ table_lock held: */ 38037b3c26Smrgstatic void set_name(struct etna_bo *bo, uint32_t name) 39037b3c26Smrg{ 40037b3c26Smrg bo->name = name; 41037b3c26Smrg /* add ourself into the name table: */ 42037b3c26Smrg drmHashInsert(bo->dev->name_table, name, bo); 43037b3c26Smrg} 44037b3c26Smrg 45037b3c26Smrg/* Called under table_lock */ 46037b3c26Smrgdrm_private void bo_del(struct etna_bo *bo) 47037b3c26Smrg{ 48037b3c26Smrg if (bo->map) 49037b3c26Smrg drm_munmap(bo->map, bo->size); 50037b3c26Smrg 51037b3c26Smrg if (bo->name) 52037b3c26Smrg drmHashDelete(bo->dev->name_table, bo->name); 53037b3c26Smrg 54037b3c26Smrg if (bo->handle) { 55037b3c26Smrg struct drm_gem_close req = { 56037b3c26Smrg .handle = bo->handle, 57037b3c26Smrg }; 58037b3c26Smrg 59037b3c26Smrg drmHashDelete(bo->dev->handle_table, bo->handle); 60037b3c26Smrg drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req); 61037b3c26Smrg } 62037b3c26Smrg 63037b3c26Smrg free(bo); 64037b3c26Smrg} 65037b3c26Smrg 66037b3c26Smrg/* lookup a buffer from it's handle, call w/ table_lock held: */ 67037b3c26Smrgstatic struct etna_bo *lookup_bo(void *tbl, uint32_t handle) 68037b3c26Smrg{ 69037b3c26Smrg struct etna_bo *bo = NULL; 70037b3c26Smrg 71037b3c26Smrg if (!drmHashLookup(tbl, handle, (void **)&bo)) { 72037b3c26Smrg /* found, incr refcnt and return: */ 73037b3c26Smrg bo = etna_bo_ref(bo); 74037b3c26Smrg 75037b3c26Smrg /* don't break the bucket if this bo was found in one */ 76037b3c26Smrg list_delinit(&bo->list); 77037b3c26Smrg } 78037b3c26Smrg 79037b3c26Smrg return bo; 80037b3c26Smrg} 81037b3c26Smrg 82037b3c26Smrg/* allocate a new buffer object, call w/ table_lock held */ 83037b3c26Smrgstatic struct etna_bo *bo_from_handle(struct etna_device *dev, 84037b3c26Smrg uint32_t size, uint32_t handle, uint32_t flags) 85037b3c26Smrg{ 86037b3c26Smrg struct etna_bo *bo = calloc(sizeof(*bo), 1); 87037b3c26Smrg 88037b3c26Smrg if (!bo) { 89037b3c26Smrg struct drm_gem_close req = { 90037b3c26Smrg .handle = handle, 91037b3c26Smrg }; 92037b3c26Smrg 93037b3c26Smrg drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req); 94037b3c26Smrg 95037b3c26Smrg return NULL; 96037b3c26Smrg } 97037b3c26Smrg 98037b3c26Smrg bo->dev = etna_device_ref(dev); 99037b3c26Smrg bo->size = size; 100037b3c26Smrg bo->handle = handle; 101037b3c26Smrg bo->flags = flags; 102037b3c26Smrg atomic_set(&bo->refcnt, 1); 103037b3c26Smrg list_inithead(&bo->list); 104037b3c26Smrg /* add ourselves to the handle table: */ 105037b3c26Smrg drmHashInsert(dev->handle_table, handle, bo); 106037b3c26Smrg 107037b3c26Smrg return bo; 108037b3c26Smrg} 109037b3c26Smrg 110037b3c26Smrg/* allocate a new (un-tiled) buffer object */ 111037b3c26Smrgstruct etna_bo *etna_bo_new(struct etna_device *dev, uint32_t size, 112037b3c26Smrg uint32_t flags) 113037b3c26Smrg{ 114037b3c26Smrg struct etna_bo *bo; 115037b3c26Smrg int ret; 116037b3c26Smrg struct drm_etnaviv_gem_new req = { 117037b3c26Smrg .flags = flags, 118037b3c26Smrg }; 119037b3c26Smrg 120037b3c26Smrg bo = etna_bo_cache_alloc(&dev->bo_cache, &size, flags); 121037b3c26Smrg if (bo) 122037b3c26Smrg return bo; 123037b3c26Smrg 124037b3c26Smrg req.size = size; 125037b3c26Smrg ret = drmCommandWriteRead(dev->fd, DRM_ETNAVIV_GEM_NEW, 126037b3c26Smrg &req, sizeof(req)); 127037b3c26Smrg if (ret) 128037b3c26Smrg return NULL; 129037b3c26Smrg 130037b3c26Smrg pthread_mutex_lock(&table_lock); 131037b3c26Smrg bo = bo_from_handle(dev, size, req.handle, flags); 132037b3c26Smrg bo->reuse = 1; 133037b3c26Smrg pthread_mutex_unlock(&table_lock); 134037b3c26Smrg 135037b3c26Smrg return bo; 136037b3c26Smrg} 137037b3c26Smrg 138037b3c26Smrgstruct etna_bo *etna_bo_ref(struct etna_bo *bo) 139037b3c26Smrg{ 140037b3c26Smrg atomic_inc(&bo->refcnt); 141037b3c26Smrg 142037b3c26Smrg return bo; 143037b3c26Smrg} 144037b3c26Smrg 145037b3c26Smrg/* get buffer info */ 146037b3c26Smrgstatic int get_buffer_info(struct etna_bo *bo) 147037b3c26Smrg{ 148037b3c26Smrg int ret; 149037b3c26Smrg struct drm_etnaviv_gem_info req = { 150037b3c26Smrg .handle = bo->handle, 151037b3c26Smrg }; 152037b3c26Smrg 153037b3c26Smrg ret = drmCommandWriteRead(bo->dev->fd, DRM_ETNAVIV_GEM_INFO, 154037b3c26Smrg &req, sizeof(req)); 155037b3c26Smrg if (ret) { 156037b3c26Smrg return ret; 157037b3c26Smrg } 158037b3c26Smrg 159037b3c26Smrg /* really all we need for now is mmap offset */ 160037b3c26Smrg bo->offset = req.offset; 161037b3c26Smrg 162037b3c26Smrg return 0; 163037b3c26Smrg} 164037b3c26Smrg 165037b3c26Smrg/* import a buffer object from DRI2 name */ 166037b3c26Smrgstruct etna_bo *etna_bo_from_name(struct etna_device *dev, uint32_t name) 167037b3c26Smrg{ 168037b3c26Smrg struct etna_bo *bo; 169037b3c26Smrg struct drm_gem_open req = { 170037b3c26Smrg .name = name, 171037b3c26Smrg }; 172037b3c26Smrg 173037b3c26Smrg pthread_mutex_lock(&table_lock); 174037b3c26Smrg 175037b3c26Smrg /* check name table first, to see if bo is already open: */ 176d8807b2fSmrg bo = lookup_bo(dev->name_table, name); 177037b3c26Smrg if (bo) 178037b3c26Smrg goto out_unlock; 179037b3c26Smrg 180037b3c26Smrg if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { 181037b3c26Smrg ERROR_MSG("gem-open failed: %s", strerror(errno)); 182037b3c26Smrg goto out_unlock; 183037b3c26Smrg } 184037b3c26Smrg 185037b3c26Smrg bo = lookup_bo(dev->handle_table, req.handle); 186037b3c26Smrg if (bo) 187037b3c26Smrg goto out_unlock; 188037b3c26Smrg 189037b3c26Smrg bo = bo_from_handle(dev, req.size, req.handle, 0); 190037b3c26Smrg if (bo) 191037b3c26Smrg set_name(bo, name); 192037b3c26Smrg 193037b3c26Smrgout_unlock: 194037b3c26Smrg pthread_mutex_unlock(&table_lock); 195037b3c26Smrg 196037b3c26Smrg return bo; 197037b3c26Smrg} 198037b3c26Smrg 199037b3c26Smrg/* import a buffer from dmabuf fd, does not take ownership of the 200037b3c26Smrg * fd so caller should close() the fd when it is otherwise done 201037b3c26Smrg * with it (even if it is still using the 'struct etna_bo *') 202037b3c26Smrg */ 203037b3c26Smrgstruct etna_bo *etna_bo_from_dmabuf(struct etna_device *dev, int fd) 204037b3c26Smrg{ 205037b3c26Smrg struct etna_bo *bo; 206037b3c26Smrg int ret, size; 207037b3c26Smrg uint32_t handle; 208037b3c26Smrg 209037b3c26Smrg pthread_mutex_lock(&table_lock); 210037b3c26Smrg 211037b3c26Smrg ret = drmPrimeFDToHandle(dev->fd, fd, &handle); 212037b3c26Smrg if (ret) { 213037b3c26Smrg return NULL; 214037b3c26Smrg } 215037b3c26Smrg 216037b3c26Smrg bo = lookup_bo(dev->handle_table, handle); 217037b3c26Smrg if (bo) 218037b3c26Smrg goto out_unlock; 219037b3c26Smrg 220037b3c26Smrg /* lseek() to get bo size */ 221037b3c26Smrg size = lseek(fd, 0, SEEK_END); 222037b3c26Smrg lseek(fd, 0, SEEK_CUR); 223037b3c26Smrg 224037b3c26Smrg bo = bo_from_handle(dev, size, handle, 0); 225037b3c26Smrg 226037b3c26Smrgout_unlock: 227037b3c26Smrg pthread_mutex_unlock(&table_lock); 228037b3c26Smrg 229037b3c26Smrg return bo; 230037b3c26Smrg} 231037b3c26Smrg 232037b3c26Smrg/* destroy a buffer object */ 233037b3c26Smrgvoid etna_bo_del(struct etna_bo *bo) 234037b3c26Smrg{ 235037b3c26Smrg struct etna_device *dev = bo->dev; 236037b3c26Smrg 237037b3c26Smrg if (!bo) 238037b3c26Smrg return; 239037b3c26Smrg 240037b3c26Smrg if (!atomic_dec_and_test(&bo->refcnt)) 241037b3c26Smrg return; 242037b3c26Smrg 243037b3c26Smrg pthread_mutex_lock(&table_lock); 244037b3c26Smrg 245037b3c26Smrg if (bo->reuse && (etna_bo_cache_free(&dev->bo_cache, bo) == 0)) 246037b3c26Smrg goto out; 247037b3c26Smrg 248037b3c26Smrg bo_del(bo); 249037b3c26Smrg etna_device_del_locked(dev); 250037b3c26Smrgout: 251037b3c26Smrg pthread_mutex_unlock(&table_lock); 252037b3c26Smrg} 253037b3c26Smrg 254037b3c26Smrg/* get the global flink/DRI2 buffer name */ 255037b3c26Smrgint etna_bo_get_name(struct etna_bo *bo, uint32_t *name) 256037b3c26Smrg{ 257037b3c26Smrg if (!bo->name) { 258037b3c26Smrg struct drm_gem_flink req = { 259037b3c26Smrg .handle = bo->handle, 260037b3c26Smrg }; 261037b3c26Smrg int ret; 262037b3c26Smrg 263037b3c26Smrg ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); 264037b3c26Smrg if (ret) { 265037b3c26Smrg return ret; 266037b3c26Smrg } 267037b3c26Smrg 268037b3c26Smrg pthread_mutex_lock(&table_lock); 269037b3c26Smrg set_name(bo, req.name); 270037b3c26Smrg pthread_mutex_unlock(&table_lock); 271037b3c26Smrg bo->reuse = 0; 272037b3c26Smrg } 273037b3c26Smrg 274037b3c26Smrg *name = bo->name; 275037b3c26Smrg 276037b3c26Smrg return 0; 277037b3c26Smrg} 278037b3c26Smrg 279037b3c26Smrguint32_t etna_bo_handle(struct etna_bo *bo) 280037b3c26Smrg{ 281037b3c26Smrg return bo->handle; 282037b3c26Smrg} 283037b3c26Smrg 284037b3c26Smrg/* caller owns the dmabuf fd that is returned and is responsible 285037b3c26Smrg * to close() it when done 286037b3c26Smrg */ 287037b3c26Smrgint etna_bo_dmabuf(struct etna_bo *bo) 288037b3c26Smrg{ 289037b3c26Smrg int ret, prime_fd; 290037b3c26Smrg 291037b3c26Smrg ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC, 292037b3c26Smrg &prime_fd); 293037b3c26Smrg if (ret) { 294037b3c26Smrg ERROR_MSG("failed to get dmabuf fd: %d", ret); 295037b3c26Smrg return ret; 296037b3c26Smrg } 297037b3c26Smrg 298037b3c26Smrg bo->reuse = 0; 299037b3c26Smrg 300037b3c26Smrg return prime_fd; 301037b3c26Smrg} 302037b3c26Smrg 303037b3c26Smrguint32_t etna_bo_size(struct etna_bo *bo) 304037b3c26Smrg{ 305037b3c26Smrg return bo->size; 306037b3c26Smrg} 307037b3c26Smrg 308037b3c26Smrgvoid *etna_bo_map(struct etna_bo *bo) 309037b3c26Smrg{ 310037b3c26Smrg if (!bo->map) { 311037b3c26Smrg if (!bo->offset) { 312037b3c26Smrg get_buffer_info(bo); 313037b3c26Smrg } 314037b3c26Smrg 315037b3c26Smrg bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, 316037b3c26Smrg MAP_SHARED, bo->dev->fd, bo->offset); 317037b3c26Smrg if (bo->map == MAP_FAILED) { 318037b3c26Smrg ERROR_MSG("mmap failed: %s", strerror(errno)); 319037b3c26Smrg bo->map = NULL; 320037b3c26Smrg } 321037b3c26Smrg } 322037b3c26Smrg 323037b3c26Smrg return bo->map; 324037b3c26Smrg} 325037b3c26Smrg 326037b3c26Smrgint etna_bo_cpu_prep(struct etna_bo *bo, uint32_t op) 327037b3c26Smrg{ 328037b3c26Smrg struct drm_etnaviv_gem_cpu_prep req = { 329037b3c26Smrg .handle = bo->handle, 330037b3c26Smrg .op = op, 331037b3c26Smrg }; 332037b3c26Smrg 333037b3c26Smrg get_abs_timeout(&req.timeout, 5000000000); 334037b3c26Smrg 335037b3c26Smrg return drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_PREP, 336037b3c26Smrg &req, sizeof(req)); 337037b3c26Smrg} 338037b3c26Smrg 339037b3c26Smrgvoid etna_bo_cpu_fini(struct etna_bo *bo) 340037b3c26Smrg{ 341037b3c26Smrg struct drm_etnaviv_gem_cpu_fini req = { 342037b3c26Smrg .handle = bo->handle, 343037b3c26Smrg }; 344037b3c26Smrg 345037b3c26Smrg drmCommandWrite(bo->dev->fd, DRM_ETNAVIV_GEM_CPU_FINI, 346037b3c26Smrg &req, sizeof(req)); 347037b3c26Smrg} 348