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