1e4812ab8SDmitry Osipenko // SPDX-License-Identifier: MIT
2e4812ab8SDmitry Osipenko /*
3e4812ab8SDmitry Osipenko * Copyright (C) 2015 Red Hat, Inc.
4e4812ab8SDmitry Osipenko * All Rights Reserved.
5e4812ab8SDmitry Osipenko *
6e4812ab8SDmitry Osipenko * Authors:
7e4812ab8SDmitry Osipenko * Dave Airlie
8e4812ab8SDmitry Osipenko * Alon Levy
9e4812ab8SDmitry Osipenko */
10e4812ab8SDmitry Osipenko
11e4812ab8SDmitry Osipenko #include <linux/dma-fence-unwrap.h>
12e4812ab8SDmitry Osipenko #include <linux/file.h>
13e4812ab8SDmitry Osipenko #include <linux/sync_file.h>
14e4812ab8SDmitry Osipenko #include <linux/uaccess.h>
15e4812ab8SDmitry Osipenko
16e4812ab8SDmitry Osipenko #include <drm/drm_file.h>
177cb8d1abSDmitry Osipenko #include <drm/drm_syncobj.h>
18e4812ab8SDmitry Osipenko #include <drm/virtgpu_drm.h>
19e4812ab8SDmitry Osipenko
20e4812ab8SDmitry Osipenko #include "virtgpu_drv.h"
21e4812ab8SDmitry Osipenko
227cb8d1abSDmitry Osipenko struct virtio_gpu_submit_post_dep {
237cb8d1abSDmitry Osipenko struct drm_syncobj *syncobj;
247cb8d1abSDmitry Osipenko struct dma_fence_chain *chain;
257cb8d1abSDmitry Osipenko u64 point;
267cb8d1abSDmitry Osipenko };
277cb8d1abSDmitry Osipenko
28e4812ab8SDmitry Osipenko struct virtio_gpu_submit {
297cb8d1abSDmitry Osipenko struct virtio_gpu_submit_post_dep *post_deps;
307cb8d1abSDmitry Osipenko unsigned int num_out_syncobjs;
317cb8d1abSDmitry Osipenko
327cb8d1abSDmitry Osipenko struct drm_syncobj **in_syncobjs;
337cb8d1abSDmitry Osipenko unsigned int num_in_syncobjs;
347cb8d1abSDmitry Osipenko
35e4812ab8SDmitry Osipenko struct virtio_gpu_object_array *buflist;
36e4812ab8SDmitry Osipenko struct drm_virtgpu_execbuffer *exbuf;
37e4812ab8SDmitry Osipenko struct virtio_gpu_fence *out_fence;
38e4812ab8SDmitry Osipenko struct virtio_gpu_fpriv *vfpriv;
39e4812ab8SDmitry Osipenko struct virtio_gpu_device *vgdev;
40e4812ab8SDmitry Osipenko struct sync_file *sync_file;
41e4812ab8SDmitry Osipenko struct drm_file *file;
42e4812ab8SDmitry Osipenko int out_fence_fd;
43e4812ab8SDmitry Osipenko u64 fence_ctx;
44e4812ab8SDmitry Osipenko u32 ring_idx;
45e4812ab8SDmitry Osipenko void *buf;
46e4812ab8SDmitry Osipenko };
47e4812ab8SDmitry Osipenko
virtio_gpu_do_fence_wait(struct virtio_gpu_submit * submit,struct dma_fence * in_fence)48eba57fb5SDmitry Osipenko static int virtio_gpu_do_fence_wait(struct virtio_gpu_submit *submit,
49e4812ab8SDmitry Osipenko struct dma_fence *in_fence)
50e4812ab8SDmitry Osipenko {
51*a62c9814SDmitry Osipenko u64 context = submit->fence_ctx + submit->ring_idx;
52e4812ab8SDmitry Osipenko
53e4812ab8SDmitry Osipenko if (dma_fence_match_context(in_fence, context))
54e4812ab8SDmitry Osipenko return 0;
55e4812ab8SDmitry Osipenko
56e4812ab8SDmitry Osipenko return dma_fence_wait(in_fence, true);
57e4812ab8SDmitry Osipenko }
58e4812ab8SDmitry Osipenko
virtio_gpu_dma_fence_wait(struct virtio_gpu_submit * submit,struct dma_fence * fence)59eba57fb5SDmitry Osipenko static int virtio_gpu_dma_fence_wait(struct virtio_gpu_submit *submit,
60eba57fb5SDmitry Osipenko struct dma_fence *fence)
61eba57fb5SDmitry Osipenko {
62eba57fb5SDmitry Osipenko struct dma_fence_unwrap itr;
63eba57fb5SDmitry Osipenko struct dma_fence *f;
64eba57fb5SDmitry Osipenko int err;
65eba57fb5SDmitry Osipenko
66eba57fb5SDmitry Osipenko dma_fence_unwrap_for_each(f, &itr, fence) {
67eba57fb5SDmitry Osipenko err = virtio_gpu_do_fence_wait(submit, f);
68eba57fb5SDmitry Osipenko if (err)
69eba57fb5SDmitry Osipenko return err;
70eba57fb5SDmitry Osipenko }
71eba57fb5SDmitry Osipenko
72eba57fb5SDmitry Osipenko return 0;
73eba57fb5SDmitry Osipenko }
74eba57fb5SDmitry Osipenko
virtio_gpu_free_syncobjs(struct drm_syncobj ** syncobjs,u32 nr_syncobjs)757cb8d1abSDmitry Osipenko static void virtio_gpu_free_syncobjs(struct drm_syncobj **syncobjs,
767cb8d1abSDmitry Osipenko u32 nr_syncobjs)
777cb8d1abSDmitry Osipenko {
787cb8d1abSDmitry Osipenko u32 i = nr_syncobjs;
797cb8d1abSDmitry Osipenko
807cb8d1abSDmitry Osipenko while (i--) {
817cb8d1abSDmitry Osipenko if (syncobjs[i])
827cb8d1abSDmitry Osipenko drm_syncobj_put(syncobjs[i]);
837cb8d1abSDmitry Osipenko }
847cb8d1abSDmitry Osipenko
857cb8d1abSDmitry Osipenko kvfree(syncobjs);
867cb8d1abSDmitry Osipenko }
877cb8d1abSDmitry Osipenko
887cb8d1abSDmitry Osipenko static int
virtio_gpu_parse_deps(struct virtio_gpu_submit * submit)897cb8d1abSDmitry Osipenko virtio_gpu_parse_deps(struct virtio_gpu_submit *submit)
907cb8d1abSDmitry Osipenko {
917cb8d1abSDmitry Osipenko struct drm_virtgpu_execbuffer *exbuf = submit->exbuf;
927cb8d1abSDmitry Osipenko struct drm_virtgpu_execbuffer_syncobj syncobj_desc;
937cb8d1abSDmitry Osipenko size_t syncobj_stride = exbuf->syncobj_stride;
947cb8d1abSDmitry Osipenko u32 num_in_syncobjs = exbuf->num_in_syncobjs;
957cb8d1abSDmitry Osipenko struct drm_syncobj **syncobjs;
967cb8d1abSDmitry Osipenko int ret = 0, i;
977cb8d1abSDmitry Osipenko
987cb8d1abSDmitry Osipenko if (!num_in_syncobjs)
997cb8d1abSDmitry Osipenko return 0;
1007cb8d1abSDmitry Osipenko
1017cb8d1abSDmitry Osipenko /*
1027cb8d1abSDmitry Osipenko * kvalloc at first tries to allocate memory using kmalloc and
1037cb8d1abSDmitry Osipenko * falls back to vmalloc only on failure. It also uses __GFP_NOWARN
1047cb8d1abSDmitry Osipenko * internally for allocations larger than a page size, preventing
1057cb8d1abSDmitry Osipenko * storm of KMSG warnings.
1067cb8d1abSDmitry Osipenko */
1077cb8d1abSDmitry Osipenko syncobjs = kvcalloc(num_in_syncobjs, sizeof(*syncobjs), GFP_KERNEL);
1087cb8d1abSDmitry Osipenko if (!syncobjs)
1097cb8d1abSDmitry Osipenko return -ENOMEM;
1107cb8d1abSDmitry Osipenko
1117cb8d1abSDmitry Osipenko for (i = 0; i < num_in_syncobjs; i++) {
1127cb8d1abSDmitry Osipenko u64 address = exbuf->in_syncobjs + i * syncobj_stride;
1137cb8d1abSDmitry Osipenko struct dma_fence *fence;
1147cb8d1abSDmitry Osipenko
1157cb8d1abSDmitry Osipenko memset(&syncobj_desc, 0, sizeof(syncobj_desc));
1167cb8d1abSDmitry Osipenko
1177cb8d1abSDmitry Osipenko if (copy_from_user(&syncobj_desc,
1187cb8d1abSDmitry Osipenko u64_to_user_ptr(address),
1197cb8d1abSDmitry Osipenko min(syncobj_stride, sizeof(syncobj_desc)))) {
1207cb8d1abSDmitry Osipenko ret = -EFAULT;
1217cb8d1abSDmitry Osipenko break;
1227cb8d1abSDmitry Osipenko }
1237cb8d1abSDmitry Osipenko
1247cb8d1abSDmitry Osipenko if (syncobj_desc.flags & ~VIRTGPU_EXECBUF_SYNCOBJ_FLAGS) {
1257cb8d1abSDmitry Osipenko ret = -EINVAL;
1267cb8d1abSDmitry Osipenko break;
1277cb8d1abSDmitry Osipenko }
1287cb8d1abSDmitry Osipenko
1297cb8d1abSDmitry Osipenko ret = drm_syncobj_find_fence(submit->file, syncobj_desc.handle,
1307cb8d1abSDmitry Osipenko syncobj_desc.point, 0, &fence);
1317cb8d1abSDmitry Osipenko if (ret)
1327cb8d1abSDmitry Osipenko break;
1337cb8d1abSDmitry Osipenko
1347cb8d1abSDmitry Osipenko ret = virtio_gpu_dma_fence_wait(submit, fence);
1357cb8d1abSDmitry Osipenko
1367cb8d1abSDmitry Osipenko dma_fence_put(fence);
1377cb8d1abSDmitry Osipenko if (ret)
1387cb8d1abSDmitry Osipenko break;
1397cb8d1abSDmitry Osipenko
1407cb8d1abSDmitry Osipenko if (syncobj_desc.flags & VIRTGPU_EXECBUF_SYNCOBJ_RESET) {
1417cb8d1abSDmitry Osipenko syncobjs[i] = drm_syncobj_find(submit->file,
1427cb8d1abSDmitry Osipenko syncobj_desc.handle);
1437cb8d1abSDmitry Osipenko if (!syncobjs[i]) {
1447cb8d1abSDmitry Osipenko ret = -EINVAL;
1457cb8d1abSDmitry Osipenko break;
1467cb8d1abSDmitry Osipenko }
1477cb8d1abSDmitry Osipenko }
1487cb8d1abSDmitry Osipenko }
1497cb8d1abSDmitry Osipenko
1507cb8d1abSDmitry Osipenko if (ret) {
1517cb8d1abSDmitry Osipenko virtio_gpu_free_syncobjs(syncobjs, i);
1527cb8d1abSDmitry Osipenko return ret;
1537cb8d1abSDmitry Osipenko }
1547cb8d1abSDmitry Osipenko
1557cb8d1abSDmitry Osipenko submit->num_in_syncobjs = num_in_syncobjs;
1567cb8d1abSDmitry Osipenko submit->in_syncobjs = syncobjs;
1577cb8d1abSDmitry Osipenko
1587cb8d1abSDmitry Osipenko return ret;
1597cb8d1abSDmitry Osipenko }
1607cb8d1abSDmitry Osipenko
virtio_gpu_reset_syncobjs(struct drm_syncobj ** syncobjs,u32 nr_syncobjs)1617cb8d1abSDmitry Osipenko static void virtio_gpu_reset_syncobjs(struct drm_syncobj **syncobjs,
1627cb8d1abSDmitry Osipenko u32 nr_syncobjs)
1637cb8d1abSDmitry Osipenko {
1647cb8d1abSDmitry Osipenko u32 i;
1657cb8d1abSDmitry Osipenko
1667cb8d1abSDmitry Osipenko for (i = 0; i < nr_syncobjs; i++) {
1677cb8d1abSDmitry Osipenko if (syncobjs[i])
1687cb8d1abSDmitry Osipenko drm_syncobj_replace_fence(syncobjs[i], NULL);
1697cb8d1abSDmitry Osipenko }
1707cb8d1abSDmitry Osipenko }
1717cb8d1abSDmitry Osipenko
1727cb8d1abSDmitry Osipenko static void
virtio_gpu_free_post_deps(struct virtio_gpu_submit_post_dep * post_deps,u32 nr_syncobjs)1737cb8d1abSDmitry Osipenko virtio_gpu_free_post_deps(struct virtio_gpu_submit_post_dep *post_deps,
1747cb8d1abSDmitry Osipenko u32 nr_syncobjs)
1757cb8d1abSDmitry Osipenko {
1767cb8d1abSDmitry Osipenko u32 i = nr_syncobjs;
1777cb8d1abSDmitry Osipenko
1787cb8d1abSDmitry Osipenko while (i--) {
1797cb8d1abSDmitry Osipenko kfree(post_deps[i].chain);
1807cb8d1abSDmitry Osipenko drm_syncobj_put(post_deps[i].syncobj);
1817cb8d1abSDmitry Osipenko }
1827cb8d1abSDmitry Osipenko
1837cb8d1abSDmitry Osipenko kvfree(post_deps);
1847cb8d1abSDmitry Osipenko }
1857cb8d1abSDmitry Osipenko
virtio_gpu_parse_post_deps(struct virtio_gpu_submit * submit)1867cb8d1abSDmitry Osipenko static int virtio_gpu_parse_post_deps(struct virtio_gpu_submit *submit)
1877cb8d1abSDmitry Osipenko {
1887cb8d1abSDmitry Osipenko struct drm_virtgpu_execbuffer *exbuf = submit->exbuf;
1897cb8d1abSDmitry Osipenko struct drm_virtgpu_execbuffer_syncobj syncobj_desc;
1907cb8d1abSDmitry Osipenko struct virtio_gpu_submit_post_dep *post_deps;
1917cb8d1abSDmitry Osipenko u32 num_out_syncobjs = exbuf->num_out_syncobjs;
1927cb8d1abSDmitry Osipenko size_t syncobj_stride = exbuf->syncobj_stride;
1937cb8d1abSDmitry Osipenko int ret = 0, i;
1947cb8d1abSDmitry Osipenko
1957cb8d1abSDmitry Osipenko if (!num_out_syncobjs)
1967cb8d1abSDmitry Osipenko return 0;
1977cb8d1abSDmitry Osipenko
1987cb8d1abSDmitry Osipenko post_deps = kvcalloc(num_out_syncobjs, sizeof(*post_deps), GFP_KERNEL);
1997cb8d1abSDmitry Osipenko if (!post_deps)
2007cb8d1abSDmitry Osipenko return -ENOMEM;
2017cb8d1abSDmitry Osipenko
2027cb8d1abSDmitry Osipenko for (i = 0; i < num_out_syncobjs; i++) {
2037cb8d1abSDmitry Osipenko u64 address = exbuf->out_syncobjs + i * syncobj_stride;
2047cb8d1abSDmitry Osipenko
2057cb8d1abSDmitry Osipenko memset(&syncobj_desc, 0, sizeof(syncobj_desc));
2067cb8d1abSDmitry Osipenko
2077cb8d1abSDmitry Osipenko if (copy_from_user(&syncobj_desc,
2087cb8d1abSDmitry Osipenko u64_to_user_ptr(address),
2097cb8d1abSDmitry Osipenko min(syncobj_stride, sizeof(syncobj_desc)))) {
2107cb8d1abSDmitry Osipenko ret = -EFAULT;
2117cb8d1abSDmitry Osipenko break;
2127cb8d1abSDmitry Osipenko }
2137cb8d1abSDmitry Osipenko
2147cb8d1abSDmitry Osipenko post_deps[i].point = syncobj_desc.point;
2157cb8d1abSDmitry Osipenko
2167cb8d1abSDmitry Osipenko if (syncobj_desc.flags) {
2177cb8d1abSDmitry Osipenko ret = -EINVAL;
2187cb8d1abSDmitry Osipenko break;
2197cb8d1abSDmitry Osipenko }
2207cb8d1abSDmitry Osipenko
2217cb8d1abSDmitry Osipenko if (syncobj_desc.point) {
2227cb8d1abSDmitry Osipenko post_deps[i].chain = dma_fence_chain_alloc();
2237cb8d1abSDmitry Osipenko if (!post_deps[i].chain) {
2247cb8d1abSDmitry Osipenko ret = -ENOMEM;
2257cb8d1abSDmitry Osipenko break;
2267cb8d1abSDmitry Osipenko }
2277cb8d1abSDmitry Osipenko }
2287cb8d1abSDmitry Osipenko
2297cb8d1abSDmitry Osipenko post_deps[i].syncobj = drm_syncobj_find(submit->file,
2307cb8d1abSDmitry Osipenko syncobj_desc.handle);
2317cb8d1abSDmitry Osipenko if (!post_deps[i].syncobj) {
2327cb8d1abSDmitry Osipenko kfree(post_deps[i].chain);
2337cb8d1abSDmitry Osipenko ret = -EINVAL;
2347cb8d1abSDmitry Osipenko break;
2357cb8d1abSDmitry Osipenko }
2367cb8d1abSDmitry Osipenko }
2377cb8d1abSDmitry Osipenko
2387cb8d1abSDmitry Osipenko if (ret) {
2397cb8d1abSDmitry Osipenko virtio_gpu_free_post_deps(post_deps, i);
2407cb8d1abSDmitry Osipenko return ret;
2417cb8d1abSDmitry Osipenko }
2427cb8d1abSDmitry Osipenko
2437cb8d1abSDmitry Osipenko submit->num_out_syncobjs = num_out_syncobjs;
2447cb8d1abSDmitry Osipenko submit->post_deps = post_deps;
2457cb8d1abSDmitry Osipenko
2467cb8d1abSDmitry Osipenko return 0;
2477cb8d1abSDmitry Osipenko }
2487cb8d1abSDmitry Osipenko
2497cb8d1abSDmitry Osipenko static void
virtio_gpu_process_post_deps(struct virtio_gpu_submit * submit)2507cb8d1abSDmitry Osipenko virtio_gpu_process_post_deps(struct virtio_gpu_submit *submit)
2517cb8d1abSDmitry Osipenko {
2527cb8d1abSDmitry Osipenko struct virtio_gpu_submit_post_dep *post_deps = submit->post_deps;
2537cb8d1abSDmitry Osipenko
2547cb8d1abSDmitry Osipenko if (post_deps) {
2557cb8d1abSDmitry Osipenko struct dma_fence *fence = &submit->out_fence->f;
2567cb8d1abSDmitry Osipenko u32 i;
2577cb8d1abSDmitry Osipenko
2587cb8d1abSDmitry Osipenko for (i = 0; i < submit->num_out_syncobjs; i++) {
2597cb8d1abSDmitry Osipenko if (post_deps[i].chain) {
2607cb8d1abSDmitry Osipenko drm_syncobj_add_point(post_deps[i].syncobj,
2617cb8d1abSDmitry Osipenko post_deps[i].chain,
2627cb8d1abSDmitry Osipenko fence, post_deps[i].point);
2637cb8d1abSDmitry Osipenko post_deps[i].chain = NULL;
2647cb8d1abSDmitry Osipenko } else {
2657cb8d1abSDmitry Osipenko drm_syncobj_replace_fence(post_deps[i].syncobj,
2667cb8d1abSDmitry Osipenko fence);
2677cb8d1abSDmitry Osipenko }
2687cb8d1abSDmitry Osipenko }
2697cb8d1abSDmitry Osipenko }
2707cb8d1abSDmitry Osipenko }
2717cb8d1abSDmitry Osipenko
virtio_gpu_fence_event_create(struct drm_device * dev,struct drm_file * file,struct virtio_gpu_fence * fence,u32 ring_idx)272e4812ab8SDmitry Osipenko static int virtio_gpu_fence_event_create(struct drm_device *dev,
273e4812ab8SDmitry Osipenko struct drm_file *file,
274e4812ab8SDmitry Osipenko struct virtio_gpu_fence *fence,
275e4812ab8SDmitry Osipenko u32 ring_idx)
276e4812ab8SDmitry Osipenko {
277e4812ab8SDmitry Osipenko struct virtio_gpu_fence_event *e = NULL;
278e4812ab8SDmitry Osipenko int ret;
279e4812ab8SDmitry Osipenko
280e4812ab8SDmitry Osipenko e = kzalloc(sizeof(*e), GFP_KERNEL);
281e4812ab8SDmitry Osipenko if (!e)
282e4812ab8SDmitry Osipenko return -ENOMEM;
283e4812ab8SDmitry Osipenko
284e4812ab8SDmitry Osipenko e->event.type = VIRTGPU_EVENT_FENCE_SIGNALED;
285e4812ab8SDmitry Osipenko e->event.length = sizeof(e->event);
286e4812ab8SDmitry Osipenko
287e4812ab8SDmitry Osipenko ret = drm_event_reserve_init(dev, file, &e->base, &e->event);
288e4812ab8SDmitry Osipenko if (ret) {
289e4812ab8SDmitry Osipenko kfree(e);
290e4812ab8SDmitry Osipenko return ret;
291e4812ab8SDmitry Osipenko }
292e4812ab8SDmitry Osipenko
293e4812ab8SDmitry Osipenko fence->e = e;
294e4812ab8SDmitry Osipenko
295e4812ab8SDmitry Osipenko return 0;
296e4812ab8SDmitry Osipenko }
297e4812ab8SDmitry Osipenko
virtio_gpu_init_submit_buflist(struct virtio_gpu_submit * submit)298e4812ab8SDmitry Osipenko static int virtio_gpu_init_submit_buflist(struct virtio_gpu_submit *submit)
299e4812ab8SDmitry Osipenko {
300e4812ab8SDmitry Osipenko struct drm_virtgpu_execbuffer *exbuf = submit->exbuf;
301e4812ab8SDmitry Osipenko u32 *bo_handles;
302e4812ab8SDmitry Osipenko
303e4812ab8SDmitry Osipenko if (!exbuf->num_bo_handles)
304e4812ab8SDmitry Osipenko return 0;
305e4812ab8SDmitry Osipenko
306e4812ab8SDmitry Osipenko bo_handles = kvmalloc_array(exbuf->num_bo_handles, sizeof(*bo_handles),
307e4812ab8SDmitry Osipenko GFP_KERNEL);
308e4812ab8SDmitry Osipenko if (!bo_handles)
309e4812ab8SDmitry Osipenko return -ENOMEM;
310e4812ab8SDmitry Osipenko
311e4812ab8SDmitry Osipenko if (copy_from_user(bo_handles, u64_to_user_ptr(exbuf->bo_handles),
312e4812ab8SDmitry Osipenko exbuf->num_bo_handles * sizeof(*bo_handles))) {
313e4812ab8SDmitry Osipenko kvfree(bo_handles);
314e4812ab8SDmitry Osipenko return -EFAULT;
315e4812ab8SDmitry Osipenko }
316e4812ab8SDmitry Osipenko
317e4812ab8SDmitry Osipenko submit->buflist = virtio_gpu_array_from_handles(submit->file, bo_handles,
318e4812ab8SDmitry Osipenko exbuf->num_bo_handles);
319e4812ab8SDmitry Osipenko if (!submit->buflist) {
320e4812ab8SDmitry Osipenko kvfree(bo_handles);
321e4812ab8SDmitry Osipenko return -ENOENT;
322e4812ab8SDmitry Osipenko }
323e4812ab8SDmitry Osipenko
324e4812ab8SDmitry Osipenko kvfree(bo_handles);
325e4812ab8SDmitry Osipenko
326e4812ab8SDmitry Osipenko return 0;
327e4812ab8SDmitry Osipenko }
328e4812ab8SDmitry Osipenko
virtio_gpu_cleanup_submit(struct virtio_gpu_submit * submit)329e4812ab8SDmitry Osipenko static void virtio_gpu_cleanup_submit(struct virtio_gpu_submit *submit)
330e4812ab8SDmitry Osipenko {
3317cb8d1abSDmitry Osipenko virtio_gpu_reset_syncobjs(submit->in_syncobjs, submit->num_in_syncobjs);
3327cb8d1abSDmitry Osipenko virtio_gpu_free_syncobjs(submit->in_syncobjs, submit->num_in_syncobjs);
3337cb8d1abSDmitry Osipenko virtio_gpu_free_post_deps(submit->post_deps, submit->num_out_syncobjs);
3347cb8d1abSDmitry Osipenko
335e4812ab8SDmitry Osipenko if (!IS_ERR(submit->buf))
336e4812ab8SDmitry Osipenko kvfree(submit->buf);
337e4812ab8SDmitry Osipenko
338e4812ab8SDmitry Osipenko if (submit->buflist)
339e4812ab8SDmitry Osipenko virtio_gpu_array_put_free(submit->buflist);
340e4812ab8SDmitry Osipenko
341e4812ab8SDmitry Osipenko if (submit->out_fence_fd >= 0)
342e4812ab8SDmitry Osipenko put_unused_fd(submit->out_fence_fd);
343e4812ab8SDmitry Osipenko
344e4812ab8SDmitry Osipenko if (submit->out_fence)
345e4812ab8SDmitry Osipenko dma_fence_put(&submit->out_fence->f);
346e4812ab8SDmitry Osipenko
347e4812ab8SDmitry Osipenko if (submit->sync_file)
348e4812ab8SDmitry Osipenko fput(submit->sync_file->file);
349e4812ab8SDmitry Osipenko }
350e4812ab8SDmitry Osipenko
virtio_gpu_submit(struct virtio_gpu_submit * submit)351e4812ab8SDmitry Osipenko static void virtio_gpu_submit(struct virtio_gpu_submit *submit)
352e4812ab8SDmitry Osipenko {
353e4812ab8SDmitry Osipenko virtio_gpu_cmd_submit(submit->vgdev, submit->buf, submit->exbuf->size,
354e4812ab8SDmitry Osipenko submit->vfpriv->ctx_id, submit->buflist,
355e4812ab8SDmitry Osipenko submit->out_fence);
356e4812ab8SDmitry Osipenko virtio_gpu_notify(submit->vgdev);
357e4812ab8SDmitry Osipenko }
358e4812ab8SDmitry Osipenko
virtio_gpu_complete_submit(struct virtio_gpu_submit * submit)359e4812ab8SDmitry Osipenko static void virtio_gpu_complete_submit(struct virtio_gpu_submit *submit)
360e4812ab8SDmitry Osipenko {
361e4812ab8SDmitry Osipenko submit->buf = NULL;
362e4812ab8SDmitry Osipenko submit->buflist = NULL;
363e4812ab8SDmitry Osipenko submit->sync_file = NULL;
364e4812ab8SDmitry Osipenko submit->out_fence_fd = -1;
365e4812ab8SDmitry Osipenko }
366e4812ab8SDmitry Osipenko
virtio_gpu_init_submit(struct virtio_gpu_submit * submit,struct drm_virtgpu_execbuffer * exbuf,struct drm_device * dev,struct drm_file * file,u64 fence_ctx,u32 ring_idx)367e4812ab8SDmitry Osipenko static int virtio_gpu_init_submit(struct virtio_gpu_submit *submit,
368e4812ab8SDmitry Osipenko struct drm_virtgpu_execbuffer *exbuf,
369e4812ab8SDmitry Osipenko struct drm_device *dev,
370e4812ab8SDmitry Osipenko struct drm_file *file,
371e4812ab8SDmitry Osipenko u64 fence_ctx, u32 ring_idx)
372e4812ab8SDmitry Osipenko {
373e4812ab8SDmitry Osipenko struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
374e4812ab8SDmitry Osipenko struct virtio_gpu_device *vgdev = dev->dev_private;
375e4812ab8SDmitry Osipenko struct virtio_gpu_fence *out_fence;
37670d1ace5SGurchetan Singh bool drm_fence_event;
377e4812ab8SDmitry Osipenko int err;
378e4812ab8SDmitry Osipenko
379e4812ab8SDmitry Osipenko memset(submit, 0, sizeof(*submit));
380e4812ab8SDmitry Osipenko
38170d1ace5SGurchetan Singh if ((exbuf->flags & VIRTGPU_EXECBUF_RING_IDX) &&
38270d1ace5SGurchetan Singh (vfpriv->ring_idx_mask & BIT_ULL(ring_idx)))
38370d1ace5SGurchetan Singh drm_fence_event = true;
38470d1ace5SGurchetan Singh else
38570d1ace5SGurchetan Singh drm_fence_event = false;
386e4812ab8SDmitry Osipenko
38770d1ace5SGurchetan Singh if ((exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_OUT) ||
3887cb8d1abSDmitry Osipenko exbuf->num_out_syncobjs ||
38970d1ace5SGurchetan Singh exbuf->num_bo_handles ||
39070d1ace5SGurchetan Singh drm_fence_event)
39170d1ace5SGurchetan Singh out_fence = virtio_gpu_fence_alloc(vgdev, fence_ctx, ring_idx);
39270d1ace5SGurchetan Singh else
39370d1ace5SGurchetan Singh out_fence = NULL;
39470d1ace5SGurchetan Singh
39570d1ace5SGurchetan Singh if (drm_fence_event) {
396e4812ab8SDmitry Osipenko err = virtio_gpu_fence_event_create(dev, file, out_fence, ring_idx);
397e4812ab8SDmitry Osipenko if (err) {
398e4812ab8SDmitry Osipenko dma_fence_put(&out_fence->f);
399e4812ab8SDmitry Osipenko return err;
400e4812ab8SDmitry Osipenko }
40170d1ace5SGurchetan Singh }
402e4812ab8SDmitry Osipenko
403e4812ab8SDmitry Osipenko submit->out_fence = out_fence;
404e4812ab8SDmitry Osipenko submit->fence_ctx = fence_ctx;
405e4812ab8SDmitry Osipenko submit->ring_idx = ring_idx;
406e4812ab8SDmitry Osipenko submit->out_fence_fd = -1;
407e4812ab8SDmitry Osipenko submit->vfpriv = vfpriv;
408e4812ab8SDmitry Osipenko submit->vgdev = vgdev;
409e4812ab8SDmitry Osipenko submit->exbuf = exbuf;
410e4812ab8SDmitry Osipenko submit->file = file;
411e4812ab8SDmitry Osipenko
412e4812ab8SDmitry Osipenko err = virtio_gpu_init_submit_buflist(submit);
413e4812ab8SDmitry Osipenko if (err)
414e4812ab8SDmitry Osipenko return err;
415e4812ab8SDmitry Osipenko
416e4812ab8SDmitry Osipenko submit->buf = vmemdup_user(u64_to_user_ptr(exbuf->command), exbuf->size);
417e4812ab8SDmitry Osipenko if (IS_ERR(submit->buf))
418e4812ab8SDmitry Osipenko return PTR_ERR(submit->buf);
419e4812ab8SDmitry Osipenko
420e4812ab8SDmitry Osipenko if (exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_OUT) {
421e4812ab8SDmitry Osipenko err = get_unused_fd_flags(O_CLOEXEC);
422e4812ab8SDmitry Osipenko if (err < 0)
423e4812ab8SDmitry Osipenko return err;
424e4812ab8SDmitry Osipenko
425e4812ab8SDmitry Osipenko submit->out_fence_fd = err;
426e4812ab8SDmitry Osipenko
427e4812ab8SDmitry Osipenko submit->sync_file = sync_file_create(&out_fence->f);
428e4812ab8SDmitry Osipenko if (!submit->sync_file)
429e4812ab8SDmitry Osipenko return -ENOMEM;
430e4812ab8SDmitry Osipenko }
431e4812ab8SDmitry Osipenko
432e4812ab8SDmitry Osipenko return 0;
433e4812ab8SDmitry Osipenko }
434e4812ab8SDmitry Osipenko
virtio_gpu_wait_in_fence(struct virtio_gpu_submit * submit)435e4812ab8SDmitry Osipenko static int virtio_gpu_wait_in_fence(struct virtio_gpu_submit *submit)
436e4812ab8SDmitry Osipenko {
437e4812ab8SDmitry Osipenko int ret = 0;
438e4812ab8SDmitry Osipenko
439e4812ab8SDmitry Osipenko if (submit->exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_IN) {
440e4812ab8SDmitry Osipenko struct dma_fence *in_fence =
441e4812ab8SDmitry Osipenko sync_file_get_fence(submit->exbuf->fence_fd);
442e4812ab8SDmitry Osipenko if (!in_fence)
443e4812ab8SDmitry Osipenko return -EINVAL;
444e4812ab8SDmitry Osipenko
445e4812ab8SDmitry Osipenko /*
446e4812ab8SDmitry Osipenko * Wait if the fence is from a foreign context, or if the
447e4812ab8SDmitry Osipenko * fence array contains any fence from a foreign context.
448e4812ab8SDmitry Osipenko */
449e4812ab8SDmitry Osipenko ret = virtio_gpu_dma_fence_wait(submit, in_fence);
450e4812ab8SDmitry Osipenko
451e4812ab8SDmitry Osipenko dma_fence_put(in_fence);
452e4812ab8SDmitry Osipenko }
453e4812ab8SDmitry Osipenko
454e4812ab8SDmitry Osipenko return ret;
455e4812ab8SDmitry Osipenko }
456e4812ab8SDmitry Osipenko
virtio_gpu_install_out_fence_fd(struct virtio_gpu_submit * submit)457e4812ab8SDmitry Osipenko static void virtio_gpu_install_out_fence_fd(struct virtio_gpu_submit *submit)
458e4812ab8SDmitry Osipenko {
459e4812ab8SDmitry Osipenko if (submit->sync_file) {
460e4812ab8SDmitry Osipenko submit->exbuf->fence_fd = submit->out_fence_fd;
461e4812ab8SDmitry Osipenko fd_install(submit->out_fence_fd, submit->sync_file->file);
462e4812ab8SDmitry Osipenko }
463e4812ab8SDmitry Osipenko }
464e4812ab8SDmitry Osipenko
virtio_gpu_lock_buflist(struct virtio_gpu_submit * submit)465e4812ab8SDmitry Osipenko static int virtio_gpu_lock_buflist(struct virtio_gpu_submit *submit)
466e4812ab8SDmitry Osipenko {
467e4812ab8SDmitry Osipenko if (submit->buflist)
468e4812ab8SDmitry Osipenko return virtio_gpu_array_lock_resv(submit->buflist);
469e4812ab8SDmitry Osipenko
470e4812ab8SDmitry Osipenko return 0;
471e4812ab8SDmitry Osipenko }
472e4812ab8SDmitry Osipenko
virtio_gpu_execbuffer_ioctl(struct drm_device * dev,void * data,struct drm_file * file)473e4812ab8SDmitry Osipenko int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data,
474e4812ab8SDmitry Osipenko struct drm_file *file)
475e4812ab8SDmitry Osipenko {
476e4812ab8SDmitry Osipenko struct virtio_gpu_device *vgdev = dev->dev_private;
477e4812ab8SDmitry Osipenko struct virtio_gpu_fpriv *vfpriv = file->driver_priv;
478e4812ab8SDmitry Osipenko u64 fence_ctx = vgdev->fence_drv.context;
479e4812ab8SDmitry Osipenko struct drm_virtgpu_execbuffer *exbuf = data;
480e4812ab8SDmitry Osipenko struct virtio_gpu_submit submit;
481e4812ab8SDmitry Osipenko u32 ring_idx = 0;
482e4812ab8SDmitry Osipenko int ret = -EINVAL;
483e4812ab8SDmitry Osipenko
484e4812ab8SDmitry Osipenko if (!vgdev->has_virgl_3d)
485e4812ab8SDmitry Osipenko return -ENOSYS;
486e4812ab8SDmitry Osipenko
487e4812ab8SDmitry Osipenko if (exbuf->flags & ~VIRTGPU_EXECBUF_FLAGS)
488e4812ab8SDmitry Osipenko return ret;
489e4812ab8SDmitry Osipenko
490e4812ab8SDmitry Osipenko if (exbuf->flags & VIRTGPU_EXECBUF_RING_IDX) {
491e4812ab8SDmitry Osipenko if (exbuf->ring_idx >= vfpriv->num_rings)
492e4812ab8SDmitry Osipenko return ret;
493e4812ab8SDmitry Osipenko
494e4812ab8SDmitry Osipenko if (!vfpriv->base_fence_ctx)
495e4812ab8SDmitry Osipenko return ret;
496e4812ab8SDmitry Osipenko
497e4812ab8SDmitry Osipenko fence_ctx = vfpriv->base_fence_ctx;
498e4812ab8SDmitry Osipenko ring_idx = exbuf->ring_idx;
499e4812ab8SDmitry Osipenko }
500e4812ab8SDmitry Osipenko
501e4812ab8SDmitry Osipenko virtio_gpu_create_context(dev, file);
502e4812ab8SDmitry Osipenko
503e4812ab8SDmitry Osipenko ret = virtio_gpu_init_submit(&submit, exbuf, dev, file,
504e4812ab8SDmitry Osipenko fence_ctx, ring_idx);
505e4812ab8SDmitry Osipenko if (ret)
506e4812ab8SDmitry Osipenko goto cleanup;
507e4812ab8SDmitry Osipenko
5087cb8d1abSDmitry Osipenko ret = virtio_gpu_parse_post_deps(&submit);
5097cb8d1abSDmitry Osipenko if (ret)
5107cb8d1abSDmitry Osipenko goto cleanup;
5117cb8d1abSDmitry Osipenko
5127cb8d1abSDmitry Osipenko ret = virtio_gpu_parse_deps(&submit);
5137cb8d1abSDmitry Osipenko if (ret)
5147cb8d1abSDmitry Osipenko goto cleanup;
5157cb8d1abSDmitry Osipenko
516e4812ab8SDmitry Osipenko /*
517e4812ab8SDmitry Osipenko * Await in-fences in the end of the job submission path to
518e4812ab8SDmitry Osipenko * optimize the path by proceeding directly to the submission
519e4812ab8SDmitry Osipenko * to virtio after the waits.
520e4812ab8SDmitry Osipenko */
521e4812ab8SDmitry Osipenko ret = virtio_gpu_wait_in_fence(&submit);
522e4812ab8SDmitry Osipenko if (ret)
523e4812ab8SDmitry Osipenko goto cleanup;
524e4812ab8SDmitry Osipenko
525e4812ab8SDmitry Osipenko ret = virtio_gpu_lock_buflist(&submit);
526e4812ab8SDmitry Osipenko if (ret)
527e4812ab8SDmitry Osipenko goto cleanup;
528e4812ab8SDmitry Osipenko
529e4812ab8SDmitry Osipenko virtio_gpu_submit(&submit);
530e4812ab8SDmitry Osipenko
531e4812ab8SDmitry Osipenko /*
532e4812ab8SDmitry Osipenko * Set up usr-out data after submitting the job to optimize
533e4812ab8SDmitry Osipenko * the job submission path.
534e4812ab8SDmitry Osipenko */
535e4812ab8SDmitry Osipenko virtio_gpu_install_out_fence_fd(&submit);
5367cb8d1abSDmitry Osipenko virtio_gpu_process_post_deps(&submit);
537e4812ab8SDmitry Osipenko virtio_gpu_complete_submit(&submit);
538e4812ab8SDmitry Osipenko cleanup:
539e4812ab8SDmitry Osipenko virtio_gpu_cleanup_submit(&submit);
540e4812ab8SDmitry Osipenko
541e4812ab8SDmitry Osipenko return ret;
542e4812ab8SDmitry Osipenko }
543