1b8e80941Smrg/* 2b8e80941Smrg * Copyright (C) 2017-2019 Lima Project 3b8e80941Smrg * 4b8e80941Smrg * Permission is hereby granted, free of charge, to any person obtaining a 5b8e80941Smrg * copy of this software and associated documentation files (the "Software"), 6b8e80941Smrg * to deal in the Software without restriction, including without limitation 7b8e80941Smrg * the rights to use, copy, modify, merge, publish, distribute, sublicense, 8b8e80941Smrg * and/or sell copies of the Software, and to permit persons to whom the 9b8e80941Smrg * Software is furnished to do so, subject to the following conditions: 10b8e80941Smrg * 11b8e80941Smrg * The above copyright notice and this permission notice shall be included in 12b8e80941Smrg * all copies or substantial portions of the Software. 13b8e80941Smrg * 14b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 15b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 17b8e80941Smrg * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR 18b8e80941Smrg * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, 19b8e80941Smrg * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR 20b8e80941Smrg * OTHER DEALINGS IN THE SOFTWARE. 21b8e80941Smrg * 22b8e80941Smrg */ 23b8e80941Smrg 24b8e80941Smrg#include <stdlib.h> 25b8e80941Smrg#include <sys/types.h> 26b8e80941Smrg#include <unistd.h> 27b8e80941Smrg#include <fcntl.h> 28b8e80941Smrg 29b8e80941Smrg#include "xf86drm.h" 30b8e80941Smrg#include "drm-uapi/lima_drm.h" 31b8e80941Smrg 32b8e80941Smrg#include "util/u_hash_table.h" 33b8e80941Smrg#include "util/os_time.h" 34b8e80941Smrg#include "os/os_mman.h" 35b8e80941Smrg 36b8e80941Smrg#include "state_tracker/drm_driver.h" 37b8e80941Smrg 38b8e80941Smrg#include "lima_screen.h" 39b8e80941Smrg#include "lima_bo.h" 40b8e80941Smrg 41b8e80941Smrg#define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x))) 42b8e80941Smrg 43b8e80941Smrgstatic unsigned handle_hash(void *key) 44b8e80941Smrg{ 45b8e80941Smrg return PTR_TO_UINT(key); 46b8e80941Smrg} 47b8e80941Smrg 48b8e80941Smrgstatic int handle_compare(void *key1, void *key2) 49b8e80941Smrg{ 50b8e80941Smrg return PTR_TO_UINT(key1) != PTR_TO_UINT(key2); 51b8e80941Smrg} 52b8e80941Smrg 53b8e80941Smrgbool lima_bo_table_init(struct lima_screen *screen) 54b8e80941Smrg{ 55b8e80941Smrg screen->bo_handles = util_hash_table_create(handle_hash, handle_compare); 56b8e80941Smrg if (!screen->bo_handles) 57b8e80941Smrg return false; 58b8e80941Smrg 59b8e80941Smrg screen->bo_flink_names = util_hash_table_create(handle_hash, handle_compare); 60b8e80941Smrg if (!screen->bo_flink_names) 61b8e80941Smrg goto err_out0; 62b8e80941Smrg 63b8e80941Smrg mtx_init(&screen->bo_table_lock, mtx_plain); 64b8e80941Smrg return true; 65b8e80941Smrg 66b8e80941Smrgerr_out0: 67b8e80941Smrg util_hash_table_destroy(screen->bo_handles); 68b8e80941Smrg return false; 69b8e80941Smrg} 70b8e80941Smrg 71b8e80941Smrgvoid lima_bo_table_fini(struct lima_screen *screen) 72b8e80941Smrg{ 73b8e80941Smrg mtx_destroy(&screen->bo_table_lock); 74b8e80941Smrg util_hash_table_destroy(screen->bo_handles); 75b8e80941Smrg util_hash_table_destroy(screen->bo_flink_names); 76b8e80941Smrg} 77b8e80941Smrg 78b8e80941Smrgstatic void lima_close_kms_handle(struct lima_screen *screen, uint32_t handle) 79b8e80941Smrg{ 80b8e80941Smrg struct drm_gem_close args = { 81b8e80941Smrg .handle = handle, 82b8e80941Smrg }; 83b8e80941Smrg 84b8e80941Smrg drmIoctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &args); 85b8e80941Smrg} 86b8e80941Smrg 87b8e80941Smrgstatic bool lima_bo_get_info(struct lima_bo *bo) 88b8e80941Smrg{ 89b8e80941Smrg struct drm_lima_gem_info req = { 90b8e80941Smrg .handle = bo->handle, 91b8e80941Smrg }; 92b8e80941Smrg 93b8e80941Smrg if(drmIoctl(bo->screen->fd, DRM_IOCTL_LIMA_GEM_INFO, &req)) 94b8e80941Smrg return false; 95b8e80941Smrg 96b8e80941Smrg bo->offset = req.offset; 97b8e80941Smrg bo->va = req.va; 98b8e80941Smrg return true; 99b8e80941Smrg} 100b8e80941Smrg 101b8e80941Smrgstruct lima_bo *lima_bo_create(struct lima_screen *screen, 102b8e80941Smrg uint32_t size, uint32_t flags) 103b8e80941Smrg{ 104b8e80941Smrg struct lima_bo *bo; 105b8e80941Smrg struct drm_lima_gem_create req = { 106b8e80941Smrg .size = size, 107b8e80941Smrg .flags = flags, 108b8e80941Smrg }; 109b8e80941Smrg 110b8e80941Smrg if (!(bo = calloc(1, sizeof(*bo)))) 111b8e80941Smrg return NULL; 112b8e80941Smrg 113b8e80941Smrg if (drmIoctl(screen->fd, DRM_IOCTL_LIMA_GEM_CREATE, &req)) 114b8e80941Smrg goto err_out0; 115b8e80941Smrg 116b8e80941Smrg bo->screen = screen; 117b8e80941Smrg bo->size = req.size; 118b8e80941Smrg bo->handle = req.handle; 119b8e80941Smrg p_atomic_set(&bo->refcnt, 1); 120b8e80941Smrg 121b8e80941Smrg if (!lima_bo_get_info(bo)) 122b8e80941Smrg goto err_out1; 123b8e80941Smrg 124b8e80941Smrg return bo; 125b8e80941Smrg 126b8e80941Smrgerr_out1: 127b8e80941Smrg lima_close_kms_handle(screen, bo->handle); 128b8e80941Smrgerr_out0: 129b8e80941Smrg free(bo); 130b8e80941Smrg return NULL; 131b8e80941Smrg} 132b8e80941Smrg 133b8e80941Smrgvoid lima_bo_free(struct lima_bo *bo) 134b8e80941Smrg{ 135b8e80941Smrg if (!p_atomic_dec_zero(&bo->refcnt)) 136b8e80941Smrg return; 137b8e80941Smrg 138b8e80941Smrg struct lima_screen *screen = bo->screen; 139b8e80941Smrg mtx_lock(&screen->bo_table_lock); 140b8e80941Smrg util_hash_table_remove(screen->bo_handles, 141b8e80941Smrg (void *)(uintptr_t)bo->handle); 142b8e80941Smrg if (bo->flink_name) 143b8e80941Smrg util_hash_table_remove(screen->bo_flink_names, 144b8e80941Smrg (void *)(uintptr_t)bo->flink_name); 145b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 146b8e80941Smrg 147b8e80941Smrg if (bo->map) 148b8e80941Smrg lima_bo_unmap(bo); 149b8e80941Smrg 150b8e80941Smrg lima_close_kms_handle(screen, bo->handle); 151b8e80941Smrg free(bo); 152b8e80941Smrg} 153b8e80941Smrg 154b8e80941Smrgvoid *lima_bo_map(struct lima_bo *bo) 155b8e80941Smrg{ 156b8e80941Smrg if (!bo->map) { 157b8e80941Smrg bo->map = os_mmap(0, bo->size, PROT_READ | PROT_WRITE, 158b8e80941Smrg MAP_SHARED, bo->screen->fd, bo->offset); 159b8e80941Smrg if (bo->map == MAP_FAILED) 160b8e80941Smrg bo->map = NULL; 161b8e80941Smrg } 162b8e80941Smrg 163b8e80941Smrg return bo->map; 164b8e80941Smrg} 165b8e80941Smrg 166b8e80941Smrgvoid lima_bo_unmap(struct lima_bo *bo) 167b8e80941Smrg{ 168b8e80941Smrg if (bo->map) { 169b8e80941Smrg os_munmap(bo->map, bo->size); 170b8e80941Smrg bo->map = NULL; 171b8e80941Smrg } 172b8e80941Smrg} 173b8e80941Smrg 174b8e80941Smrgbool lima_bo_export(struct lima_bo *bo, struct winsys_handle *handle) 175b8e80941Smrg{ 176b8e80941Smrg struct lima_screen *screen = bo->screen; 177b8e80941Smrg 178b8e80941Smrg switch (handle->type) { 179b8e80941Smrg case WINSYS_HANDLE_TYPE_SHARED: 180b8e80941Smrg if (!bo->flink_name) { 181b8e80941Smrg struct drm_gem_flink flink = { 182b8e80941Smrg .handle = bo->handle, 183b8e80941Smrg .name = 0, 184b8e80941Smrg }; 185b8e80941Smrg if (drmIoctl(screen->fd, DRM_IOCTL_GEM_FLINK, &flink)) 186b8e80941Smrg return false; 187b8e80941Smrg 188b8e80941Smrg bo->flink_name = flink.name; 189b8e80941Smrg 190b8e80941Smrg mtx_lock(&screen->bo_table_lock); 191b8e80941Smrg util_hash_table_set(screen->bo_flink_names, 192b8e80941Smrg (void *)(uintptr_t)bo->flink_name, bo); 193b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 194b8e80941Smrg } 195b8e80941Smrg handle->handle = bo->flink_name; 196b8e80941Smrg return true; 197b8e80941Smrg 198b8e80941Smrg case WINSYS_HANDLE_TYPE_KMS: 199b8e80941Smrg mtx_lock(&screen->bo_table_lock); 200b8e80941Smrg util_hash_table_set(screen->bo_handles, 201b8e80941Smrg (void *)(uintptr_t)bo->handle, bo); 202b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 203b8e80941Smrg 204b8e80941Smrg handle->handle = bo->handle; 205b8e80941Smrg return true; 206b8e80941Smrg 207b8e80941Smrg case WINSYS_HANDLE_TYPE_FD: 208b8e80941Smrg if (drmPrimeHandleToFD(screen->fd, bo->handle, DRM_CLOEXEC, 209b8e80941Smrg (int*)&handle->handle)) 210b8e80941Smrg return false; 211b8e80941Smrg 212b8e80941Smrg mtx_lock(&screen->bo_table_lock); 213b8e80941Smrg util_hash_table_set(screen->bo_handles, 214b8e80941Smrg (void *)(uintptr_t)bo->handle, bo); 215b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 216b8e80941Smrg return true; 217b8e80941Smrg 218b8e80941Smrg default: 219b8e80941Smrg return false; 220b8e80941Smrg } 221b8e80941Smrg} 222b8e80941Smrg 223b8e80941Smrgstruct lima_bo *lima_bo_import(struct lima_screen *screen, 224b8e80941Smrg struct winsys_handle *handle) 225b8e80941Smrg{ 226b8e80941Smrg struct lima_bo *bo = NULL; 227b8e80941Smrg struct drm_gem_open req = {0}; 228b8e80941Smrg uint32_t dma_buf_size = 0; 229b8e80941Smrg unsigned h = handle->handle; 230b8e80941Smrg 231b8e80941Smrg mtx_lock(&screen->bo_table_lock); 232b8e80941Smrg 233b8e80941Smrg /* Convert a DMA buf handle to a KMS handle now. */ 234b8e80941Smrg if (handle->type == WINSYS_HANDLE_TYPE_FD) { 235b8e80941Smrg uint32_t prime_handle; 236b8e80941Smrg off_t size; 237b8e80941Smrg 238b8e80941Smrg /* Get a KMS handle. */ 239b8e80941Smrg if (drmPrimeFDToHandle(screen->fd, h, &prime_handle)) { 240b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 241b8e80941Smrg return NULL; 242b8e80941Smrg } 243b8e80941Smrg 244b8e80941Smrg /* Query the buffer size. */ 245b8e80941Smrg size = lseek(h, 0, SEEK_END); 246b8e80941Smrg if (size == (off_t)-1) { 247b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 248b8e80941Smrg lima_close_kms_handle(screen, prime_handle); 249b8e80941Smrg return NULL; 250b8e80941Smrg } 251b8e80941Smrg lseek(h, 0, SEEK_SET); 252b8e80941Smrg 253b8e80941Smrg dma_buf_size = size; 254b8e80941Smrg h = prime_handle; 255b8e80941Smrg } 256b8e80941Smrg 257b8e80941Smrg switch (handle->type) { 258b8e80941Smrg case WINSYS_HANDLE_TYPE_SHARED: 259b8e80941Smrg bo = util_hash_table_get(screen->bo_flink_names, 260b8e80941Smrg (void *)(uintptr_t)h); 261b8e80941Smrg break; 262b8e80941Smrg case WINSYS_HANDLE_TYPE_KMS: 263b8e80941Smrg case WINSYS_HANDLE_TYPE_FD: 264b8e80941Smrg bo = util_hash_table_get(screen->bo_handles, 265b8e80941Smrg (void *)(uintptr_t)h); 266b8e80941Smrg break; 267b8e80941Smrg default: 268b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 269b8e80941Smrg return NULL; 270b8e80941Smrg } 271b8e80941Smrg 272b8e80941Smrg if (bo) { 273b8e80941Smrg p_atomic_inc(&bo->refcnt); 274b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 275b8e80941Smrg return bo; 276b8e80941Smrg } 277b8e80941Smrg 278b8e80941Smrg if (!(bo = calloc(1, sizeof(*bo)))) { 279b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 280b8e80941Smrg if (handle->type == WINSYS_HANDLE_TYPE_FD) 281b8e80941Smrg lima_close_kms_handle(screen, h); 282b8e80941Smrg return NULL; 283b8e80941Smrg } 284b8e80941Smrg 285b8e80941Smrg bo->screen = screen; 286b8e80941Smrg p_atomic_set(&bo->refcnt, 1); 287b8e80941Smrg 288b8e80941Smrg switch (handle->type) { 289b8e80941Smrg case WINSYS_HANDLE_TYPE_SHARED: 290b8e80941Smrg req.name = h; 291b8e80941Smrg if (drmIoctl(screen->fd, DRM_IOCTL_GEM_OPEN, &req)) { 292b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 293b8e80941Smrg free(bo); 294b8e80941Smrg return NULL; 295b8e80941Smrg } 296b8e80941Smrg bo->handle = req.handle; 297b8e80941Smrg bo->flink_name = h; 298b8e80941Smrg bo->size = req.size; 299b8e80941Smrg break; 300b8e80941Smrg case WINSYS_HANDLE_TYPE_FD: 301b8e80941Smrg bo->handle = h; 302b8e80941Smrg bo->size = dma_buf_size; 303b8e80941Smrg break; 304b8e80941Smrg default: 305b8e80941Smrg /* not possible */ 306b8e80941Smrg assert(0); 307b8e80941Smrg } 308b8e80941Smrg 309b8e80941Smrg if (lima_bo_get_info(bo)) { 310b8e80941Smrg if (handle->type == WINSYS_HANDLE_TYPE_SHARED) 311b8e80941Smrg util_hash_table_set(screen->bo_flink_names, 312b8e80941Smrg (void *)(uintptr_t)bo->flink_name, bo); 313b8e80941Smrg util_hash_table_set(screen->bo_handles, 314b8e80941Smrg (void*)(uintptr_t)bo->handle, bo); 315b8e80941Smrg } 316b8e80941Smrg else { 317b8e80941Smrg lima_close_kms_handle(screen, bo->handle); 318b8e80941Smrg free(bo); 319b8e80941Smrg bo = NULL; 320b8e80941Smrg } 321b8e80941Smrg 322b8e80941Smrg mtx_unlock(&screen->bo_table_lock); 323b8e80941Smrg 324b8e80941Smrg return bo; 325b8e80941Smrg} 326b8e80941Smrg 327b8e80941Smrgbool lima_bo_wait(struct lima_bo *bo, uint32_t op, uint64_t timeout_ns) 328b8e80941Smrg{ 329b8e80941Smrg int64_t abs_timeout = os_time_get_absolute_timeout(timeout_ns); 330b8e80941Smrg struct drm_lima_gem_wait req = { 331b8e80941Smrg .handle = bo->handle, 332b8e80941Smrg .op = op, 333b8e80941Smrg .timeout_ns = abs_timeout, 334b8e80941Smrg }; 335b8e80941Smrg 336b8e80941Smrg return drmIoctl(bo->screen->fd, DRM_IOCTL_LIMA_GEM_WAIT, &req) == 0; 337b8e80941Smrg} 338