1d722e3fbSopenharmony_ci/* -*- mode: C; c-file-style: "k&r"; tab-width 4; indent-tabs-mode: t; -*- */ 2d722e3fbSopenharmony_ci 3d722e3fbSopenharmony_ci/* 4d722e3fbSopenharmony_ci * Copyright (C) 2012 Rob Clark <robclark@freedesktop.org> 5d722e3fbSopenharmony_ci * 6d722e3fbSopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a 7d722e3fbSopenharmony_ci * copy of this software and associated documentation files (the "Software"), 8d722e3fbSopenharmony_ci * to deal in the Software without restriction, including without limitation 9d722e3fbSopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense, 10d722e3fbSopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the 11d722e3fbSopenharmony_ci * Software is furnished to do so, subject to the following conditions: 12d722e3fbSopenharmony_ci * 13d722e3fbSopenharmony_ci * The above copyright notice and this permission notice (including the next 14d722e3fbSopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the 15d722e3fbSopenharmony_ci * Software. 16d722e3fbSopenharmony_ci * 17d722e3fbSopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18d722e3fbSopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19d722e3fbSopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 20d722e3fbSopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21d722e3fbSopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22d722e3fbSopenharmony_ci * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23d722e3fbSopenharmony_ci * SOFTWARE. 24d722e3fbSopenharmony_ci * 25d722e3fbSopenharmony_ci * Authors: 26d722e3fbSopenharmony_ci * Rob Clark <robclark@freedesktop.org> 27d722e3fbSopenharmony_ci */ 28d722e3fbSopenharmony_ci 29d722e3fbSopenharmony_ci#include "freedreno_drmif.h" 30d722e3fbSopenharmony_ci#include "freedreno_priv.h" 31d722e3fbSopenharmony_ci 32d722e3fbSopenharmony_cidrm_private pthread_mutex_t table_lock = PTHREAD_MUTEX_INITIALIZER; 33d722e3fbSopenharmony_cidrm_private void bo_del(struct fd_bo *bo); 34d722e3fbSopenharmony_ci 35d722e3fbSopenharmony_ci/* set buffer name, and add to table, call w/ table_lock held: */ 36d722e3fbSopenharmony_cistatic void set_name(struct fd_bo *bo, uint32_t name) 37d722e3fbSopenharmony_ci{ 38d722e3fbSopenharmony_ci bo->name = name; 39d722e3fbSopenharmony_ci /* add ourself into the handle table: */ 40d722e3fbSopenharmony_ci drmHashInsert(bo->dev->name_table, name, bo); 41d722e3fbSopenharmony_ci} 42d722e3fbSopenharmony_ci 43d722e3fbSopenharmony_ci/* lookup a buffer, call w/ table_lock held: */ 44d722e3fbSopenharmony_cistatic struct fd_bo * lookup_bo(void *tbl, uint32_t key) 45d722e3fbSopenharmony_ci{ 46d722e3fbSopenharmony_ci struct fd_bo *bo = NULL; 47d722e3fbSopenharmony_ci if (!drmHashLookup(tbl, key, (void **)&bo)) { 48d722e3fbSopenharmony_ci /* found, incr refcnt and return: */ 49d722e3fbSopenharmony_ci bo = fd_bo_ref(bo); 50d722e3fbSopenharmony_ci 51d722e3fbSopenharmony_ci /* don't break the bucket if this bo was found in one */ 52d722e3fbSopenharmony_ci list_delinit(&bo->list); 53d722e3fbSopenharmony_ci } 54d722e3fbSopenharmony_ci return bo; 55d722e3fbSopenharmony_ci} 56d722e3fbSopenharmony_ci 57d722e3fbSopenharmony_ci/* allocate a new buffer object, call w/ table_lock held */ 58d722e3fbSopenharmony_cistatic struct fd_bo * bo_from_handle(struct fd_device *dev, 59d722e3fbSopenharmony_ci uint32_t size, uint32_t handle) 60d722e3fbSopenharmony_ci{ 61d722e3fbSopenharmony_ci struct fd_bo *bo; 62d722e3fbSopenharmony_ci 63d722e3fbSopenharmony_ci bo = dev->funcs->bo_from_handle(dev, size, handle); 64d722e3fbSopenharmony_ci if (!bo) { 65d722e3fbSopenharmony_ci drmCloseBufferHandle(dev->fd, handle); 66d722e3fbSopenharmony_ci return NULL; 67d722e3fbSopenharmony_ci } 68d722e3fbSopenharmony_ci bo->dev = fd_device_ref(dev); 69d722e3fbSopenharmony_ci bo->size = size; 70d722e3fbSopenharmony_ci bo->handle = handle; 71d722e3fbSopenharmony_ci atomic_set(&bo->refcnt, 1); 72d722e3fbSopenharmony_ci list_inithead(&bo->list); 73d722e3fbSopenharmony_ci /* add ourself into the handle table: */ 74d722e3fbSopenharmony_ci drmHashInsert(dev->handle_table, handle, bo); 75d722e3fbSopenharmony_ci return bo; 76d722e3fbSopenharmony_ci} 77d722e3fbSopenharmony_ci 78d722e3fbSopenharmony_cistatic struct fd_bo * 79d722e3fbSopenharmony_cibo_new(struct fd_device *dev, uint32_t size, uint32_t flags, 80d722e3fbSopenharmony_ci struct fd_bo_cache *cache) 81d722e3fbSopenharmony_ci{ 82d722e3fbSopenharmony_ci struct fd_bo *bo = NULL; 83d722e3fbSopenharmony_ci uint32_t handle; 84d722e3fbSopenharmony_ci int ret; 85d722e3fbSopenharmony_ci 86d722e3fbSopenharmony_ci bo = fd_bo_cache_alloc(cache, &size, flags); 87d722e3fbSopenharmony_ci if (bo) 88d722e3fbSopenharmony_ci return bo; 89d722e3fbSopenharmony_ci 90d722e3fbSopenharmony_ci ret = dev->funcs->bo_new_handle(dev, size, flags, &handle); 91d722e3fbSopenharmony_ci if (ret) 92d722e3fbSopenharmony_ci return NULL; 93d722e3fbSopenharmony_ci 94d722e3fbSopenharmony_ci pthread_mutex_lock(&table_lock); 95d722e3fbSopenharmony_ci bo = bo_from_handle(dev, size, handle); 96d722e3fbSopenharmony_ci pthread_mutex_unlock(&table_lock); 97d722e3fbSopenharmony_ci 98d722e3fbSopenharmony_ci VG_BO_ALLOC(bo); 99d722e3fbSopenharmony_ci 100d722e3fbSopenharmony_ci return bo; 101d722e3fbSopenharmony_ci} 102d722e3fbSopenharmony_ci 103d722e3fbSopenharmony_cidrm_public struct fd_bo * 104d722e3fbSopenharmony_cifd_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags) 105d722e3fbSopenharmony_ci{ 106d722e3fbSopenharmony_ci struct fd_bo *bo = bo_new(dev, size, flags, &dev->bo_cache); 107d722e3fbSopenharmony_ci if (bo) 108d722e3fbSopenharmony_ci bo->bo_reuse = BO_CACHE; 109d722e3fbSopenharmony_ci return bo; 110d722e3fbSopenharmony_ci} 111d722e3fbSopenharmony_ci 112d722e3fbSopenharmony_ci/* internal function to allocate bo's that use the ringbuffer cache 113d722e3fbSopenharmony_ci * instead of the normal bo_cache. The purpose is, because cmdstream 114d722e3fbSopenharmony_ci * bo's get vmap'd on the kernel side, and that is expensive, we want 115d722e3fbSopenharmony_ci * to re-use cmdstream bo's for cmdstream and not unrelated purposes. 116d722e3fbSopenharmony_ci */ 117d722e3fbSopenharmony_cidrm_private struct fd_bo * 118d722e3fbSopenharmony_cifd_bo_new_ring(struct fd_device *dev, uint32_t size, uint32_t flags) 119d722e3fbSopenharmony_ci{ 120d722e3fbSopenharmony_ci struct fd_bo *bo = bo_new(dev, size, flags, &dev->ring_cache); 121d722e3fbSopenharmony_ci if (bo) 122d722e3fbSopenharmony_ci bo->bo_reuse = RING_CACHE; 123d722e3fbSopenharmony_ci return bo; 124d722e3fbSopenharmony_ci} 125d722e3fbSopenharmony_ci 126d722e3fbSopenharmony_cidrm_public struct fd_bo * 127d722e3fbSopenharmony_cifd_bo_from_handle(struct fd_device *dev, uint32_t handle, uint32_t size) 128d722e3fbSopenharmony_ci{ 129d722e3fbSopenharmony_ci struct fd_bo *bo = NULL; 130d722e3fbSopenharmony_ci 131d722e3fbSopenharmony_ci pthread_mutex_lock(&table_lock); 132d722e3fbSopenharmony_ci 133d722e3fbSopenharmony_ci bo = lookup_bo(dev->handle_table, handle); 134d722e3fbSopenharmony_ci if (bo) 135d722e3fbSopenharmony_ci goto out_unlock; 136d722e3fbSopenharmony_ci 137d722e3fbSopenharmony_ci bo = bo_from_handle(dev, size, handle); 138d722e3fbSopenharmony_ci 139d722e3fbSopenharmony_ci VG_BO_ALLOC(bo); 140d722e3fbSopenharmony_ci 141d722e3fbSopenharmony_ciout_unlock: 142d722e3fbSopenharmony_ci pthread_mutex_unlock(&table_lock); 143d722e3fbSopenharmony_ci 144d722e3fbSopenharmony_ci return bo; 145d722e3fbSopenharmony_ci} 146d722e3fbSopenharmony_ci 147d722e3fbSopenharmony_cidrm_public struct fd_bo * 148d722e3fbSopenharmony_cifd_bo_from_dmabuf(struct fd_device *dev, int fd) 149d722e3fbSopenharmony_ci{ 150d722e3fbSopenharmony_ci int ret, size; 151d722e3fbSopenharmony_ci uint32_t handle; 152d722e3fbSopenharmony_ci struct fd_bo *bo; 153d722e3fbSopenharmony_ci 154d722e3fbSopenharmony_ci pthread_mutex_lock(&table_lock); 155d722e3fbSopenharmony_ci ret = drmPrimeFDToHandle(dev->fd, fd, &handle); 156d722e3fbSopenharmony_ci if (ret) { 157d722e3fbSopenharmony_ci pthread_mutex_unlock(&table_lock); 158d722e3fbSopenharmony_ci return NULL; 159d722e3fbSopenharmony_ci } 160d722e3fbSopenharmony_ci 161d722e3fbSopenharmony_ci bo = lookup_bo(dev->handle_table, handle); 162d722e3fbSopenharmony_ci if (bo) 163d722e3fbSopenharmony_ci goto out_unlock; 164d722e3fbSopenharmony_ci 165d722e3fbSopenharmony_ci /* lseek() to get bo size */ 166d722e3fbSopenharmony_ci size = lseek(fd, 0, SEEK_END); 167d722e3fbSopenharmony_ci lseek(fd, 0, SEEK_CUR); 168d722e3fbSopenharmony_ci 169d722e3fbSopenharmony_ci bo = bo_from_handle(dev, size, handle); 170d722e3fbSopenharmony_ci 171d722e3fbSopenharmony_ci VG_BO_ALLOC(bo); 172d722e3fbSopenharmony_ci 173d722e3fbSopenharmony_ciout_unlock: 174d722e3fbSopenharmony_ci pthread_mutex_unlock(&table_lock); 175d722e3fbSopenharmony_ci 176d722e3fbSopenharmony_ci return bo; 177d722e3fbSopenharmony_ci} 178d722e3fbSopenharmony_ci 179d722e3fbSopenharmony_cidrm_public struct fd_bo * fd_bo_from_name(struct fd_device *dev, uint32_t name) 180d722e3fbSopenharmony_ci{ 181d722e3fbSopenharmony_ci struct drm_gem_open req = { 182d722e3fbSopenharmony_ci .name = name, 183d722e3fbSopenharmony_ci }; 184d722e3fbSopenharmony_ci struct fd_bo *bo; 185d722e3fbSopenharmony_ci 186d722e3fbSopenharmony_ci pthread_mutex_lock(&table_lock); 187d722e3fbSopenharmony_ci 188d722e3fbSopenharmony_ci /* check name table first, to see if bo is already open: */ 189d722e3fbSopenharmony_ci bo = lookup_bo(dev->name_table, name); 190d722e3fbSopenharmony_ci if (bo) 191d722e3fbSopenharmony_ci goto out_unlock; 192d722e3fbSopenharmony_ci 193d722e3fbSopenharmony_ci if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) { 194d722e3fbSopenharmony_ci ERROR_MSG("gem-open failed: %s", strerror(errno)); 195d722e3fbSopenharmony_ci goto out_unlock; 196d722e3fbSopenharmony_ci } 197d722e3fbSopenharmony_ci 198d722e3fbSopenharmony_ci bo = lookup_bo(dev->handle_table, req.handle); 199d722e3fbSopenharmony_ci if (bo) 200d722e3fbSopenharmony_ci goto out_unlock; 201d722e3fbSopenharmony_ci 202d722e3fbSopenharmony_ci bo = bo_from_handle(dev, req.size, req.handle); 203d722e3fbSopenharmony_ci if (bo) { 204d722e3fbSopenharmony_ci set_name(bo, name); 205d722e3fbSopenharmony_ci VG_BO_ALLOC(bo); 206d722e3fbSopenharmony_ci } 207d722e3fbSopenharmony_ci 208d722e3fbSopenharmony_ciout_unlock: 209d722e3fbSopenharmony_ci pthread_mutex_unlock(&table_lock); 210d722e3fbSopenharmony_ci 211d722e3fbSopenharmony_ci return bo; 212d722e3fbSopenharmony_ci} 213d722e3fbSopenharmony_ci 214d722e3fbSopenharmony_cidrm_public uint64_t fd_bo_get_iova(struct fd_bo *bo) 215d722e3fbSopenharmony_ci{ 216d722e3fbSopenharmony_ci return bo->funcs->iova(bo); 217d722e3fbSopenharmony_ci} 218d722e3fbSopenharmony_ci 219d722e3fbSopenharmony_cidrm_public void fd_bo_put_iova(struct fd_bo *bo) 220d722e3fbSopenharmony_ci{ 221d722e3fbSopenharmony_ci /* currently a no-op */ 222d722e3fbSopenharmony_ci} 223d722e3fbSopenharmony_ci 224d722e3fbSopenharmony_cidrm_public struct fd_bo * fd_bo_ref(struct fd_bo *bo) 225d722e3fbSopenharmony_ci{ 226d722e3fbSopenharmony_ci atomic_inc(&bo->refcnt); 227d722e3fbSopenharmony_ci return bo; 228d722e3fbSopenharmony_ci} 229d722e3fbSopenharmony_ci 230d722e3fbSopenharmony_cidrm_public void fd_bo_del(struct fd_bo *bo) 231d722e3fbSopenharmony_ci{ 232d722e3fbSopenharmony_ci struct fd_device *dev = bo->dev; 233d722e3fbSopenharmony_ci 234d722e3fbSopenharmony_ci if (!atomic_dec_and_test(&bo->refcnt)) 235d722e3fbSopenharmony_ci return; 236d722e3fbSopenharmony_ci 237d722e3fbSopenharmony_ci pthread_mutex_lock(&table_lock); 238d722e3fbSopenharmony_ci 239d722e3fbSopenharmony_ci if ((bo->bo_reuse == BO_CACHE) && (fd_bo_cache_free(&dev->bo_cache, bo) == 0)) 240d722e3fbSopenharmony_ci goto out; 241d722e3fbSopenharmony_ci if ((bo->bo_reuse == RING_CACHE) && (fd_bo_cache_free(&dev->ring_cache, bo) == 0)) 242d722e3fbSopenharmony_ci goto out; 243d722e3fbSopenharmony_ci 244d722e3fbSopenharmony_ci bo_del(bo); 245d722e3fbSopenharmony_ci fd_device_del_locked(dev); 246d722e3fbSopenharmony_ciout: 247d722e3fbSopenharmony_ci pthread_mutex_unlock(&table_lock); 248d722e3fbSopenharmony_ci} 249d722e3fbSopenharmony_ci 250d722e3fbSopenharmony_ci/* Called under table_lock */ 251d722e3fbSopenharmony_cidrm_private void bo_del(struct fd_bo *bo) 252d722e3fbSopenharmony_ci{ 253d722e3fbSopenharmony_ci VG_BO_FREE(bo); 254d722e3fbSopenharmony_ci 255d722e3fbSopenharmony_ci if (bo->map) 256d722e3fbSopenharmony_ci drm_munmap(bo->map, bo->size); 257d722e3fbSopenharmony_ci 258d722e3fbSopenharmony_ci /* TODO probably bo's in bucket list get removed from 259d722e3fbSopenharmony_ci * handle table?? 260d722e3fbSopenharmony_ci */ 261d722e3fbSopenharmony_ci 262d722e3fbSopenharmony_ci if (bo->handle) { 263d722e3fbSopenharmony_ci drmHashDelete(bo->dev->handle_table, bo->handle); 264d722e3fbSopenharmony_ci if (bo->name) 265d722e3fbSopenharmony_ci drmHashDelete(bo->dev->name_table, bo->name); 266d722e3fbSopenharmony_ci drmCloseBufferHandle(bo->dev->fd, bo->handle); 267d722e3fbSopenharmony_ci } 268d722e3fbSopenharmony_ci 269d722e3fbSopenharmony_ci bo->funcs->destroy(bo); 270d722e3fbSopenharmony_ci} 271d722e3fbSopenharmony_ci 272d722e3fbSopenharmony_cidrm_public int fd_bo_get_name(struct fd_bo *bo, uint32_t *name) 273d722e3fbSopenharmony_ci{ 274d722e3fbSopenharmony_ci if (!bo->name) { 275d722e3fbSopenharmony_ci struct drm_gem_flink req = { 276d722e3fbSopenharmony_ci .handle = bo->handle, 277d722e3fbSopenharmony_ci }; 278d722e3fbSopenharmony_ci int ret; 279d722e3fbSopenharmony_ci 280d722e3fbSopenharmony_ci ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req); 281d722e3fbSopenharmony_ci if (ret) { 282d722e3fbSopenharmony_ci return ret; 283d722e3fbSopenharmony_ci } 284d722e3fbSopenharmony_ci 285d722e3fbSopenharmony_ci pthread_mutex_lock(&table_lock); 286d722e3fbSopenharmony_ci set_name(bo, req.name); 287d722e3fbSopenharmony_ci pthread_mutex_unlock(&table_lock); 288d722e3fbSopenharmony_ci bo->bo_reuse = NO_CACHE; 289d722e3fbSopenharmony_ci } 290d722e3fbSopenharmony_ci 291d722e3fbSopenharmony_ci *name = bo->name; 292d722e3fbSopenharmony_ci 293d722e3fbSopenharmony_ci return 0; 294d722e3fbSopenharmony_ci} 295d722e3fbSopenharmony_ci 296d722e3fbSopenharmony_cidrm_public uint32_t fd_bo_handle(struct fd_bo *bo) 297d722e3fbSopenharmony_ci{ 298d722e3fbSopenharmony_ci return bo->handle; 299d722e3fbSopenharmony_ci} 300d722e3fbSopenharmony_ci 301d722e3fbSopenharmony_cidrm_public int fd_bo_dmabuf(struct fd_bo *bo) 302d722e3fbSopenharmony_ci{ 303d722e3fbSopenharmony_ci int ret, prime_fd; 304d722e3fbSopenharmony_ci 305d722e3fbSopenharmony_ci ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC, 306d722e3fbSopenharmony_ci &prime_fd); 307d722e3fbSopenharmony_ci if (ret) { 308d722e3fbSopenharmony_ci ERROR_MSG("failed to get dmabuf fd: %d", ret); 309d722e3fbSopenharmony_ci return ret; 310d722e3fbSopenharmony_ci } 311d722e3fbSopenharmony_ci 312d722e3fbSopenharmony_ci bo->bo_reuse = NO_CACHE; 313d722e3fbSopenharmony_ci 314d722e3fbSopenharmony_ci return prime_fd; 315d722e3fbSopenharmony_ci} 316d722e3fbSopenharmony_ci 317d722e3fbSopenharmony_cidrm_public uint32_t fd_bo_size(struct fd_bo *bo) 318d722e3fbSopenharmony_ci{ 319d722e3fbSopenharmony_ci return bo->size; 320d722e3fbSopenharmony_ci} 321d722e3fbSopenharmony_ci 322d722e3fbSopenharmony_cidrm_public void * fd_bo_map(struct fd_bo *bo) 323d722e3fbSopenharmony_ci{ 324d722e3fbSopenharmony_ci if (!bo->map) { 325d722e3fbSopenharmony_ci uint64_t offset; 326d722e3fbSopenharmony_ci int ret; 327d722e3fbSopenharmony_ci 328d722e3fbSopenharmony_ci ret = bo->funcs->offset(bo, &offset); 329d722e3fbSopenharmony_ci if (ret) { 330d722e3fbSopenharmony_ci return NULL; 331d722e3fbSopenharmony_ci } 332d722e3fbSopenharmony_ci 333d722e3fbSopenharmony_ci bo->map = drm_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, 334d722e3fbSopenharmony_ci bo->dev->fd, offset); 335d722e3fbSopenharmony_ci if (bo->map == MAP_FAILED) { 336d722e3fbSopenharmony_ci ERROR_MSG("mmap failed: %s", strerror(errno)); 337d722e3fbSopenharmony_ci bo->map = NULL; 338d722e3fbSopenharmony_ci } 339d722e3fbSopenharmony_ci } 340d722e3fbSopenharmony_ci return bo->map; 341d722e3fbSopenharmony_ci} 342d722e3fbSopenharmony_ci 343d722e3fbSopenharmony_ci/* a bit odd to take the pipe as an arg, but it's a, umm, quirk of kgsl.. */ 344d722e3fbSopenharmony_cidrm_public int fd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op) 345d722e3fbSopenharmony_ci{ 346d722e3fbSopenharmony_ci return bo->funcs->cpu_prep(bo, pipe, op); 347d722e3fbSopenharmony_ci} 348d722e3fbSopenharmony_ci 349d722e3fbSopenharmony_cidrm_public void fd_bo_cpu_fini(struct fd_bo *bo) 350d722e3fbSopenharmony_ci{ 351d722e3fbSopenharmony_ci bo->funcs->cpu_fini(bo); 352d722e3fbSopenharmony_ci} 353d722e3fbSopenharmony_ci 354d722e3fbSopenharmony_ci#if !HAVE_FREEDRENO_KGSL 355d722e3fbSopenharmony_cidrm_public struct fd_bo * fd_bo_from_fbdev(struct fd_pipe *pipe, int fbfd, uint32_t size) 356d722e3fbSopenharmony_ci{ 357d722e3fbSopenharmony_ci return NULL; 358d722e3fbSopenharmony_ci} 359d722e3fbSopenharmony_ci#endif 360