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