1 /*
2 * Copyright (C) 2012-2018 Rob Clark <robclark@freedesktop.org>
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 (including the next
12 * paragraph) shall be included in all copies or substantial portions of the
13 * Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
18 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 * SOFTWARE.
22 *
23 * Authors:
24 * Rob Clark <robclark@freedesktop.org>
25 */
26
27 #include "os/os_mman.h"
28
29 #include "freedreno_drmif.h"
30 #include "freedreno_priv.h"
31
32 simple_mtx_t table_lock = _SIMPLE_MTX_INITIALIZER_NP;
33 void bo_del(struct fd_bo *bo);
34
35 /* set buffer name, and add to table, call w/ table_lock held: */
36 static void
set_name(struct fd_bo * bo,uint32_t name)37 set_name(struct fd_bo *bo, uint32_t name)
38 {
39 bo->name = name;
40 /* add ourself into the handle table: */
41 _mesa_hash_table_insert(bo->dev->name_table, &bo->name, bo);
42 }
43
44 /* lookup a buffer, call w/ table_lock held: */
45 static struct fd_bo *
lookup_bo(struct hash_table * tbl,uint32_t key)46 lookup_bo(struct hash_table *tbl, uint32_t key)
47 {
48 struct fd_bo *bo = NULL;
49 struct hash_entry *entry = _mesa_hash_table_search(tbl, &key);
50 if (entry) {
51 /* found, incr refcnt and return: */
52 bo = fd_bo_ref(entry->data);
53
54 /* don't break the bucket if this bo was found in one */
55 list_delinit(&bo->list);
56 }
57 return bo;
58 }
59
60 /* allocate a new buffer object, call w/ table_lock held */
61 static struct fd_bo *
bo_from_handle(struct fd_device * dev,uint32_t size,uint32_t handle)62 bo_from_handle(struct fd_device *dev, uint32_t size, uint32_t handle)
63 {
64 struct fd_bo *bo;
65
66 simple_mtx_assert_locked(&table_lock);
67
68 bo = dev->funcs->bo_from_handle(dev, size, handle);
69 if (!bo) {
70 struct drm_gem_close req = {
71 .handle = handle,
72 };
73 drmIoctl(dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
74 return NULL;
75 }
76 bo->dev = dev;
77 bo->size = size;
78 bo->handle = handle;
79 bo->iova = bo->funcs->iova(bo);
80 bo->reloc_flags = FD_RELOC_FLAGS_INIT;
81
82 p_atomic_set(&bo->refcnt, 1);
83 list_inithead(&bo->list);
84 /* add ourself into the handle table: */
85 _mesa_hash_table_insert(dev->handle_table, &bo->handle, bo);
86 return bo;
87 }
88
89 static struct fd_bo *
bo_new(struct fd_device * dev,uint32_t size,uint32_t flags,struct fd_bo_cache * cache)90 bo_new(struct fd_device *dev, uint32_t size, uint32_t flags,
91 struct fd_bo_cache *cache)
92 {
93 struct fd_bo *bo = NULL;
94 uint32_t handle;
95 int ret;
96
97 /* demote cached-coherent to WC if not supported: */
98 if ((flags & FD_BO_CACHED_COHERENT) && !dev->has_cached_coherent)
99 flags &= ~FD_BO_CACHED_COHERENT;
100
101 bo = fd_bo_cache_alloc(cache, &size, flags);
102 if (bo)
103 return bo;
104
105 ret = dev->funcs->bo_new_handle(dev, size, flags, &handle);
106 if (ret)
107 return NULL;
108
109 simple_mtx_lock(&table_lock);
110 bo = bo_from_handle(dev, size, handle);
111 simple_mtx_unlock(&table_lock);
112
113 bo->alloc_flags = flags;
114 bo->max_fences = 1;
115 bo->fences = &bo->_inline_fence;
116
117 VG_BO_ALLOC(bo);
118
119 return bo;
120 }
121
122 struct fd_bo *
_fd_bo_new(struct fd_device * dev,uint32_t size,uint32_t flags)123 _fd_bo_new(struct fd_device *dev, uint32_t size, uint32_t flags)
124 {
125 struct fd_bo *bo = bo_new(dev, size, flags, &dev->bo_cache);
126 if (bo)
127 bo->bo_reuse = BO_CACHE;
128 return bo;
129 }
130
131 void
_fd_bo_set_name(struct fd_bo * bo,const char * fmt,va_list ap)132 _fd_bo_set_name(struct fd_bo *bo, const char *fmt, va_list ap)
133 {
134 bo->funcs->set_name(bo, fmt, ap);
135 }
136
137 /* internal function to allocate bo's that use the ringbuffer cache
138 * instead of the normal bo_cache. The purpose is, because cmdstream
139 * bo's get vmap'd on the kernel side, and that is expensive, we want
140 * to re-use cmdstream bo's for cmdstream and not unrelated purposes.
141 */
142 struct fd_bo *
fd_bo_new_ring(struct fd_device * dev,uint32_t size)143 fd_bo_new_ring(struct fd_device *dev, uint32_t size)
144 {
145 uint32_t flags = FD_BO_GPUREADONLY | FD_BO_CACHED_COHERENT;
146 struct fd_bo *bo = bo_new(dev, size, flags, &dev->ring_cache);
147 if (bo) {
148 bo->bo_reuse = RING_CACHE;
149 bo->reloc_flags |= FD_RELOC_DUMP;
150 fd_bo_set_name(bo, "cmdstream");
151 }
152 return bo;
153 }
154
155 struct fd_bo *
fd_bo_from_handle(struct fd_device * dev,uint32_t handle,uint32_t size)156 fd_bo_from_handle(struct fd_device *dev, uint32_t handle, uint32_t size)
157 {
158 struct fd_bo *bo = NULL;
159
160 simple_mtx_lock(&table_lock);
161
162 bo = lookup_bo(dev->handle_table, handle);
163 if (bo)
164 goto out_unlock;
165
166 bo = bo_from_handle(dev, size, handle);
167
168 VG_BO_ALLOC(bo);
169
170 out_unlock:
171 simple_mtx_unlock(&table_lock);
172
173 return bo;
174 }
175
176 struct fd_bo *
fd_bo_from_dmabuf(struct fd_device * dev,int fd)177 fd_bo_from_dmabuf(struct fd_device *dev, int fd)
178 {
179 int ret, size;
180 uint32_t handle;
181 struct fd_bo *bo;
182
183 simple_mtx_lock(&table_lock);
184 ret = drmPrimeFDToHandle(dev->fd, fd, &handle);
185 if (ret) {
186 simple_mtx_unlock(&table_lock);
187 return NULL;
188 }
189
190 bo = lookup_bo(dev->handle_table, handle);
191 if (bo)
192 goto out_unlock;
193
194 /* lseek() to get bo size */
195 size = lseek(fd, 0, SEEK_END);
196 lseek(fd, 0, SEEK_CUR);
197
198 bo = bo_from_handle(dev, size, handle);
199
200 VG_BO_ALLOC(bo);
201
202 out_unlock:
203 simple_mtx_unlock(&table_lock);
204
205 return bo;
206 }
207
208 struct fd_bo *
fd_bo_from_name(struct fd_device * dev,uint32_t name)209 fd_bo_from_name(struct fd_device *dev, uint32_t name)
210 {
211 struct drm_gem_open req = {
212 .name = name,
213 };
214 struct fd_bo *bo;
215
216 simple_mtx_lock(&table_lock);
217
218 /* check name table first, to see if bo is already open: */
219 bo = lookup_bo(dev->name_table, name);
220 if (bo)
221 goto out_unlock;
222
223 if (drmIoctl(dev->fd, DRM_IOCTL_GEM_OPEN, &req)) {
224 ERROR_MSG("gem-open failed: %s", strerror(errno));
225 goto out_unlock;
226 }
227
228 bo = lookup_bo(dev->handle_table, req.handle);
229 if (bo)
230 goto out_unlock;
231
232 bo = bo_from_handle(dev, req.size, req.handle);
233 if (bo) {
234 set_name(bo, name);
235 VG_BO_ALLOC(bo);
236 }
237
238 out_unlock:
239 simple_mtx_unlock(&table_lock);
240
241 return bo;
242 }
243
244 void
fd_bo_mark_for_dump(struct fd_bo * bo)245 fd_bo_mark_for_dump(struct fd_bo *bo)
246 {
247 bo->reloc_flags |= FD_RELOC_DUMP;
248 }
249
250 uint64_t
fd_bo_get_iova(struct fd_bo * bo)251 fd_bo_get_iova(struct fd_bo *bo)
252 {
253 /* ancient kernels did not support this */
254 assert(bo->iova != 0);
255 return bo->iova;
256 }
257
258 struct fd_bo *
fd_bo_ref(struct fd_bo * bo)259 fd_bo_ref(struct fd_bo *bo)
260 {
261 p_atomic_inc(&bo->refcnt);
262 return bo;
263 }
264
265 static void
bo_del_or_recycle(struct fd_bo * bo)266 bo_del_or_recycle(struct fd_bo *bo)
267 {
268 struct fd_device *dev = bo->dev;
269
270 simple_mtx_assert_locked(&table_lock);
271
272 if ((bo->bo_reuse == BO_CACHE) &&
273 (fd_bo_cache_free(&dev->bo_cache, bo) == 0))
274 return;
275
276 if ((bo->bo_reuse == RING_CACHE) &&
277 (fd_bo_cache_free(&dev->ring_cache, bo) == 0))
278 return;
279
280 bo_del(bo);
281 }
282
283 void
fd_bo_del_locked(struct fd_bo * bo)284 fd_bo_del_locked(struct fd_bo *bo)
285 {
286 simple_mtx_assert_locked(&table_lock);
287
288 if (!p_atomic_dec_zero(&bo->refcnt))
289 return;
290
291 bo_del_or_recycle(bo);
292 }
293
294 void
fd_bo_del(struct fd_bo * bo)295 fd_bo_del(struct fd_bo *bo)
296 {
297 if (!p_atomic_dec_zero(&bo->refcnt))
298 return;
299
300 simple_mtx_lock(&table_lock);
301 bo_del_or_recycle(bo);
302 simple_mtx_unlock(&table_lock);
303 }
304
305 /**
306 * Cleanup fences, dropping pipe references. If 'expired' is true, only
307 * cleanup expired fences.
308 *
309 * Normally we expect at most a single fence, the exception being bo's
310 * shared between contexts
311 */
312 static void
cleanup_fences(struct fd_bo * bo,bool expired)313 cleanup_fences(struct fd_bo *bo, bool expired)
314 {
315 simple_mtx_assert_locked(&table_lock);
316
317 for (int i = 0; i < bo->nr_fences; i++) {
318 struct fd_bo_fence *f = &bo->fences[i];
319
320 if (expired && fd_fence_before(f->pipe->control->fence, f->fence))
321 continue;
322
323 struct fd_pipe *pipe = f->pipe;
324
325 bo->nr_fences--;
326
327 if (bo->nr_fences > 0) {
328 /* Shuffle up the last entry to replace the current slot: */
329 bo->fences[i] = bo->fences[bo->nr_fences];
330 i--;
331 }
332
333 fd_pipe_del_locked(pipe);
334 }
335 }
336
337 /* Called under table_lock */
338 void
bo_del(struct fd_bo * bo)339 bo_del(struct fd_bo *bo)
340 {
341 VG_BO_FREE(bo);
342
343 simple_mtx_assert_locked(&table_lock);
344
345 cleanup_fences(bo, false);
346 if (bo->fences != &bo->_inline_fence)
347 free(bo->fences);
348
349 if (bo->map)
350 os_munmap(bo->map, bo->size);
351
352 /* TODO probably bo's in bucket list get removed from
353 * handle table??
354 */
355
356 if (bo->handle) {
357 struct drm_gem_close req = {
358 .handle = bo->handle,
359 };
360 _mesa_hash_table_remove_key(bo->dev->handle_table, &bo->handle);
361 if (bo->name)
362 _mesa_hash_table_remove_key(bo->dev->name_table, &bo->name);
363 drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_CLOSE, &req);
364 }
365
366 bo->funcs->destroy(bo);
367 }
368
369 static void
bo_flush(struct fd_bo * bo)370 bo_flush(struct fd_bo *bo)
371 {
372 for (int i = 0; i < bo->nr_fences; i++) {
373 struct fd_bo_fence *f = &bo->fences[i];
374 fd_pipe_flush(f->pipe, f->fence);
375 }
376 }
377
378 int
fd_bo_get_name(struct fd_bo * bo,uint32_t * name)379 fd_bo_get_name(struct fd_bo *bo, uint32_t *name)
380 {
381 if (!bo->name) {
382 struct drm_gem_flink req = {
383 .handle = bo->handle,
384 };
385 int ret;
386
387 ret = drmIoctl(bo->dev->fd, DRM_IOCTL_GEM_FLINK, &req);
388 if (ret) {
389 return ret;
390 }
391
392 simple_mtx_lock(&table_lock);
393 set_name(bo, req.name);
394 simple_mtx_unlock(&table_lock);
395 bo->bo_reuse = NO_CACHE;
396 bo->shared = true;
397 bo_flush(bo);
398 }
399
400 *name = bo->name;
401
402 return 0;
403 }
404
405 uint32_t
fd_bo_handle(struct fd_bo * bo)406 fd_bo_handle(struct fd_bo *bo)
407 {
408 bo->bo_reuse = NO_CACHE;
409 bo->shared = true;
410 bo_flush(bo);
411 return bo->handle;
412 }
413
414 int
fd_bo_dmabuf(struct fd_bo * bo)415 fd_bo_dmabuf(struct fd_bo *bo)
416 {
417 int ret, prime_fd;
418
419 ret = drmPrimeHandleToFD(bo->dev->fd, bo->handle, DRM_CLOEXEC, &prime_fd);
420 if (ret) {
421 ERROR_MSG("failed to get dmabuf fd: %d", ret);
422 return ret;
423 }
424
425 bo->bo_reuse = NO_CACHE;
426 bo->shared = true;
427 bo_flush(bo);
428
429 return prime_fd;
430 }
431
432 uint32_t
fd_bo_size(struct fd_bo * bo)433 fd_bo_size(struct fd_bo *bo)
434 {
435 return bo->size;
436 }
437
438 bool
fd_bo_is_cached(struct fd_bo * bo)439 fd_bo_is_cached(struct fd_bo *bo)
440 {
441 return !!(bo->alloc_flags & FD_BO_CACHED_COHERENT);
442 }
443
444 void *
fd_bo_map(struct fd_bo * bo)445 fd_bo_map(struct fd_bo *bo)
446 {
447 if (!bo->map) {
448 uint64_t offset;
449 int ret;
450
451 ret = bo->funcs->offset(bo, &offset);
452 if (ret) {
453 return NULL;
454 }
455
456 bo->map = os_mmap(0, bo->size, PROT_READ | PROT_WRITE, MAP_SHARED,
457 bo->dev->fd, offset);
458 if (bo->map == MAP_FAILED) {
459 ERROR_MSG("mmap failed: %s", strerror(errno));
460 bo->map = NULL;
461 }
462 }
463 return bo->map;
464 }
465
466 /* a bit odd to take the pipe as an arg, but it's a, umm, quirk of kgsl.. */
467 int
fd_bo_cpu_prep(struct fd_bo * bo,struct fd_pipe * pipe,uint32_t op)468 fd_bo_cpu_prep(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t op)
469 {
470 if (op & (FD_BO_PREP_NOSYNC | FD_BO_PREP_FLUSH)) {
471 simple_mtx_lock(&table_lock);
472 enum fd_bo_state state = fd_bo_state(bo);
473 simple_mtx_unlock(&table_lock);
474
475 if (state == FD_BO_STATE_IDLE)
476 return 0;
477
478 if (op & FD_BO_PREP_FLUSH)
479 bo_flush(bo);
480
481 /* If we have *only* been asked to flush, then we aren't really
482 * interested about whether shared buffers are busy, so avoid
483 * the kernel ioctl.
484 */
485 if ((state == FD_BO_STATE_BUSY) ||
486 (op == FD_BO_PREP_FLUSH))
487 return -EBUSY;
488 }
489
490 /* In case the bo is referenced by a deferred submit, flush up to the
491 * required fence now:
492 */
493 bo_flush(bo);
494
495 /* FD_BO_PREP_FLUSH is purely a frontend flag, and is not seen/handled
496 * by backend or kernel:
497 */
498 return bo->funcs->cpu_prep(bo, pipe, op & ~FD_BO_PREP_FLUSH);
499 }
500
501 void
fd_bo_cpu_fini(struct fd_bo * bo)502 fd_bo_cpu_fini(struct fd_bo *bo)
503 {
504 // TODO until we have cached buffers, the kernel side ioctl does nothing,
505 // so just skip it. When we have cached buffers, we can make the
506 // ioctl conditional
507 // bo->funcs->cpu_fini(bo);
508 }
509
510 void
fd_bo_add_fence(struct fd_bo * bo,struct fd_pipe * pipe,uint32_t fence)511 fd_bo_add_fence(struct fd_bo *bo, struct fd_pipe *pipe, uint32_t fence)
512 {
513 simple_mtx_assert_locked(&table_lock);
514
515 if (bo->nosync)
516 return;
517
518 /* The common case is bo re-used on the same pipe it had previously
519 * been used on:
520 */
521 for (int i = 0; i < bo->nr_fences; i++) {
522 struct fd_bo_fence *f = &bo->fences[i];
523 if (f->pipe == pipe) {
524 assert(fd_fence_before(f->fence, fence));
525 f->fence = fence;
526 return;
527 }
528 }
529
530 cleanup_fences(bo, true);
531
532 /* The first time we grow past a single fence, we need some special
533 * handling, as we've been using the embedded _inline_fence to avoid
534 * a separate allocation:
535 */
536 if (unlikely((bo->nr_fences == 1) &&
537 (bo->fences == &bo->_inline_fence))) {
538 bo->nr_fences = bo->max_fences = 0;
539 bo->fences = NULL;
540 APPEND(bo, fences, bo->_inline_fence);
541 }
542
543 APPEND(bo, fences, (struct fd_bo_fence){
544 .pipe = fd_pipe_ref_locked(pipe),
545 .fence = fence,
546 });
547 }
548
549 enum fd_bo_state
fd_bo_state(struct fd_bo * bo)550 fd_bo_state(struct fd_bo *bo)
551 {
552 simple_mtx_assert_locked(&table_lock);
553
554 cleanup_fences(bo, true);
555
556 if (bo->shared || bo->nosync)
557 return FD_BO_STATE_UNKNOWN;
558
559 if (!bo->nr_fences)
560 return FD_BO_STATE_IDLE;
561
562 return FD_BO_STATE_BUSY;
563 }
564
565