19f464c52Smaya/*
29f464c52Smaya * Copyright (C) 2017-2019 Lima Project
39f464c52Smaya *
49f464c52Smaya * Permission is hereby granted, free of charge, to any person obtaining a
59f464c52Smaya * copy of this software and associated documentation files (the "Software"),
69f464c52Smaya * to deal in the Software without restriction, including without limitation
79f464c52Smaya * the rights to use, copy, modify, merge, publish, distribute, sublicense,
89f464c52Smaya * and/or sell copies of the Software, and to permit persons to whom the
99f464c52Smaya * Software is furnished to do so, subject to the following conditions:
109f464c52Smaya *
119f464c52Smaya * The above copyright notice and this permission notice shall be included in
129f464c52Smaya * all copies or substantial portions of the Software.
139f464c52Smaya *
149f464c52Smaya * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
159f464c52Smaya * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
169f464c52Smaya * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
179f464c52Smaya * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
189f464c52Smaya * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
199f464c52Smaya * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
209f464c52Smaya * OTHER DEALINGS IN THE SOFTWARE.
219f464c52Smaya *
229f464c52Smaya */
239f464c52Smaya
249f464c52Smaya#include <stdlib.h>
259f464c52Smaya#include <sys/types.h>
269f464c52Smaya#include <unistd.h>
279f464c52Smaya#include <fcntl.h>
289f464c52Smaya
299f464c52Smaya#include "xf86drm.h"
309f464c52Smaya#include "drm-uapi/lima_drm.h"
319f464c52Smaya
329f464c52Smaya#include "util/u_hash_table.h"
337ec681f3Smrg#include "util/u_math.h"
349f464c52Smaya#include "util/os_time.h"
359f464c52Smaya#include "os/os_mman.h"
369f464c52Smaya
377ec681f3Smrg#include "frontend/drm_driver.h"
389f464c52Smaya
399f464c52Smaya#include "lima_screen.h"
409f464c52Smaya#include "lima_bo.h"
417ec681f3Smrg#include "lima_util.h"
429f464c52Smaya
439f464c52Smayabool lima_bo_table_init(struct lima_screen *screen)
449f464c52Smaya{
457ec681f3Smrg   screen->bo_handles = util_hash_table_create_ptr_keys();
469f464c52Smaya   if (!screen->bo_handles)
479f464c52Smaya      return false;
489f464c52Smaya
497ec681f3Smrg   screen->bo_flink_names = util_hash_table_create_ptr_keys();
509f464c52Smaya   if (!screen->bo_flink_names)
519f464c52Smaya      goto err_out0;
529f464c52Smaya
539f464c52Smaya   mtx_init(&screen->bo_table_lock, mtx_plain);
549f464c52Smaya   return true;
559f464c52Smaya
569f464c52Smayaerr_out0:
577ec681f3Smrg   _mesa_hash_table_destroy(screen->bo_handles, NULL);
589f464c52Smaya   return false;
599f464c52Smaya}
609f464c52Smaya
617ec681f3Smrgbool lima_bo_cache_init(struct lima_screen *screen)
627ec681f3Smrg{
637ec681f3Smrg   mtx_init(&screen->bo_cache_lock, mtx_plain);
647ec681f3Smrg   list_inithead(&screen->bo_cache_time);
657ec681f3Smrg   for (int i = 0; i < NR_BO_CACHE_BUCKETS; i++)
667ec681f3Smrg      list_inithead(&screen->bo_cache_buckets[i]);
677ec681f3Smrg
687ec681f3Smrg   return true;
697ec681f3Smrg}
707ec681f3Smrg
719f464c52Smayavoid lima_bo_table_fini(struct lima_screen *screen)
729f464c52Smaya{
739f464c52Smaya   mtx_destroy(&screen->bo_table_lock);
747ec681f3Smrg   _mesa_hash_table_destroy(screen->bo_handles, NULL);
757ec681f3Smrg   _mesa_hash_table_destroy(screen->bo_flink_names, NULL);
767ec681f3Smrg}
777ec681f3Smrg
787ec681f3Smrgstatic void
797ec681f3Smrglima_bo_cache_remove(struct lima_bo *bo)
807ec681f3Smrg{
817ec681f3Smrg   list_del(&bo->size_list);
827ec681f3Smrg   list_del(&bo->time_list);
839f464c52Smaya}
849f464c52Smaya
859f464c52Smayastatic void lima_close_kms_handle(struct lima_screen *screen, uint32_t handle)
869f464c52Smaya{
879f464c52Smaya   struct drm_gem_close args = {
889f464c52Smaya      .handle = handle,
899f464c52Smaya   };
909f464c52Smaya
919f464c52Smaya   drmIoctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &args);
929f464c52Smaya}
939f464c52Smaya
947ec681f3Smrgstatic void
957ec681f3Smrglima_bo_free(struct lima_bo *bo)
967ec681f3Smrg{
977ec681f3Smrg   struct lima_screen *screen = bo->screen;
987ec681f3Smrg
997ec681f3Smrg   if (lima_debug & LIMA_DEBUG_BO_CACHE)
1007ec681f3Smrg      fprintf(stderr, "%s: %p (size=%d)\n", __func__,
1017ec681f3Smrg              bo, bo->size);
1027ec681f3Smrg
1037ec681f3Smrg   mtx_lock(&screen->bo_table_lock);
1047ec681f3Smrg   _mesa_hash_table_remove_key(screen->bo_handles,
1057ec681f3Smrg                          (void *)(uintptr_t)bo->handle);
1067ec681f3Smrg   if (bo->flink_name)
1077ec681f3Smrg      _mesa_hash_table_remove_key(screen->bo_flink_names,
1087ec681f3Smrg                             (void *)(uintptr_t)bo->flink_name);
1097ec681f3Smrg   mtx_unlock(&screen->bo_table_lock);
1107ec681f3Smrg
1117ec681f3Smrg   if (bo->map)
1127ec681f3Smrg      lima_bo_unmap(bo);
1137ec681f3Smrg
1147ec681f3Smrg   lima_close_kms_handle(screen, bo->handle);
1157ec681f3Smrg   free(bo);
1167ec681f3Smrg}
1177ec681f3Smrg
1187ec681f3Smrgvoid lima_bo_cache_fini(struct lima_screen *screen)
1197ec681f3Smrg{
1207ec681f3Smrg   mtx_destroy(&screen->bo_cache_lock);
1217ec681f3Smrg
1227ec681f3Smrg   list_for_each_entry_safe(struct lima_bo, entry,
1237ec681f3Smrg                            &screen->bo_cache_time, time_list) {
1247ec681f3Smrg      lima_bo_cache_remove(entry);
1257ec681f3Smrg      lima_bo_free(entry);
1267ec681f3Smrg   }
1277ec681f3Smrg}
1287ec681f3Smrg
1299f464c52Smayastatic bool lima_bo_get_info(struct lima_bo *bo)
1309f464c52Smaya{
1319f464c52Smaya   struct drm_lima_gem_info req = {
1329f464c52Smaya      .handle = bo->handle,
1339f464c52Smaya   };
1349f464c52Smaya
1359f464c52Smaya   if(drmIoctl(bo->screen->fd, DRM_IOCTL_LIMA_GEM_INFO, &req))
1369f464c52Smaya      return false;
1379f464c52Smaya
1389f464c52Smaya   bo->offset = req.offset;
1399f464c52Smaya   bo->va = req.va;
1409f464c52Smaya   return true;
1419f464c52Smaya}
1429f464c52Smaya
1437ec681f3Smrgstatic unsigned
1447ec681f3Smrglima_bucket_index(unsigned size)
1457ec681f3Smrg{
1467ec681f3Smrg   /* Round down to POT to compute a bucket index */
1477ec681f3Smrg
1487ec681f3Smrg   unsigned bucket_index = util_logbase2(size);
1497ec681f3Smrg
1507ec681f3Smrg   /* Clamp the bucket index; all huge allocations will be
1517ec681f3Smrg    * sorted into the largest bucket */
1527ec681f3Smrg   bucket_index = CLAMP(bucket_index, MIN_BO_CACHE_BUCKET,
1537ec681f3Smrg                        MAX_BO_CACHE_BUCKET);
1547ec681f3Smrg
1557ec681f3Smrg   /* Reindex from 0 */
1567ec681f3Smrg   return (bucket_index - MIN_BO_CACHE_BUCKET);
1577ec681f3Smrg}
1587ec681f3Smrg
1597ec681f3Smrgstatic struct list_head *
1607ec681f3Smrglima_bo_cache_get_bucket(struct lima_screen *screen, unsigned size)
1617ec681f3Smrg{
1627ec681f3Smrg   return &screen->bo_cache_buckets[lima_bucket_index(size)];
1637ec681f3Smrg}
1647ec681f3Smrg
1657ec681f3Smrgstatic void
1667ec681f3Smrglima_bo_cache_free_stale_bos(struct lima_screen *screen, time_t time)
1677ec681f3Smrg{
1687ec681f3Smrg   unsigned cnt = 0;
1697ec681f3Smrg   list_for_each_entry_safe(struct lima_bo, entry,
1707ec681f3Smrg                            &screen->bo_cache_time, time_list) {
1717ec681f3Smrg      /* Free BOs that are sitting idle for longer than 5 seconds */
1727ec681f3Smrg      if (time - entry->free_time > 6) {
1737ec681f3Smrg         lima_bo_cache_remove(entry);
1747ec681f3Smrg         lima_bo_free(entry);
1757ec681f3Smrg         cnt++;
1767ec681f3Smrg      } else
1777ec681f3Smrg         break;
1787ec681f3Smrg   }
1797ec681f3Smrg   if ((lima_debug & LIMA_DEBUG_BO_CACHE) && cnt)
1807ec681f3Smrg      fprintf(stderr, "%s: freed %d stale BOs\n", __func__, cnt);
1817ec681f3Smrg}
1827ec681f3Smrg
1837ec681f3Smrgstatic void
1847ec681f3Smrglima_bo_cache_print_stats(struct lima_screen *screen)
1857ec681f3Smrg{
1867ec681f3Smrg   fprintf(stderr, "===============\n");
1877ec681f3Smrg   fprintf(stderr, "BO cache stats:\n");
1887ec681f3Smrg   unsigned total_size = 0;
1897ec681f3Smrg   for (int i = 0; i < NR_BO_CACHE_BUCKETS; i++) {
1907ec681f3Smrg      struct list_head *bucket = &screen->bo_cache_buckets[i];
1917ec681f3Smrg      unsigned bucket_size = 0;
1927ec681f3Smrg      list_for_each_entry(struct lima_bo, entry, bucket, size_list) {
1937ec681f3Smrg         bucket_size += entry->size;
1947ec681f3Smrg         total_size += entry->size;
1957ec681f3Smrg      }
1967ec681f3Smrg      fprintf(stderr, "Bucket #%d, BOs: %d, size: %u\n", i,
1977ec681f3Smrg              list_length(bucket),
1987ec681f3Smrg              bucket_size);
1997ec681f3Smrg   }
2007ec681f3Smrg   fprintf(stderr, "Total size: %u\n", total_size);
2017ec681f3Smrg}
2027ec681f3Smrg
2037ec681f3Smrgstatic bool
2047ec681f3Smrglima_bo_cache_put(struct lima_bo *bo)
2057ec681f3Smrg{
2067ec681f3Smrg   if (!bo->cacheable)
2077ec681f3Smrg      return false;
2087ec681f3Smrg
2097ec681f3Smrg   struct lima_screen *screen = bo->screen;
2107ec681f3Smrg
2117ec681f3Smrg   mtx_lock(&screen->bo_cache_lock);
2127ec681f3Smrg   struct list_head *bucket = lima_bo_cache_get_bucket(screen, bo->size);
2137ec681f3Smrg
2147ec681f3Smrg   if (!bucket) {
2157ec681f3Smrg      mtx_unlock(&screen->bo_cache_lock);
2167ec681f3Smrg      return false;
2177ec681f3Smrg   }
2187ec681f3Smrg
2197ec681f3Smrg   struct timespec time;
2207ec681f3Smrg   clock_gettime(CLOCK_MONOTONIC, &time);
2217ec681f3Smrg   bo->free_time = time.tv_sec;
2227ec681f3Smrg   list_addtail(&bo->size_list, bucket);
2237ec681f3Smrg   list_addtail(&bo->time_list, &screen->bo_cache_time);
2247ec681f3Smrg   lima_bo_cache_free_stale_bos(screen, time.tv_sec);
2257ec681f3Smrg   if (lima_debug & LIMA_DEBUG_BO_CACHE) {
2267ec681f3Smrg      fprintf(stderr, "%s: put BO: %p (size=%d)\n", __func__, bo, bo->size);
2277ec681f3Smrg      lima_bo_cache_print_stats(screen);
2287ec681f3Smrg   }
2297ec681f3Smrg   mtx_unlock(&screen->bo_cache_lock);
2307ec681f3Smrg
2317ec681f3Smrg   return true;
2327ec681f3Smrg}
2337ec681f3Smrg
2347ec681f3Smrgstatic struct lima_bo *
2357ec681f3Smrglima_bo_cache_get(struct lima_screen *screen, uint32_t size, uint32_t flags)
2367ec681f3Smrg{
2377ec681f3Smrg   /* we won't cache heap buffer */
2387ec681f3Smrg   if (flags & LIMA_BO_FLAG_HEAP)
2397ec681f3Smrg      return NULL;
2407ec681f3Smrg
2417ec681f3Smrg   struct lima_bo *bo = NULL;
2427ec681f3Smrg   mtx_lock(&screen->bo_cache_lock);
2437ec681f3Smrg   struct list_head *bucket = lima_bo_cache_get_bucket(screen, size);
2447ec681f3Smrg
2457ec681f3Smrg   if (!bucket) {
2467ec681f3Smrg      mtx_unlock(&screen->bo_cache_lock);
2477ec681f3Smrg      return false;
2487ec681f3Smrg   }
2497ec681f3Smrg
2507ec681f3Smrg   list_for_each_entry_safe(struct lima_bo, entry, bucket, size_list) {
2517ec681f3Smrg      if (entry->size >= size) {
2527ec681f3Smrg         /* Check if BO is idle. If it's not it's better to allocate new one */
2537ec681f3Smrg         if (!lima_bo_wait(entry, LIMA_GEM_WAIT_WRITE, 0)) {
2547ec681f3Smrg            if (lima_debug & LIMA_DEBUG_BO_CACHE) {
2557ec681f3Smrg               fprintf(stderr, "%s: found BO %p but it's busy\n", __func__,
2567ec681f3Smrg                       entry);
2577ec681f3Smrg            }
2587ec681f3Smrg            break;
2597ec681f3Smrg         }
2607ec681f3Smrg
2617ec681f3Smrg         lima_bo_cache_remove(entry);
2627ec681f3Smrg         p_atomic_set(&entry->refcnt, 1);
2637ec681f3Smrg         entry->flags = flags;
2647ec681f3Smrg         bo = entry;
2657ec681f3Smrg         if (lima_debug & LIMA_DEBUG_BO_CACHE) {
2667ec681f3Smrg            fprintf(stderr, "%s: got BO: %p (size=%d), requested size %d\n",
2677ec681f3Smrg                    __func__, bo, bo->size, size);
2687ec681f3Smrg            lima_bo_cache_print_stats(screen);
2697ec681f3Smrg         }
2707ec681f3Smrg         break;
2717ec681f3Smrg      }
2727ec681f3Smrg   }
2737ec681f3Smrg
2747ec681f3Smrg   mtx_unlock(&screen->bo_cache_lock);
2757ec681f3Smrg
2767ec681f3Smrg   return bo;
2777ec681f3Smrg}
2787ec681f3Smrg
2799f464c52Smayastruct lima_bo *lima_bo_create(struct lima_screen *screen,
2809f464c52Smaya                               uint32_t size, uint32_t flags)
2819f464c52Smaya{
2829f464c52Smaya   struct lima_bo *bo;
2837ec681f3Smrg
2847ec681f3Smrg   size = align(size, LIMA_PAGE_SIZE);
2857ec681f3Smrg
2867ec681f3Smrg   /* Try to get bo from cache first */
2877ec681f3Smrg   bo = lima_bo_cache_get(screen, size, flags);
2887ec681f3Smrg   if (bo)
2897ec681f3Smrg      return bo;
2907ec681f3Smrg
2919f464c52Smaya   struct drm_lima_gem_create req = {
2929f464c52Smaya      .size = size,
2939f464c52Smaya      .flags = flags,
2949f464c52Smaya   };
2959f464c52Smaya
2969f464c52Smaya   if (!(bo = calloc(1, sizeof(*bo))))
2979f464c52Smaya      return NULL;
2989f464c52Smaya
2997ec681f3Smrg   list_inithead(&bo->time_list);
3007ec681f3Smrg   list_inithead(&bo->size_list);
3017ec681f3Smrg
3029f464c52Smaya   if (drmIoctl(screen->fd, DRM_IOCTL_LIMA_GEM_CREATE, &req))
3039f464c52Smaya      goto err_out0;
3049f464c52Smaya
3059f464c52Smaya   bo->screen = screen;
3069f464c52Smaya   bo->size = req.size;
3077ec681f3Smrg   bo->flags = req.flags;
3089f464c52Smaya   bo->handle = req.handle;
3097ec681f3Smrg   bo->cacheable = !(lima_debug & LIMA_DEBUG_NO_BO_CACHE ||
3107ec681f3Smrg                     flags & LIMA_BO_FLAG_HEAP);
3119f464c52Smaya   p_atomic_set(&bo->refcnt, 1);
3129f464c52Smaya
3139f464c52Smaya   if (!lima_bo_get_info(bo))
3149f464c52Smaya      goto err_out1;
3159f464c52Smaya
3167ec681f3Smrg   if (lima_debug & LIMA_DEBUG_BO_CACHE)
3177ec681f3Smrg      fprintf(stderr, "%s: %p (size=%d)\n", __func__,
3187ec681f3Smrg              bo, bo->size);
3197ec681f3Smrg
3209f464c52Smaya   return bo;
3219f464c52Smaya
3229f464c52Smayaerr_out1:
3239f464c52Smaya   lima_close_kms_handle(screen, bo->handle);
3249f464c52Smayaerr_out0:
3259f464c52Smaya   free(bo);
3269f464c52Smaya   return NULL;
3279f464c52Smaya}
3289f464c52Smaya
3297ec681f3Smrgvoid lima_bo_unreference(struct lima_bo *bo)
3309f464c52Smaya{
3319f464c52Smaya   if (!p_atomic_dec_zero(&bo->refcnt))
3329f464c52Smaya      return;
3339f464c52Smaya
3347ec681f3Smrg   /* Try to put it into cache */
3357ec681f3Smrg   if (lima_bo_cache_put(bo))
3367ec681f3Smrg      return;
3379f464c52Smaya
3387ec681f3Smrg   lima_bo_free(bo);
3399f464c52Smaya}
3409f464c52Smaya
3419f464c52Smayavoid *lima_bo_map(struct lima_bo *bo)
3429f464c52Smaya{
3439f464c52Smaya   if (!bo->map) {
3449f464c52Smaya      bo->map = os_mmap(0, bo->size, PROT_READ | PROT_WRITE,
3459f464c52Smaya                        MAP_SHARED, bo->screen->fd, bo->offset);
3469f464c52Smaya      if (bo->map == MAP_FAILED)
3479f464c52Smaya          bo->map = NULL;
3489f464c52Smaya   }
3499f464c52Smaya
3509f464c52Smaya   return bo->map;
3519f464c52Smaya}
3529f464c52Smaya
3539f464c52Smayavoid lima_bo_unmap(struct lima_bo *bo)
3549f464c52Smaya{
3559f464c52Smaya   if (bo->map) {
3569f464c52Smaya      os_munmap(bo->map, bo->size);
3579f464c52Smaya      bo->map = NULL;
3589f464c52Smaya   }
3599f464c52Smaya}
3609f464c52Smaya
3619f464c52Smayabool lima_bo_export(struct lima_bo *bo, struct winsys_handle *handle)
3629f464c52Smaya{
3639f464c52Smaya   struct lima_screen *screen = bo->screen;
3649f464c52Smaya
3657ec681f3Smrg   /* Don't cache exported BOs */
3667ec681f3Smrg   bo->cacheable = false;
3677ec681f3Smrg
3689f464c52Smaya   switch (handle->type) {
3699f464c52Smaya   case WINSYS_HANDLE_TYPE_SHARED:
3709f464c52Smaya      if (!bo->flink_name) {
3719f464c52Smaya         struct drm_gem_flink flink = {
3729f464c52Smaya            .handle = bo->handle,
3739f464c52Smaya            .name = 0,
3749f464c52Smaya         };
3759f464c52Smaya         if (drmIoctl(screen->fd, DRM_IOCTL_GEM_FLINK, &flink))
3769f464c52Smaya            return false;
3779f464c52Smaya
3789f464c52Smaya         bo->flink_name = flink.name;
3799f464c52Smaya
3809f464c52Smaya         mtx_lock(&screen->bo_table_lock);
3817ec681f3Smrg         _mesa_hash_table_insert(screen->bo_flink_names,
3829f464c52Smaya                             (void *)(uintptr_t)bo->flink_name, bo);
3839f464c52Smaya         mtx_unlock(&screen->bo_table_lock);
3849f464c52Smaya      }
3859f464c52Smaya      handle->handle = bo->flink_name;
3869f464c52Smaya      return true;
3879f464c52Smaya
3889f464c52Smaya   case WINSYS_HANDLE_TYPE_KMS:
3899f464c52Smaya      mtx_lock(&screen->bo_table_lock);
3907ec681f3Smrg      _mesa_hash_table_insert(screen->bo_handles,
3919f464c52Smaya                          (void *)(uintptr_t)bo->handle, bo);
3929f464c52Smaya      mtx_unlock(&screen->bo_table_lock);
3939f464c52Smaya
3949f464c52Smaya      handle->handle = bo->handle;
3959f464c52Smaya      return true;
3969f464c52Smaya
3979f464c52Smaya   case WINSYS_HANDLE_TYPE_FD:
3989f464c52Smaya      if (drmPrimeHandleToFD(screen->fd, bo->handle, DRM_CLOEXEC,
3999f464c52Smaya                             (int*)&handle->handle))
4009f464c52Smaya         return false;
4019f464c52Smaya
4029f464c52Smaya      mtx_lock(&screen->bo_table_lock);
4037ec681f3Smrg      _mesa_hash_table_insert(screen->bo_handles,
4049f464c52Smaya                          (void *)(uintptr_t)bo->handle, bo);
4059f464c52Smaya      mtx_unlock(&screen->bo_table_lock);
4069f464c52Smaya      return true;
4079f464c52Smaya
4089f464c52Smaya   default:
4099f464c52Smaya      return false;
4109f464c52Smaya   }
4119f464c52Smaya}
4129f464c52Smaya
4139f464c52Smayastruct lima_bo *lima_bo_import(struct lima_screen *screen,
4149f464c52Smaya                               struct winsys_handle *handle)
4159f464c52Smaya{
4169f464c52Smaya   struct lima_bo *bo = NULL;
4179f464c52Smaya   struct drm_gem_open req = {0};
4189f464c52Smaya   uint32_t dma_buf_size = 0;
4199f464c52Smaya   unsigned h = handle->handle;
4209f464c52Smaya
4219f464c52Smaya   mtx_lock(&screen->bo_table_lock);
4229f464c52Smaya
4239f464c52Smaya   /* Convert a DMA buf handle to a KMS handle now. */
4249f464c52Smaya   if (handle->type == WINSYS_HANDLE_TYPE_FD) {
4259f464c52Smaya      uint32_t prime_handle;
4269f464c52Smaya      off_t size;
4279f464c52Smaya
4289f464c52Smaya      /* Get a KMS handle. */
4299f464c52Smaya      if (drmPrimeFDToHandle(screen->fd, h, &prime_handle)) {
4309f464c52Smaya         mtx_unlock(&screen->bo_table_lock);
4319f464c52Smaya         return NULL;
4329f464c52Smaya      }
4339f464c52Smaya
4349f464c52Smaya      /* Query the buffer size. */
4359f464c52Smaya      size = lseek(h, 0, SEEK_END);
4369f464c52Smaya      if (size == (off_t)-1) {
4379f464c52Smaya         mtx_unlock(&screen->bo_table_lock);
4389f464c52Smaya         lima_close_kms_handle(screen, prime_handle);
4399f464c52Smaya         return NULL;
4409f464c52Smaya      }
4419f464c52Smaya      lseek(h, 0, SEEK_SET);
4429f464c52Smaya
4439f464c52Smaya      dma_buf_size = size;
4449f464c52Smaya      h = prime_handle;
4459f464c52Smaya   }
4469f464c52Smaya
4479f464c52Smaya   switch (handle->type) {
4489f464c52Smaya   case WINSYS_HANDLE_TYPE_SHARED:
4499f464c52Smaya      bo = util_hash_table_get(screen->bo_flink_names,
4509f464c52Smaya                               (void *)(uintptr_t)h);
4519f464c52Smaya      break;
4529f464c52Smaya   case WINSYS_HANDLE_TYPE_KMS:
4539f464c52Smaya   case WINSYS_HANDLE_TYPE_FD:
4549f464c52Smaya      bo = util_hash_table_get(screen->bo_handles,
4559f464c52Smaya                               (void *)(uintptr_t)h);
4569f464c52Smaya      break;
4579f464c52Smaya   default:
4589f464c52Smaya      mtx_unlock(&screen->bo_table_lock);
4599f464c52Smaya      return NULL;
4609f464c52Smaya   }
4619f464c52Smaya
4629f464c52Smaya   if (bo) {
4639f464c52Smaya      p_atomic_inc(&bo->refcnt);
4647ec681f3Smrg      /* Don't cache imported BOs */
4657ec681f3Smrg      bo->cacheable = false;
4669f464c52Smaya      mtx_unlock(&screen->bo_table_lock);
4679f464c52Smaya      return bo;
4689f464c52Smaya   }
4699f464c52Smaya
4709f464c52Smaya   if (!(bo = calloc(1, sizeof(*bo)))) {
4719f464c52Smaya      mtx_unlock(&screen->bo_table_lock);
4729f464c52Smaya      if (handle->type == WINSYS_HANDLE_TYPE_FD)
4739f464c52Smaya         lima_close_kms_handle(screen, h);
4749f464c52Smaya      return NULL;
4759f464c52Smaya   }
4769f464c52Smaya
4777ec681f3Smrg   /* Don't cache imported BOs */
4787ec681f3Smrg   bo->cacheable = false;
4797ec681f3Smrg   list_inithead(&bo->time_list);
4807ec681f3Smrg   list_inithead(&bo->size_list);
4819f464c52Smaya   bo->screen = screen;
4829f464c52Smaya   p_atomic_set(&bo->refcnt, 1);
4839f464c52Smaya
4849f464c52Smaya   switch (handle->type) {
4859f464c52Smaya   case WINSYS_HANDLE_TYPE_SHARED:
4869f464c52Smaya      req.name = h;
4879f464c52Smaya      if (drmIoctl(screen->fd, DRM_IOCTL_GEM_OPEN, &req)) {
4889f464c52Smaya         mtx_unlock(&screen->bo_table_lock);
4899f464c52Smaya         free(bo);
4909f464c52Smaya         return NULL;
4919f464c52Smaya      }
4929f464c52Smaya      bo->handle = req.handle;
4939f464c52Smaya      bo->flink_name = h;
4949f464c52Smaya      bo->size = req.size;
4959f464c52Smaya      break;
4969f464c52Smaya   case WINSYS_HANDLE_TYPE_FD:
4979f464c52Smaya      bo->handle = h;
4989f464c52Smaya      bo->size = dma_buf_size;
4999f464c52Smaya      break;
5009f464c52Smaya   default:
5019f464c52Smaya      /* not possible */
5029f464c52Smaya      assert(0);
5039f464c52Smaya   }
5049f464c52Smaya
5059f464c52Smaya   if (lima_bo_get_info(bo)) {
5069f464c52Smaya      if (handle->type == WINSYS_HANDLE_TYPE_SHARED)
5077ec681f3Smrg         _mesa_hash_table_insert(screen->bo_flink_names,
5089f464c52Smaya                          (void *)(uintptr_t)bo->flink_name, bo);
5097ec681f3Smrg      _mesa_hash_table_insert(screen->bo_handles,
5109f464c52Smaya                          (void*)(uintptr_t)bo->handle, bo);
5119f464c52Smaya   }
5129f464c52Smaya   else {
5139f464c52Smaya      lima_close_kms_handle(screen, bo->handle);
5149f464c52Smaya      free(bo);
5159f464c52Smaya      bo = NULL;
5169f464c52Smaya   }
5179f464c52Smaya
5189f464c52Smaya   mtx_unlock(&screen->bo_table_lock);
5199f464c52Smaya
5209f464c52Smaya   return bo;
5219f464c52Smaya}
5229f464c52Smaya
5239f464c52Smayabool lima_bo_wait(struct lima_bo *bo, uint32_t op, uint64_t timeout_ns)
5249f464c52Smaya{
5257ec681f3Smrg   int64_t abs_timeout;
5267ec681f3Smrg
5277ec681f3Smrg   if (timeout_ns == 0)
5287ec681f3Smrg      abs_timeout = 0;
5297ec681f3Smrg   else
5307ec681f3Smrg      abs_timeout = os_time_get_absolute_timeout(timeout_ns);
5317ec681f3Smrg
5327ec681f3Smrg   if (abs_timeout == OS_TIMEOUT_INFINITE)
5337ec681f3Smrg      abs_timeout = INT64_MAX;
5347ec681f3Smrg
5359f464c52Smaya   struct drm_lima_gem_wait req = {
5369f464c52Smaya      .handle = bo->handle,
5379f464c52Smaya      .op = op,
5389f464c52Smaya      .timeout_ns = abs_timeout,
5399f464c52Smaya   };
5409f464c52Smaya
5419f464c52Smaya   return drmIoctl(bo->screen->fd, DRM_IOCTL_LIMA_GEM_WAIT, &req) == 0;
5429f464c52Smaya}
543