History

drm/virtio: Support sync objects

Add sync object DRM UAPI support to VirtIO-GPU driver. Sync objects support is needed by native context VirtIO-GPU Mesa drivers, it also will be used by Venus and Virgl contexts. Reviewed-by; Emil Velikov <emil.velikov@collabora.com> Signed-off-by: Dmitry Osipenko <dmitry.osipenko@collabora.com> Tested-by: Pierre-Eric Pelloux-Prayer <pierre-eric.pelloux-prayer@amd.com> # amdgpu nctx Tested-by: Rob Clark <robdclark@gmail.com> # freedreno nctx Reviewed-by: Rob Clark <robdclark@gmail.com> Acked-by: Gurchetan Singh <gurchetansingh@chromium.org> Acked-by: Gerd Hoffmann <kraxel@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20230416115237.798604-4-dmitry.osipenko@collabora.com

Dmitry Osipenko committed 3 years ago

Commit 7cb8d1a1 parent 744d35d3 files · +241 −2Browse files

Unified · Split

3 files
  1. drivers/gpu/drm/virtio/virtgpu_drv.c +2 −1
  2. drivers/gpu/drm/virtio/virtgpu_submit.c +224 −0
  3. include/uapi/drm/virtgpu_drm.h +15 −1
drivers/gpu/drm/virtio/virtgpu_drv.c+2−1
@@ -176,7 +176,8 @@ static const struct drm_driver driver = { · 175 unmodified lines
176176 * If KMS is disabled DRIVER_MODESET and DRIVER_ATOMIC are masked
177177 * out via drm_device::driver_features:
178178 */
179− .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_RENDER | DRIVER_ATOMIC,
179+ .driver_features = DRIVER_MODESET | DRIVER_GEM | DRIVER_RENDER | DRIVER_ATOMIC |
180+ DRIVER_SYNCOBJ | DRIVER_SYNCOBJ_TIMELINE,
180181 .open = virtio_gpu_driver_open,
181182 .postclose = virtio_gpu_driver_postclose,
182183
drivers/gpu/drm/virtio/virtgpu_submit.c+224−0
@@ -14,11 +14,24 @@ · 13 unmodified lines
1414 #include <linux/uaccess.h>
1515
1616 #include <drm/drm_file.h>
17+#include <drm/drm_syncobj.h>
1718 #include <drm/virtgpu_drm.h>
1819
1920 #include "virtgpu_drv.h"
2021
22+struct virtio_gpu_submit_post_dep {
23+ struct drm_syncobj *syncobj;
24+ struct dma_fence_chain *chain;
25+ u64 point;
26+};
27+
2128 struct virtio_gpu_submit {
29+ struct virtio_gpu_submit_post_dep *post_deps;
30+ unsigned int num_out_syncobjs;
31+
32+ struct drm_syncobj **in_syncobjs;
33+ unsigned int num_in_syncobjs;
34+
2235 struct virtio_gpu_object_array *buflist;
2336 struct drm_virtgpu_execbuffer *exbuf;
2437 struct virtio_gpu_fence *out_fence;
@@ -59,6 +72,203 @@ static int virtio_gpu_dma_fence_wait(struct virtio_gpu_submit *submit, · 34 unmodified lines
5972 return 0;
6073 }
6174
75+static void virtio_gpu_free_syncobjs(struct drm_syncobj **syncobjs,
76+ u32 nr_syncobjs)
77+{
78+ u32 i = nr_syncobjs;
79+
80+ while (i--) {
81+ if (syncobjs[i])
82+ drm_syncobj_put(syncobjs[i]);
83+ }
84+
85+ kvfree(syncobjs);
86+}
87+
88+static int
89+virtio_gpu_parse_deps(struct virtio_gpu_submit *submit)
90+{
91+ struct drm_virtgpu_execbuffer *exbuf = submit->exbuf;
92+ struct drm_virtgpu_execbuffer_syncobj syncobj_desc;
93+ size_t syncobj_stride = exbuf->syncobj_stride;
94+ u32 num_in_syncobjs = exbuf->num_in_syncobjs;
95+ struct drm_syncobj **syncobjs;
96+ int ret = 0, i;
97+
98+ if (!num_in_syncobjs)
99+ return 0;
100+
101+ /*
102+ * kvalloc at first tries to allocate memory using kmalloc and
103+ * falls back to vmalloc only on failure. It also uses __GFP_NOWARN
104+ * internally for allocations larger than a page size, preventing
105+ * storm of KMSG warnings.
106+ */
107+ syncobjs = kvcalloc(num_in_syncobjs, sizeof(*syncobjs), GFP_KERNEL);
108+ if (!syncobjs)
109+ return -ENOMEM;
110+
111+ for (i = 0; i < num_in_syncobjs; i++) {
112+ u64 address = exbuf->in_syncobjs + i * syncobj_stride;
113+ struct dma_fence *fence;
114+
115+ memset(&syncobj_desc, 0, sizeof(syncobj_desc));
116+
117+ if (copy_from_user(&syncobj_desc,
118+ u64_to_user_ptr(address),
119+ min(syncobj_stride, sizeof(syncobj_desc)))) {
120+ ret = -EFAULT;
121+ break;
122+ }
123+
124+ if (syncobj_desc.flags & ~VIRTGPU_EXECBUF_SYNCOBJ_FLAGS) {
125+ ret = -EINVAL;
126+ break;
127+ }
128+
129+ ret = drm_syncobj_find_fence(submit->file, syncobj_desc.handle,
130+ syncobj_desc.point, 0, &fence);
131+ if (ret)
132+ break;
133+
134+ ret = virtio_gpu_dma_fence_wait(submit, fence);
135+
136+ dma_fence_put(fence);
137+ if (ret)
138+ break;
139+
140+ if (syncobj_desc.flags & VIRTGPU_EXECBUF_SYNCOBJ_RESET) {
141+ syncobjs[i] = drm_syncobj_find(submit->file,
142+ syncobj_desc.handle);
143+ if (!syncobjs[i]) {
144+ ret = -EINVAL;
145+ break;
146+ }
147+ }
148+ }
149+
150+ if (ret) {
151+ virtio_gpu_free_syncobjs(syncobjs, i);
152+ return ret;
153+ }
154+
155+ submit->num_in_syncobjs = num_in_syncobjs;
156+ submit->in_syncobjs = syncobjs;
157+
158+ return ret;
159+}
160+
161+static void virtio_gpu_reset_syncobjs(struct drm_syncobj **syncobjs,
162+ u32 nr_syncobjs)
163+{
164+ u32 i;
165+
166+ for (i = 0; i < nr_syncobjs; i++) {
167+ if (syncobjs[i])
168+ drm_syncobj_replace_fence(syncobjs[i], NULL);
169+ }
170+}
171+
172+static void
173+virtio_gpu_free_post_deps(struct virtio_gpu_submit_post_dep *post_deps,
174+ u32 nr_syncobjs)
175+{
176+ u32 i = nr_syncobjs;
177+
178+ while (i--) {
179+ kfree(post_deps[i].chain);
180+ drm_syncobj_put(post_deps[i].syncobj);
181+ }
182+
183+ kvfree(post_deps);
184+}
185+
186+static int virtio_gpu_parse_post_deps(struct virtio_gpu_submit *submit)
187+{
188+ struct drm_virtgpu_execbuffer *exbuf = submit->exbuf;
189+ struct drm_virtgpu_execbuffer_syncobj syncobj_desc;
190+ struct virtio_gpu_submit_post_dep *post_deps;
191+ u32 num_out_syncobjs = exbuf->num_out_syncobjs;
192+ size_t syncobj_stride = exbuf->syncobj_stride;
193+ int ret = 0, i;
194+
195+ if (!num_out_syncobjs)
196+ return 0;
197+
198+ post_deps = kvcalloc(num_out_syncobjs, sizeof(*post_deps), GFP_KERNEL);
199+ if (!post_deps)
200+ return -ENOMEM;
201+
202+ for (i = 0; i < num_out_syncobjs; i++) {
203+ u64 address = exbuf->out_syncobjs + i * syncobj_stride;
204+
205+ memset(&syncobj_desc, 0, sizeof(syncobj_desc));
206+
207+ if (copy_from_user(&syncobj_desc,
208+ u64_to_user_ptr(address),
209+ min(syncobj_stride, sizeof(syncobj_desc)))) {
210+ ret = -EFAULT;
211+ break;
212+ }
213+
214+ post_deps[i].point = syncobj_desc.point;
215+
216+ if (syncobj_desc.flags) {
217+ ret = -EINVAL;
218+ break;
219+ }
220+
221+ if (syncobj_desc.point) {
222+ post_deps[i].chain = dma_fence_chain_alloc();
223+ if (!post_deps[i].chain) {
224+ ret = -ENOMEM;
225+ break;
226+ }
227+ }
228+
229+ post_deps[i].syncobj = drm_syncobj_find(submit->file,
230+ syncobj_desc.handle);
231+ if (!post_deps[i].syncobj) {
232+ kfree(post_deps[i].chain);
233+ ret = -EINVAL;
234+ break;
235+ }
236+ }
237+
238+ if (ret) {
239+ virtio_gpu_free_post_deps(post_deps, i);
240+ return ret;
241+ }
242+
243+ submit->num_out_syncobjs = num_out_syncobjs;
244+ submit->post_deps = post_deps;
245+
246+ return 0;
247+}
248+
249+static void
250+virtio_gpu_process_post_deps(struct virtio_gpu_submit *submit)
251+{
252+ struct virtio_gpu_submit_post_dep *post_deps = submit->post_deps;
253+
254+ if (post_deps) {
255+ struct dma_fence *fence = &submit->out_fence->f;
256+ u32 i;
257+
258+ for (i = 0; i < submit->num_out_syncobjs; i++) {
259+ if (post_deps[i].chain) {
260+ drm_syncobj_add_point(post_deps[i].syncobj,
261+ post_deps[i].chain,
262+ fence, post_deps[i].point);
263+ post_deps[i].chain = NULL;
264+ } else {
265+ drm_syncobj_replace_fence(post_deps[i].syncobj,
266+ fence);
267+ }
268+ }
269+ }
270+}
271+
62272 static int virtio_gpu_fence_event_create(struct drm_device *dev,
63273 struct drm_file *file,
64274 struct virtio_gpu_fence *fence,
@@ -118,6 +328,10 @@ static int virtio_gpu_init_submit_buflist(struct virtio_gpu_submit *submit) · 53 unmodified lines
118328
119329 static void virtio_gpu_cleanup_submit(struct virtio_gpu_submit *submit)
120330 {
331+ virtio_gpu_reset_syncobjs(submit->in_syncobjs, submit->num_in_syncobjs);
332+ virtio_gpu_free_syncobjs(submit->in_syncobjs, submit->num_in_syncobjs);
333+ virtio_gpu_free_post_deps(submit->post_deps, submit->num_out_syncobjs);
334+
121335 if (!IS_ERR(submit->buf))
122336 kvfree(submit->buf);
123337
@@ -172,6 +386,7 @@ static int virtio_gpu_init_submit(struct virtio_gpu_submit *submit, · 48 unmodified lines
172386 drm_fence_event = false;
173387
174388 if ((exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_OUT) ||
389+ exbuf->num_out_syncobjs ||
175390 exbuf->num_bo_handles ||
176391 drm_fence_event)
177392 out_fence = virtio_gpu_fence_alloc(vgdev, fence_ctx, ring_idx);
@@ -291,6 +506,14 @@ int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, · 113 unmodified lines
291506 if (ret)
292507 goto cleanup;
293508
509+ ret = virtio_gpu_parse_post_deps(&submit);
510+ if (ret)
511+ goto cleanup;
512+
513+ ret = virtio_gpu_parse_deps(&submit);
514+ if (ret)
515+ goto cleanup;
516+
294517 /*
295518 * Await in-fences in the end of the job submission path to
296519 * optimize the path by proceeding directly to the submission
@@ -311,6 +534,7 @@ int virtio_gpu_execbuffer_ioctl(struct drm_device *dev, void *data, · 14 unmodified lines
311534 * the job submission path.
312535 */
313536 virtio_gpu_install_out_fence_fd(&submit);
537+ virtio_gpu_process_post_deps(&submit);
314538 virtio_gpu_complete_submit(&submit);
315539 cleanup:
316540 virtio_gpu_cleanup_submit(&submit);
include/uapi/drm/virtgpu_drm.h+15−1
@@ -64,6 +64,16 @@ struct drm_virtgpu_map { · 63 unmodified lines
6464 __u32 pad;
6565 };
6666
67+#define VIRTGPU_EXECBUF_SYNCOBJ_RESET 0x01
68+#define VIRTGPU_EXECBUF_SYNCOBJ_FLAGS ( \
69+ VIRTGPU_EXECBUF_SYNCOBJ_RESET | \
70+ 0)
71+struct drm_virtgpu_execbuffer_syncobj {
72+ __u32 handle;
73+ __u32 flags;
74+ __u64 point;
75+};
76+
6777 /* fence_fd is modified on success if VIRTGPU_EXECBUF_FENCE_FD_OUT flag is set. */
6878 struct drm_virtgpu_execbuffer {
6979 __u32 flags;
@@ -73,7 +83,11 @@ struct drm_virtgpu_execbuffer { · 3 unmodified lines
7383 __u32 num_bo_handles;
7484 __s32 fence_fd; /* in/out fence fd (see VIRTGPU_EXECBUF_FENCE_FD_IN/OUT) */
7585 __u32 ring_idx; /* command ring index (see VIRTGPU_EXECBUF_RING_IDX) */
76− __u32 pad;
86+ __u32 syncobj_stride; /* size of @drm_virtgpu_execbuffer_syncobj */
87+ __u32 num_in_syncobjs;
88+ __u32 num_out_syncobjs;
89+ __u64 in_syncobjs;
90+ __u64 out_syncobjs;
7791 };
7892
7993 #define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */