1b8e80941Smrg/* 2b8e80941Smrg * Copyright © 2014-2017 Broadcom 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 (including the next 12b8e80941Smrg * paragraph) shall be included in all copies or substantial portions of the 13b8e80941Smrg * Software. 14b8e80941Smrg * 15b8e80941Smrg * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16b8e80941Smrg * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17b8e80941Smrg * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL 18b8e80941Smrg * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19b8e80941Smrg * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20b8e80941Smrg * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21b8e80941Smrg * IN THE SOFTWARE. 22b8e80941Smrg */ 23b8e80941Smrg 24b8e80941Smrg#include <errno.h> 25b8e80941Smrg#include <err.h> 26b8e80941Smrg#include <sys/mman.h> 27b8e80941Smrg#include <fcntl.h> 28b8e80941Smrg#include <xf86drm.h> 29b8e80941Smrg#include <xf86drmMode.h> 30b8e80941Smrg 31b8e80941Smrg#include "util/u_hash_table.h" 32b8e80941Smrg#include "util/u_memory.h" 33b8e80941Smrg#include "util/ralloc.h" 34b8e80941Smrg 35b8e80941Smrg#include "v3d_context.h" 36b8e80941Smrg#include "v3d_screen.h" 37b8e80941Smrg 38b8e80941Smrg#ifdef HAVE_VALGRIND 39b8e80941Smrg#include <valgrind.h> 40b8e80941Smrg#include <memcheck.h> 41b8e80941Smrg#define VG(x) x 42b8e80941Smrg#else 43b8e80941Smrg#define VG(x) 44b8e80941Smrg#endif 45b8e80941Smrg 46b8e80941Smrgstatic bool dump_stats = false; 47b8e80941Smrg 48b8e80941Smrgstatic void 49b8e80941Smrgv3d_bo_cache_free_all(struct v3d_bo_cache *cache); 50b8e80941Smrg 51b8e80941Smrgstatic void 52b8e80941Smrgv3d_bo_dump_stats(struct v3d_screen *screen) 53b8e80941Smrg{ 54b8e80941Smrg struct v3d_bo_cache *cache = &screen->bo_cache; 55b8e80941Smrg 56b8e80941Smrg uint32_t cache_count = 0; 57b8e80941Smrg uint32_t cache_size = 0; 58b8e80941Smrg list_for_each_entry(struct v3d_bo, bo, &cache->time_list, time_list) { 59b8e80941Smrg cache_count++; 60b8e80941Smrg cache_size += bo->size; 61b8e80941Smrg } 62b8e80941Smrg 63b8e80941Smrg fprintf(stderr, " BOs allocated: %d\n", screen->bo_count); 64b8e80941Smrg fprintf(stderr, " BOs size: %dkb\n", screen->bo_size / 1024); 65b8e80941Smrg fprintf(stderr, " BOs cached: %d\n", cache_count); 66b8e80941Smrg fprintf(stderr, " BOs cached size: %dkb\n", cache_size / 1024); 67b8e80941Smrg 68b8e80941Smrg if (!list_empty(&cache->time_list)) { 69b8e80941Smrg struct v3d_bo *first = list_first_entry(&cache->time_list, 70b8e80941Smrg struct v3d_bo, 71b8e80941Smrg time_list); 72b8e80941Smrg struct v3d_bo *last = list_last_entry(&cache->time_list, 73b8e80941Smrg struct v3d_bo, 74b8e80941Smrg time_list); 75b8e80941Smrg 76b8e80941Smrg fprintf(stderr, " oldest cache time: %ld\n", 77b8e80941Smrg (long)first->free_time); 78b8e80941Smrg fprintf(stderr, " newest cache time: %ld\n", 79b8e80941Smrg (long)last->free_time); 80b8e80941Smrg 81b8e80941Smrg struct timespec time; 82b8e80941Smrg clock_gettime(CLOCK_MONOTONIC, &time); 83b8e80941Smrg fprintf(stderr, " now: %ld\n", 84b8e80941Smrg time.tv_sec); 85b8e80941Smrg } 86b8e80941Smrg} 87b8e80941Smrg 88b8e80941Smrgstatic void 89b8e80941Smrgv3d_bo_remove_from_cache(struct v3d_bo_cache *cache, struct v3d_bo *bo) 90b8e80941Smrg{ 91b8e80941Smrg list_del(&bo->time_list); 92b8e80941Smrg list_del(&bo->size_list); 93b8e80941Smrg} 94b8e80941Smrg 95b8e80941Smrgstatic struct v3d_bo * 96b8e80941Smrgv3d_bo_from_cache(struct v3d_screen *screen, uint32_t size, const char *name) 97b8e80941Smrg{ 98b8e80941Smrg struct v3d_bo_cache *cache = &screen->bo_cache; 99b8e80941Smrg uint32_t page_index = size / 4096 - 1; 100b8e80941Smrg 101b8e80941Smrg if (cache->size_list_size <= page_index) 102b8e80941Smrg return NULL; 103b8e80941Smrg 104b8e80941Smrg struct v3d_bo *bo = NULL; 105b8e80941Smrg mtx_lock(&cache->lock); 106b8e80941Smrg if (!list_empty(&cache->size_list[page_index])) { 107b8e80941Smrg bo = list_first_entry(&cache->size_list[page_index], 108b8e80941Smrg struct v3d_bo, size_list); 109b8e80941Smrg 110b8e80941Smrg /* Check that the BO has gone idle. If not, then we want to 111b8e80941Smrg * allocate something new instead, since we assume that the 112b8e80941Smrg * user will proceed to CPU map it and fill it with stuff. 113b8e80941Smrg */ 114b8e80941Smrg if (!v3d_bo_wait(bo, 0, NULL)) { 115b8e80941Smrg mtx_unlock(&cache->lock); 116b8e80941Smrg return NULL; 117b8e80941Smrg } 118b8e80941Smrg 119b8e80941Smrg pipe_reference_init(&bo->reference, 1); 120b8e80941Smrg v3d_bo_remove_from_cache(cache, bo); 121b8e80941Smrg 122b8e80941Smrg bo->name = name; 123b8e80941Smrg } 124b8e80941Smrg mtx_unlock(&cache->lock); 125b8e80941Smrg return bo; 126b8e80941Smrg} 127b8e80941Smrg 128b8e80941Smrgstruct v3d_bo * 129b8e80941Smrgv3d_bo_alloc(struct v3d_screen *screen, uint32_t size, const char *name) 130b8e80941Smrg{ 131b8e80941Smrg struct v3d_bo *bo; 132b8e80941Smrg int ret; 133b8e80941Smrg 134b8e80941Smrg /* The CLIF dumping requires that there is no whitespace in the name. 135b8e80941Smrg */ 136b8e80941Smrg assert(!strchr(name, ' ')); 137b8e80941Smrg 138b8e80941Smrg size = align(size, 4096); 139b8e80941Smrg 140b8e80941Smrg bo = v3d_bo_from_cache(screen, size, name); 141b8e80941Smrg if (bo) { 142b8e80941Smrg if (dump_stats) { 143b8e80941Smrg fprintf(stderr, "Allocated %s %dkb from cache:\n", 144b8e80941Smrg name, size / 1024); 145b8e80941Smrg v3d_bo_dump_stats(screen); 146b8e80941Smrg } 147b8e80941Smrg return bo; 148b8e80941Smrg } 149b8e80941Smrg 150b8e80941Smrg bo = CALLOC_STRUCT(v3d_bo); 151b8e80941Smrg if (!bo) 152b8e80941Smrg return NULL; 153b8e80941Smrg 154b8e80941Smrg pipe_reference_init(&bo->reference, 1); 155b8e80941Smrg bo->screen = screen; 156b8e80941Smrg bo->size = size; 157b8e80941Smrg bo->name = name; 158b8e80941Smrg bo->private = true; 159b8e80941Smrg 160b8e80941Smrg retry: 161b8e80941Smrg ; 162b8e80941Smrg 163b8e80941Smrg bool cleared_and_retried = false; 164b8e80941Smrg struct drm_v3d_create_bo create = { 165b8e80941Smrg .size = size 166b8e80941Smrg }; 167b8e80941Smrg 168b8e80941Smrg ret = v3d_ioctl(screen->fd, DRM_IOCTL_V3D_CREATE_BO, &create); 169b8e80941Smrg bo->handle = create.handle; 170b8e80941Smrg bo->offset = create.offset; 171b8e80941Smrg 172b8e80941Smrg if (ret != 0) { 173b8e80941Smrg if (!list_empty(&screen->bo_cache.time_list) && 174b8e80941Smrg !cleared_and_retried) { 175b8e80941Smrg cleared_and_retried = true; 176b8e80941Smrg v3d_bo_cache_free_all(&screen->bo_cache); 177b8e80941Smrg goto retry; 178b8e80941Smrg } 179b8e80941Smrg 180b8e80941Smrg free(bo); 181b8e80941Smrg return NULL; 182b8e80941Smrg } 183b8e80941Smrg 184b8e80941Smrg screen->bo_count++; 185b8e80941Smrg screen->bo_size += bo->size; 186b8e80941Smrg if (dump_stats) { 187b8e80941Smrg fprintf(stderr, "Allocated %s %dkb:\n", name, size / 1024); 188b8e80941Smrg v3d_bo_dump_stats(screen); 189b8e80941Smrg } 190b8e80941Smrg 191b8e80941Smrg return bo; 192b8e80941Smrg} 193b8e80941Smrg 194b8e80941Smrgvoid 195b8e80941Smrgv3d_bo_last_unreference(struct v3d_bo *bo) 196b8e80941Smrg{ 197b8e80941Smrg struct v3d_screen *screen = bo->screen; 198b8e80941Smrg 199b8e80941Smrg struct timespec time; 200b8e80941Smrg clock_gettime(CLOCK_MONOTONIC, &time); 201b8e80941Smrg mtx_lock(&screen->bo_cache.lock); 202b8e80941Smrg v3d_bo_last_unreference_locked_timed(bo, time.tv_sec); 203b8e80941Smrg mtx_unlock(&screen->bo_cache.lock); 204b8e80941Smrg} 205b8e80941Smrg 206b8e80941Smrgstatic void 207b8e80941Smrgv3d_bo_free(struct v3d_bo *bo) 208b8e80941Smrg{ 209b8e80941Smrg struct v3d_screen *screen = bo->screen; 210b8e80941Smrg 211b8e80941Smrg if (bo->map) { 212b8e80941Smrg if (using_v3d_simulator && bo->name && 213b8e80941Smrg strcmp(bo->name, "winsys") == 0) { 214b8e80941Smrg free(bo->map); 215b8e80941Smrg } else { 216b8e80941Smrg munmap(bo->map, bo->size); 217b8e80941Smrg VG(VALGRIND_FREELIKE_BLOCK(bo->map, 0)); 218b8e80941Smrg } 219b8e80941Smrg } 220b8e80941Smrg 221b8e80941Smrg struct drm_gem_close c; 222b8e80941Smrg memset(&c, 0, sizeof(c)); 223b8e80941Smrg c.handle = bo->handle; 224b8e80941Smrg int ret = v3d_ioctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &c); 225b8e80941Smrg if (ret != 0) 226b8e80941Smrg fprintf(stderr, "close object %d: %s\n", bo->handle, strerror(errno)); 227b8e80941Smrg 228b8e80941Smrg screen->bo_count--; 229b8e80941Smrg screen->bo_size -= bo->size; 230b8e80941Smrg 231b8e80941Smrg if (dump_stats) { 232b8e80941Smrg fprintf(stderr, "Freed %s%s%dkb:\n", 233b8e80941Smrg bo->name ? bo->name : "", 234b8e80941Smrg bo->name ? " " : "", 235b8e80941Smrg bo->size / 1024); 236b8e80941Smrg v3d_bo_dump_stats(screen); 237b8e80941Smrg } 238b8e80941Smrg 239b8e80941Smrg free(bo); 240b8e80941Smrg} 241b8e80941Smrg 242b8e80941Smrgstatic void 243b8e80941Smrgfree_stale_bos(struct v3d_screen *screen, time_t time) 244b8e80941Smrg{ 245b8e80941Smrg struct v3d_bo_cache *cache = &screen->bo_cache; 246b8e80941Smrg bool freed_any = false; 247b8e80941Smrg 248b8e80941Smrg list_for_each_entry_safe(struct v3d_bo, bo, &cache->time_list, 249b8e80941Smrg time_list) { 250b8e80941Smrg /* If it's more than a second old, free it. */ 251b8e80941Smrg if (time - bo->free_time > 2) { 252b8e80941Smrg if (dump_stats && !freed_any) { 253b8e80941Smrg fprintf(stderr, "Freeing stale BOs:\n"); 254b8e80941Smrg v3d_bo_dump_stats(screen); 255b8e80941Smrg freed_any = true; 256b8e80941Smrg } 257b8e80941Smrg v3d_bo_remove_from_cache(cache, bo); 258b8e80941Smrg v3d_bo_free(bo); 259b8e80941Smrg } else { 260b8e80941Smrg break; 261b8e80941Smrg } 262b8e80941Smrg } 263b8e80941Smrg 264b8e80941Smrg if (dump_stats && freed_any) { 265b8e80941Smrg fprintf(stderr, "Freed stale BOs:\n"); 266b8e80941Smrg v3d_bo_dump_stats(screen); 267b8e80941Smrg } 268b8e80941Smrg} 269b8e80941Smrg 270b8e80941Smrgstatic void 271b8e80941Smrgv3d_bo_cache_free_all(struct v3d_bo_cache *cache) 272b8e80941Smrg{ 273b8e80941Smrg mtx_lock(&cache->lock); 274b8e80941Smrg list_for_each_entry_safe(struct v3d_bo, bo, &cache->time_list, 275b8e80941Smrg time_list) { 276b8e80941Smrg v3d_bo_remove_from_cache(cache, bo); 277b8e80941Smrg v3d_bo_free(bo); 278b8e80941Smrg } 279b8e80941Smrg mtx_unlock(&cache->lock); 280b8e80941Smrg} 281b8e80941Smrg 282b8e80941Smrgvoid 283b8e80941Smrgv3d_bo_last_unreference_locked_timed(struct v3d_bo *bo, time_t time) 284b8e80941Smrg{ 285b8e80941Smrg struct v3d_screen *screen = bo->screen; 286b8e80941Smrg struct v3d_bo_cache *cache = &screen->bo_cache; 287b8e80941Smrg uint32_t page_index = bo->size / 4096 - 1; 288b8e80941Smrg 289b8e80941Smrg if (!bo->private) { 290b8e80941Smrg v3d_bo_free(bo); 291b8e80941Smrg return; 292b8e80941Smrg } 293b8e80941Smrg 294b8e80941Smrg if (cache->size_list_size <= page_index) { 295b8e80941Smrg struct list_head *new_list = 296b8e80941Smrg ralloc_array(screen, struct list_head, page_index + 1); 297b8e80941Smrg 298b8e80941Smrg /* Move old list contents over (since the array has moved, and 299b8e80941Smrg * therefore the pointers to the list heads have to change). 300b8e80941Smrg */ 301b8e80941Smrg for (int i = 0; i < cache->size_list_size; i++) { 302b8e80941Smrg struct list_head *old_head = &cache->size_list[i]; 303b8e80941Smrg if (list_empty(old_head)) 304b8e80941Smrg list_inithead(&new_list[i]); 305b8e80941Smrg else { 306b8e80941Smrg new_list[i].next = old_head->next; 307b8e80941Smrg new_list[i].prev = old_head->prev; 308b8e80941Smrg new_list[i].next->prev = &new_list[i]; 309b8e80941Smrg new_list[i].prev->next = &new_list[i]; 310b8e80941Smrg } 311b8e80941Smrg } 312b8e80941Smrg for (int i = cache->size_list_size; i < page_index + 1; i++) 313b8e80941Smrg list_inithead(&new_list[i]); 314b8e80941Smrg 315b8e80941Smrg cache->size_list = new_list; 316b8e80941Smrg cache->size_list_size = page_index + 1; 317b8e80941Smrg } 318b8e80941Smrg 319b8e80941Smrg bo->free_time = time; 320b8e80941Smrg list_addtail(&bo->size_list, &cache->size_list[page_index]); 321b8e80941Smrg list_addtail(&bo->time_list, &cache->time_list); 322b8e80941Smrg if (dump_stats) { 323b8e80941Smrg fprintf(stderr, "Freed %s %dkb to cache:\n", 324b8e80941Smrg bo->name, bo->size / 1024); 325b8e80941Smrg v3d_bo_dump_stats(screen); 326b8e80941Smrg } 327b8e80941Smrg bo->name = NULL; 328b8e80941Smrg 329b8e80941Smrg free_stale_bos(screen, time); 330b8e80941Smrg} 331b8e80941Smrg 332b8e80941Smrgstatic struct v3d_bo * 333b8e80941Smrgv3d_bo_open_handle(struct v3d_screen *screen, 334b8e80941Smrg uint32_t handle, uint32_t size) 335b8e80941Smrg{ 336b8e80941Smrg struct v3d_bo *bo; 337b8e80941Smrg 338b8e80941Smrg assert(size); 339b8e80941Smrg 340b8e80941Smrg mtx_lock(&screen->bo_handles_mutex); 341b8e80941Smrg 342b8e80941Smrg bo = util_hash_table_get(screen->bo_handles, (void*)(uintptr_t)handle); 343b8e80941Smrg if (bo) { 344b8e80941Smrg pipe_reference(NULL, &bo->reference); 345b8e80941Smrg goto done; 346b8e80941Smrg } 347b8e80941Smrg 348b8e80941Smrg bo = CALLOC_STRUCT(v3d_bo); 349b8e80941Smrg pipe_reference_init(&bo->reference, 1); 350b8e80941Smrg bo->screen = screen; 351b8e80941Smrg bo->handle = handle; 352b8e80941Smrg bo->size = size; 353b8e80941Smrg bo->name = "winsys"; 354b8e80941Smrg bo->private = false; 355b8e80941Smrg 356b8e80941Smrg#ifdef USE_V3D_SIMULATOR 357b8e80941Smrg v3d_simulator_open_from_handle(screen->fd, bo->handle, bo->size); 358b8e80941Smrg bo->map = malloc(bo->size); 359b8e80941Smrg#endif 360b8e80941Smrg 361b8e80941Smrg struct drm_v3d_get_bo_offset get = { 362b8e80941Smrg .handle = handle, 363b8e80941Smrg }; 364b8e80941Smrg int ret = v3d_ioctl(screen->fd, DRM_IOCTL_V3D_GET_BO_OFFSET, &get); 365b8e80941Smrg if (ret) { 366b8e80941Smrg fprintf(stderr, "Failed to get BO offset: %s\n", 367b8e80941Smrg strerror(errno)); 368b8e80941Smrg free(bo->map); 369b8e80941Smrg free(bo); 370b8e80941Smrg return NULL; 371b8e80941Smrg } 372b8e80941Smrg bo->offset = get.offset; 373b8e80941Smrg assert(bo->offset != 0); 374b8e80941Smrg 375b8e80941Smrg util_hash_table_set(screen->bo_handles, (void *)(uintptr_t)handle, bo); 376b8e80941Smrg 377b8e80941Smrg screen->bo_count++; 378b8e80941Smrg screen->bo_size += bo->size; 379b8e80941Smrg 380b8e80941Smrgdone: 381b8e80941Smrg mtx_unlock(&screen->bo_handles_mutex); 382b8e80941Smrg return bo; 383b8e80941Smrg} 384b8e80941Smrg 385b8e80941Smrgstruct v3d_bo * 386b8e80941Smrgv3d_bo_open_name(struct v3d_screen *screen, uint32_t name) 387b8e80941Smrg{ 388b8e80941Smrg struct drm_gem_open o = { 389b8e80941Smrg .name = name 390b8e80941Smrg }; 391b8e80941Smrg int ret = v3d_ioctl(screen->fd, DRM_IOCTL_GEM_OPEN, &o); 392b8e80941Smrg if (ret) { 393b8e80941Smrg fprintf(stderr, "Failed to open bo %d: %s\n", 394b8e80941Smrg name, strerror(errno)); 395b8e80941Smrg return NULL; 396b8e80941Smrg } 397b8e80941Smrg 398b8e80941Smrg return v3d_bo_open_handle(screen, o.handle, o.size); 399b8e80941Smrg} 400b8e80941Smrg 401b8e80941Smrgstruct v3d_bo * 402b8e80941Smrgv3d_bo_open_dmabuf(struct v3d_screen *screen, int fd) 403b8e80941Smrg{ 404b8e80941Smrg uint32_t handle; 405b8e80941Smrg int ret = drmPrimeFDToHandle(screen->fd, fd, &handle); 406b8e80941Smrg int size; 407b8e80941Smrg if (ret) { 408b8e80941Smrg fprintf(stderr, "Failed to get v3d handle for dmabuf %d\n", fd); 409b8e80941Smrg return NULL; 410b8e80941Smrg } 411b8e80941Smrg 412b8e80941Smrg /* Determine the size of the bo we were handed. */ 413b8e80941Smrg size = lseek(fd, 0, SEEK_END); 414b8e80941Smrg if (size == -1) { 415b8e80941Smrg fprintf(stderr, "Couldn't get size of dmabuf fd %d.\n", fd); 416b8e80941Smrg return NULL; 417b8e80941Smrg } 418b8e80941Smrg 419b8e80941Smrg return v3d_bo_open_handle(screen, handle, size); 420b8e80941Smrg} 421b8e80941Smrg 422b8e80941Smrgint 423b8e80941Smrgv3d_bo_get_dmabuf(struct v3d_bo *bo) 424b8e80941Smrg{ 425b8e80941Smrg int fd; 426b8e80941Smrg int ret = drmPrimeHandleToFD(bo->screen->fd, bo->handle, 427b8e80941Smrg O_CLOEXEC, &fd); 428b8e80941Smrg if (ret != 0) { 429b8e80941Smrg fprintf(stderr, "Failed to export gem bo %d to dmabuf\n", 430b8e80941Smrg bo->handle); 431b8e80941Smrg return -1; 432b8e80941Smrg } 433b8e80941Smrg 434b8e80941Smrg mtx_lock(&bo->screen->bo_handles_mutex); 435b8e80941Smrg bo->private = false; 436b8e80941Smrg util_hash_table_set(bo->screen->bo_handles, (void *)(uintptr_t)bo->handle, bo); 437b8e80941Smrg mtx_unlock(&bo->screen->bo_handles_mutex); 438b8e80941Smrg 439b8e80941Smrg return fd; 440b8e80941Smrg} 441b8e80941Smrg 442b8e80941Smrgbool 443b8e80941Smrgv3d_bo_flink(struct v3d_bo *bo, uint32_t *name) 444b8e80941Smrg{ 445b8e80941Smrg struct drm_gem_flink flink = { 446b8e80941Smrg .handle = bo->handle, 447b8e80941Smrg }; 448b8e80941Smrg int ret = v3d_ioctl(bo->screen->fd, DRM_IOCTL_GEM_FLINK, &flink); 449b8e80941Smrg if (ret) { 450b8e80941Smrg fprintf(stderr, "Failed to flink bo %d: %s\n", 451b8e80941Smrg bo->handle, strerror(errno)); 452b8e80941Smrg free(bo); 453b8e80941Smrg return false; 454b8e80941Smrg } 455b8e80941Smrg 456b8e80941Smrg bo->private = false; 457b8e80941Smrg *name = flink.name; 458b8e80941Smrg 459b8e80941Smrg return true; 460b8e80941Smrg} 461b8e80941Smrg 462b8e80941Smrgstatic int v3d_wait_bo_ioctl(int fd, uint32_t handle, uint64_t timeout_ns) 463b8e80941Smrg{ 464b8e80941Smrg struct drm_v3d_wait_bo wait = { 465b8e80941Smrg .handle = handle, 466b8e80941Smrg .timeout_ns = timeout_ns, 467b8e80941Smrg }; 468b8e80941Smrg int ret = v3d_ioctl(fd, DRM_IOCTL_V3D_WAIT_BO, &wait); 469b8e80941Smrg if (ret == -1) 470b8e80941Smrg return -errno; 471b8e80941Smrg else 472b8e80941Smrg return 0; 473b8e80941Smrg 474b8e80941Smrg} 475b8e80941Smrg 476b8e80941Smrgbool 477b8e80941Smrgv3d_bo_wait(struct v3d_bo *bo, uint64_t timeout_ns, const char *reason) 478b8e80941Smrg{ 479b8e80941Smrg struct v3d_screen *screen = bo->screen; 480b8e80941Smrg 481b8e80941Smrg if (unlikely(V3D_DEBUG & V3D_DEBUG_PERF) && timeout_ns && reason) { 482b8e80941Smrg if (v3d_wait_bo_ioctl(screen->fd, bo->handle, 0) == -ETIME) { 483b8e80941Smrg fprintf(stderr, "Blocking on %s BO for %s\n", 484b8e80941Smrg bo->name, reason); 485b8e80941Smrg } 486b8e80941Smrg } 487b8e80941Smrg 488b8e80941Smrg int ret = v3d_wait_bo_ioctl(screen->fd, bo->handle, timeout_ns); 489b8e80941Smrg if (ret) { 490b8e80941Smrg if (ret != -ETIME) { 491b8e80941Smrg fprintf(stderr, "wait failed: %d\n", ret); 492b8e80941Smrg abort(); 493b8e80941Smrg } 494b8e80941Smrg 495b8e80941Smrg return false; 496b8e80941Smrg } 497b8e80941Smrg 498b8e80941Smrg return true; 499b8e80941Smrg} 500b8e80941Smrg 501b8e80941Smrgvoid * 502b8e80941Smrgv3d_bo_map_unsynchronized(struct v3d_bo *bo) 503b8e80941Smrg{ 504b8e80941Smrg uint64_t offset; 505b8e80941Smrg int ret; 506b8e80941Smrg 507b8e80941Smrg if (bo->map) 508b8e80941Smrg return bo->map; 509b8e80941Smrg 510b8e80941Smrg struct drm_v3d_mmap_bo map; 511b8e80941Smrg memset(&map, 0, sizeof(map)); 512b8e80941Smrg map.handle = bo->handle; 513b8e80941Smrg ret = v3d_ioctl(bo->screen->fd, DRM_IOCTL_V3D_MMAP_BO, &map); 514b8e80941Smrg offset = map.offset; 515b8e80941Smrg if (ret != 0) { 516b8e80941Smrg fprintf(stderr, "map ioctl failure\n"); 517b8e80941Smrg abort(); 518b8e80941Smrg } 519b8e80941Smrg 520b8e80941Smrg bo->map = mmap(NULL, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED, 521b8e80941Smrg bo->screen->fd, offset); 522b8e80941Smrg if (bo->map == MAP_FAILED) { 523b8e80941Smrg fprintf(stderr, "mmap of bo %d (offset 0x%016llx, size %d) failed\n", 524b8e80941Smrg bo->handle, (long long)offset, bo->size); 525b8e80941Smrg abort(); 526b8e80941Smrg } 527b8e80941Smrg VG(VALGRIND_MALLOCLIKE_BLOCK(bo->map, bo->size, 0, false)); 528b8e80941Smrg 529b8e80941Smrg return bo->map; 530b8e80941Smrg} 531b8e80941Smrg 532b8e80941Smrgvoid * 533b8e80941Smrgv3d_bo_map(struct v3d_bo *bo) 534b8e80941Smrg{ 535b8e80941Smrg void *map = v3d_bo_map_unsynchronized(bo); 536b8e80941Smrg 537b8e80941Smrg bool ok = v3d_bo_wait(bo, PIPE_TIMEOUT_INFINITE, "bo map"); 538b8e80941Smrg if (!ok) { 539b8e80941Smrg fprintf(stderr, "BO wait for map failed\n"); 540b8e80941Smrg abort(); 541b8e80941Smrg } 542b8e80941Smrg 543b8e80941Smrg return map; 544b8e80941Smrg} 545b8e80941Smrg 546b8e80941Smrgvoid 547b8e80941Smrgv3d_bufmgr_destroy(struct pipe_screen *pscreen) 548b8e80941Smrg{ 549b8e80941Smrg struct v3d_screen *screen = v3d_screen(pscreen); 550b8e80941Smrg struct v3d_bo_cache *cache = &screen->bo_cache; 551b8e80941Smrg 552b8e80941Smrg v3d_bo_cache_free_all(cache); 553b8e80941Smrg 554b8e80941Smrg if (dump_stats) { 555b8e80941Smrg fprintf(stderr, "BO stats after screen destroy:\n"); 556b8e80941Smrg v3d_bo_dump_stats(screen); 557b8e80941Smrg } 558b8e80941Smrg} 559