lima: actually wait for bo in lima_bo_wait
[mesa.git] / src / gallium / drivers / lima / lima_bo.c
1 /*
2 * Copyright (C) 2017-2019 Lima Project
3 *
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:
10 *
11 * The above copyright notice and this permission notice shall be included in
12 * all copies or substantial portions of the Software.
13 *
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.
21 *
22 */
23
24 #include <stdlib.h>
25 #include <sys/types.h>
26 #include <unistd.h>
27 #include <fcntl.h>
28
29 #include "xf86drm.h"
30 #include "drm-uapi/lima_drm.h"
31
32 #include "util/u_hash_table.h"
33 #include "util/os_time.h"
34 #include "os/os_mman.h"
35
36 #include "state_tracker/drm_driver.h"
37
38 #include "lima_screen.h"
39 #include "lima_bo.h"
40
41 #define PTR_TO_UINT(x) ((unsigned)((intptr_t)(x)))
42
43 static unsigned handle_hash(void *key)
44 {
45 return PTR_TO_UINT(key);
46 }
47
48 static int handle_compare(void *key1, void *key2)
49 {
50 return PTR_TO_UINT(key1) != PTR_TO_UINT(key2);
51 }
52
53 bool lima_bo_table_init(struct lima_screen *screen)
54 {
55 screen->bo_handles = util_hash_table_create(handle_hash, handle_compare);
56 if (!screen->bo_handles)
57 return false;
58
59 screen->bo_flink_names = util_hash_table_create(handle_hash, handle_compare);
60 if (!screen->bo_flink_names)
61 goto err_out0;
62
63 mtx_init(&screen->bo_table_lock, mtx_plain);
64 return true;
65
66 err_out0:
67 util_hash_table_destroy(screen->bo_handles);
68 return false;
69 }
70
71 void lima_bo_table_fini(struct lima_screen *screen)
72 {
73 mtx_destroy(&screen->bo_table_lock);
74 util_hash_table_destroy(screen->bo_handles);
75 util_hash_table_destroy(screen->bo_flink_names);
76 }
77
78 static void lima_close_kms_handle(struct lima_screen *screen, uint32_t handle)
79 {
80 struct drm_gem_close args = {
81 .handle = handle,
82 };
83
84 drmIoctl(screen->fd, DRM_IOCTL_GEM_CLOSE, &args);
85 }
86
87 static bool lima_bo_get_info(struct lima_bo *bo)
88 {
89 struct drm_lima_gem_info req = {
90 .handle = bo->handle,
91 };
92
93 if(drmIoctl(bo->screen->fd, DRM_IOCTL_LIMA_GEM_INFO, &req))
94 return false;
95
96 bo->offset = req.offset;
97 bo->va = req.va;
98 return true;
99 }
100
101 struct lima_bo *lima_bo_create(struct lima_screen *screen,
102 uint32_t size, uint32_t flags)
103 {
104 struct lima_bo *bo;
105 struct drm_lima_gem_create req = {
106 .size = size,
107 .flags = flags,
108 };
109
110 if (!(bo = calloc(1, sizeof(*bo))))
111 return NULL;
112
113 if (drmIoctl(screen->fd, DRM_IOCTL_LIMA_GEM_CREATE, &req))
114 goto err_out0;
115
116 bo->screen = screen;
117 bo->size = req.size;
118 bo->handle = req.handle;
119 p_atomic_set(&bo->refcnt, 1);
120
121 if (!lima_bo_get_info(bo))
122 goto err_out1;
123
124 return bo;
125
126 err_out1:
127 lima_close_kms_handle(screen, bo->handle);
128 err_out0:
129 free(bo);
130 return NULL;
131 }
132
133 void lima_bo_free(struct lima_bo *bo)
134 {
135 if (!p_atomic_dec_zero(&bo->refcnt))
136 return;
137
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);
142 if (bo->flink_name)
143 util_hash_table_remove(screen->bo_flink_names,
144 (void *)(uintptr_t)bo->flink_name);
145 mtx_unlock(&screen->bo_table_lock);
146
147 if (bo->map)
148 lima_bo_unmap(bo);
149
150 lima_close_kms_handle(screen, bo->handle);
151 free(bo);
152 }
153
154 void *lima_bo_map(struct lima_bo *bo)
155 {
156 if (!bo->map) {
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)
160 bo->map = NULL;
161 }
162
163 return bo->map;
164 }
165
166 void lima_bo_unmap(struct lima_bo *bo)
167 {
168 if (bo->map) {
169 os_munmap(bo->map, bo->size);
170 bo->map = NULL;
171 }
172 }
173
174 bool lima_bo_export(struct lima_bo *bo, struct winsys_handle *handle)
175 {
176 struct lima_screen *screen = bo->screen;
177
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,
183 .name = 0,
184 };
185 if (drmIoctl(screen->fd, DRM_IOCTL_GEM_FLINK, &flink))
186 return false;
187
188 bo->flink_name = flink.name;
189
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);
194 }
195 handle->handle = bo->flink_name;
196 return true;
197
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);
203
204 handle->handle = bo->handle;
205 return true;
206
207 case WINSYS_HANDLE_TYPE_FD:
208 if (drmPrimeHandleToFD(screen->fd, bo->handle, DRM_CLOEXEC,
209 (int*)&handle->handle))
210 return false;
211
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);
216 return true;
217
218 default:
219 return false;
220 }
221 }
222
223 struct lima_bo *lima_bo_import(struct lima_screen *screen,
224 struct winsys_handle *handle)
225 {
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;
230
231 mtx_lock(&screen->bo_table_lock);
232
233 /* Convert a DMA buf handle to a KMS handle now. */
234 if (handle->type == WINSYS_HANDLE_TYPE_FD) {
235 uint32_t prime_handle;
236 off_t size;
237
238 /* Get a KMS handle. */
239 if (drmPrimeFDToHandle(screen->fd, h, &prime_handle)) {
240 mtx_unlock(&screen->bo_table_lock);
241 return NULL;
242 }
243
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);
249 return NULL;
250 }
251 lseek(h, 0, SEEK_SET);
252
253 dma_buf_size = size;
254 h = prime_handle;
255 }
256
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);
261 break;
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);
266 break;
267 default:
268 mtx_unlock(&screen->bo_table_lock);
269 return NULL;
270 }
271
272 if (bo) {
273 p_atomic_inc(&bo->refcnt);
274 mtx_unlock(&screen->bo_table_lock);
275 return bo;
276 }
277
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);
282 return NULL;
283 }
284
285 bo->screen = screen;
286 p_atomic_set(&bo->refcnt, 1);
287
288 switch (handle->type) {
289 case WINSYS_HANDLE_TYPE_SHARED:
290 req.name = h;
291 if (drmIoctl(screen->fd, DRM_IOCTL_GEM_OPEN, &req)) {
292 mtx_unlock(&screen->bo_table_lock);
293 free(bo);
294 return NULL;
295 }
296 bo->handle = req.handle;
297 bo->flink_name = h;
298 bo->size = req.size;
299 break;
300 case WINSYS_HANDLE_TYPE_FD:
301 bo->handle = h;
302 bo->size = dma_buf_size;
303 break;
304 default:
305 /* not possible */
306 assert(0);
307 }
308
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);
315 }
316 else {
317 lima_close_kms_handle(screen, bo->handle);
318 free(bo);
319 bo = NULL;
320 }
321
322 mtx_unlock(&screen->bo_table_lock);
323
324 return bo;
325 }
326
327 bool lima_bo_wait(struct lima_bo *bo, uint32_t op, uint64_t timeout_ns)
328 {
329 int64_t abs_timeout = os_time_get_absolute_timeout(timeout_ns);
330 if (abs_timeout == OS_TIMEOUT_INFINITE)
331 abs_timeout = INT64_MAX;
332
333 struct drm_lima_gem_wait req = {
334 .handle = bo->handle,
335 .op = op,
336 .timeout_ns = abs_timeout,
337 };
338
339 return drmIoctl(bo->screen->fd, DRM_IOCTL_LIMA_GEM_WAIT, &req) == 0;
340 }