2 * Copyright (C) 2017-2019 Lima Project
4 * Permission is hereby granted, free of charge, to any person obtaining a
5 * copy of this software and associated documentation files (the "Software"),
6 * to deal in the Software without restriction, including without limitation
7 * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8 * and/or sell copies of the Software, and to permit persons to whom the
9 * Software is furnished to do so, subject to the following conditions:
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
14 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
17 * THE COPYRIGHT HOLDER(S) OR AUTHOR(S) BE LIABLE FOR ANY CLAIM, DAMAGES OR
18 * OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
19 * ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
20 * OTHER DEALINGS IN THE SOFTWARE.
25 #include <sys/types.h>
30 #include "drm-uapi/lima_drm.h"
32 #include "util/u_hash_table.h"
33 #include "util/os_time.h"
34 #include "os/os_mman.h"
36 #include "state_tracker/drm_driver.h"
38 #include "lima_screen.h"
41 #define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x)))
43 static unsigned handle_hash(void *key
)
45 return PTR_TO_UINT(key
);
48 static int handle_compare(void *key1
, void *key2
)
50 return PTR_TO_UINT(key1
) != PTR_TO_UINT(key2
);
53 bool lima_bo_table_init(struct lima_screen
*screen
)
55 screen
->bo_handles
= util_hash_table_create(handle_hash
, handle_compare
);
56 if (!screen
->bo_handles
)
59 screen
->bo_flink_names
= util_hash_table_create(handle_hash
, handle_compare
);
60 if (!screen
->bo_flink_names
)
63 mtx_init(&screen
->bo_table_lock
, mtx_plain
);
67 util_hash_table_destroy(screen
->bo_handles
);
71 void lima_bo_table_fini(struct lima_screen
*screen
)
73 mtx_destroy(&screen
->bo_table_lock
);
74 util_hash_table_destroy(screen
->bo_handles
);
75 util_hash_table_destroy(screen
->bo_flink_names
);
78 static void lima_close_kms_handle(struct lima_screen
*screen
, uint32_t handle
)
80 struct drm_gem_close args
= {
84 drmIoctl(screen
->fd
, DRM_IOCTL_GEM_CLOSE
, &args
);
87 static bool lima_bo_get_info(struct lima_bo
*bo
)
89 struct drm_lima_gem_info req
= {
93 if(drmIoctl(bo
->screen
->fd
, DRM_IOCTL_LIMA_GEM_INFO
, &req
))
96 bo
->offset
= req
.offset
;
101 struct lima_bo
*lima_bo_create(struct lima_screen
*screen
,
102 uint32_t size
, uint32_t flags
)
105 struct drm_lima_gem_create req
= {
110 if (!(bo
= calloc(1, sizeof(*bo
))))
113 if (drmIoctl(screen
->fd
, DRM_IOCTL_LIMA_GEM_CREATE
, &req
))
118 bo
->handle
= req
.handle
;
119 p_atomic_set(&bo
->refcnt
, 1);
121 if (!lima_bo_get_info(bo
))
127 lima_close_kms_handle(screen
, bo
->handle
);
133 void lima_bo_free(struct lima_bo
*bo
)
135 if (!p_atomic_dec_zero(&bo
->refcnt
))
138 struct lima_screen
*screen
= bo
->screen
;
139 mtx_lock(&screen
->bo_table_lock
);
140 util_hash_table_remove(screen
->bo_handles
,
141 (void *)(uintptr_t)bo
->handle
);
143 util_hash_table_remove(screen
->bo_flink_names
,
144 (void *)(uintptr_t)bo
->flink_name
);
145 mtx_unlock(&screen
->bo_table_lock
);
150 lima_close_kms_handle(screen
, bo
->handle
);
154 void *lima_bo_map(struct lima_bo
*bo
)
157 bo
->map
= os_mmap(0, bo
->size
, PROT_READ
| PROT_WRITE
,
158 MAP_SHARED
, bo
->screen
->fd
, bo
->offset
);
159 if (bo
->map
== MAP_FAILED
)
166 void lima_bo_unmap(struct lima_bo
*bo
)
169 os_munmap(bo
->map
, bo
->size
);
174 bool lima_bo_export(struct lima_bo
*bo
, struct winsys_handle
*handle
)
176 struct lima_screen
*screen
= bo
->screen
;
178 switch (handle
->type
) {
179 case WINSYS_HANDLE_TYPE_SHARED
:
180 if (!bo
->flink_name
) {
181 struct drm_gem_flink flink
= {
182 .handle
= bo
->handle
,
185 if (drmIoctl(screen
->fd
, DRM_IOCTL_GEM_FLINK
, &flink
))
188 bo
->flink_name
= flink
.name
;
190 mtx_lock(&screen
->bo_table_lock
);
191 util_hash_table_set(screen
->bo_flink_names
,
192 (void *)(uintptr_t)bo
->flink_name
, bo
);
193 mtx_unlock(&screen
->bo_table_lock
);
195 handle
->handle
= bo
->flink_name
;
198 case WINSYS_HANDLE_TYPE_KMS
:
199 mtx_lock(&screen
->bo_table_lock
);
200 util_hash_table_set(screen
->bo_handles
,
201 (void *)(uintptr_t)bo
->handle
, bo
);
202 mtx_unlock(&screen
->bo_table_lock
);
204 handle
->handle
= bo
->handle
;
207 case WINSYS_HANDLE_TYPE_FD
:
208 if (drmPrimeHandleToFD(screen
->fd
, bo
->handle
, DRM_CLOEXEC
,
209 (int*)&handle
->handle
))
212 mtx_lock(&screen
->bo_table_lock
);
213 util_hash_table_set(screen
->bo_handles
,
214 (void *)(uintptr_t)bo
->handle
, bo
);
215 mtx_unlock(&screen
->bo_table_lock
);
223 struct lima_bo
*lima_bo_import(struct lima_screen
*screen
,
224 struct winsys_handle
*handle
)
226 struct lima_bo
*bo
= NULL
;
227 struct drm_gem_open req
= {0};
228 uint32_t dma_buf_size
= 0;
229 unsigned h
= handle
->handle
;
231 mtx_lock(&screen
->bo_table_lock
);
233 /* Convert a DMA buf handle to a KMS handle now. */
234 if (handle
->type
== WINSYS_HANDLE_TYPE_FD
) {
235 uint32_t prime_handle
;
238 /* Get a KMS handle. */
239 if (drmPrimeFDToHandle(screen
->fd
, h
, &prime_handle
)) {
240 mtx_unlock(&screen
->bo_table_lock
);
244 /* Query the buffer size. */
245 size
= lseek(h
, 0, SEEK_END
);
246 if (size
== (off_t
)-1) {
247 mtx_unlock(&screen
->bo_table_lock
);
248 lima_close_kms_handle(screen
, prime_handle
);
251 lseek(h
, 0, SEEK_SET
);
257 switch (handle
->type
) {
258 case WINSYS_HANDLE_TYPE_SHARED
:
259 bo
= util_hash_table_get(screen
->bo_flink_names
,
260 (void *)(uintptr_t)h
);
262 case WINSYS_HANDLE_TYPE_KMS
:
263 case WINSYS_HANDLE_TYPE_FD
:
264 bo
= util_hash_table_get(screen
->bo_handles
,
265 (void *)(uintptr_t)h
);
268 mtx_unlock(&screen
->bo_table_lock
);
273 p_atomic_inc(&bo
->refcnt
);
274 mtx_unlock(&screen
->bo_table_lock
);
278 if (!(bo
= calloc(1, sizeof(*bo
)))) {
279 mtx_unlock(&screen
->bo_table_lock
);
280 if (handle
->type
== WINSYS_HANDLE_TYPE_FD
)
281 lima_close_kms_handle(screen
, h
);
286 p_atomic_set(&bo
->refcnt
, 1);
288 switch (handle
->type
) {
289 case WINSYS_HANDLE_TYPE_SHARED
:
291 if (drmIoctl(screen
->fd
, DRM_IOCTL_GEM_OPEN
, &req
)) {
292 mtx_unlock(&screen
->bo_table_lock
);
296 bo
->handle
= req
.handle
;
300 case WINSYS_HANDLE_TYPE_FD
:
302 bo
->size
= dma_buf_size
;
309 if (lima_bo_get_info(bo
)) {
310 if (handle
->type
== WINSYS_HANDLE_TYPE_SHARED
)
311 util_hash_table_set(screen
->bo_flink_names
,
312 (void *)(uintptr_t)bo
->flink_name
, bo
);
313 util_hash_table_set(screen
->bo_handles
,
314 (void*)(uintptr_t)bo
->handle
, bo
);
317 lima_close_kms_handle(screen
, bo
->handle
);
322 mtx_unlock(&screen
->bo_table_lock
);
327 bool lima_bo_wait(struct lima_bo
*bo
, uint32_t op
, uint64_t timeout_ns
)
329 int64_t abs_timeout
= os_time_get_absolute_timeout(timeout_ns
);
330 if (abs_timeout
== OS_TIMEOUT_INFINITE
)
331 abs_timeout
= INT64_MAX
;
333 struct drm_lima_gem_wait req
= {
334 .handle
= bo
->handle
,
336 .timeout_ns
= abs_timeout
,
339 return drmIoctl(bo
->screen
->fd
, DRM_IOCTL_LIMA_GEM_WAIT
, &req
) == 0;