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
176 * If KMS is disabled DRIVER_MODESET and DRIVER_ATOMIC are masked176 * If KMS is disabled DRIVER_MODESET and DRIVER_ATOMIC are masked
177 * out via drm_device::driver_features:177 * out via drm_device::driver_features:
178 */178 */
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,
180 .open = virtio_gpu_driver_open,181 .open = virtio_gpu_driver_open,
181 .postclose = virtio_gpu_driver_postclose,182 .postclose = virtio_gpu_driver_postclose,
182 183
drivers/gpu/drm/virtio/virtgpu_submit.c+224−0
@@ -14,11 +14,24 @@ · 13 unmodified lines
14#include <linux/uaccess.h>14#include <linux/uaccess.h>
15 15
16#include <drm/drm_file.h>16#include <drm/drm_file.h>
17#include <drm/drm_syncobj.h>
17#include <drm/virtgpu_drm.h>18#include <drm/virtgpu_drm.h>
18 19
19#include "virtgpu_drv.h"20#include "virtgpu_drv.h"
20 21
22struct virtio_gpu_submit_post_dep {
23 struct drm_syncobj *syncobj;
24 struct dma_fence_chain *chain;
25 u64 point;
26};
27
21struct virtio_gpu_submit {28struct 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
22 struct virtio_gpu_object_array *buflist;35 struct virtio_gpu_object_array *buflist;
23 struct drm_virtgpu_execbuffer *exbuf;36 struct drm_virtgpu_execbuffer *exbuf;
24 struct virtio_gpu_fence *out_fence;37 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
59 return 0;72 return 0;
60}73}
61 74
75static 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
88static int
89virtio_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
161static 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
172static void
173virtio_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
186static 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
249static void
250virtio_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
62static int virtio_gpu_fence_event_create(struct drm_device *dev,272static int virtio_gpu_fence_event_create(struct drm_device *dev,
63 struct drm_file *file,273 struct drm_file *file,
64 struct virtio_gpu_fence *fence,274 struct virtio_gpu_fence *fence,
@@ -118,6 +328,10 @@ static int virtio_gpu_init_submit_buflist(struct virtio_gpu_submit *submit) · 53 unmodified lines
118 328
119static void virtio_gpu_cleanup_submit(struct virtio_gpu_submit *submit)329static void virtio_gpu_cleanup_submit(struct virtio_gpu_submit *submit)
120{330{
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
121 if (!IS_ERR(submit->buf))335 if (!IS_ERR(submit->buf))
122 kvfree(submit->buf);336 kvfree(submit->buf);
123 337
@@ -172,6 +386,7 @@ static int virtio_gpu_init_submit(struct virtio_gpu_submit *submit, · 48 unmodified lines
172 drm_fence_event = false;386 drm_fence_event = false;
173 387
174 if ((exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_OUT) ||388 if ((exbuf->flags & VIRTGPU_EXECBUF_FENCE_FD_OUT) ||
389 exbuf->num_out_syncobjs ||
175 exbuf->num_bo_handles ||390 exbuf->num_bo_handles ||
176 drm_fence_event)391 drm_fence_event)
177 out_fence = virtio_gpu_fence_alloc(vgdev, fence_ctx, ring_idx);392 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
291 if (ret)506 if (ret)
292 goto cleanup;507 goto cleanup;
293 508
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
294 /*517 /*
295 * Await in-fences in the end of the job submission path to518 * Await in-fences in the end of the job submission path to
296 * optimize the path by proceeding directly to the submission519 * 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
311 * the job submission path.534 * the job submission path.
312 */535 */
313 virtio_gpu_install_out_fence_fd(&submit);536 virtio_gpu_install_out_fence_fd(&submit);
537 virtio_gpu_process_post_deps(&submit);
314 virtio_gpu_complete_submit(&submit);538 virtio_gpu_complete_submit(&submit);
315cleanup:539cleanup:
316 virtio_gpu_cleanup_submit(&submit);540 virtio_gpu_cleanup_submit(&submit);
include/uapi/drm/virtgpu_drm.h+15−1
@@ -64,6 +64,16 @@ struct drm_virtgpu_map { · 63 unmodified lines
64 __u32 pad;64 __u32 pad;
65};65};
66 66
67#define VIRTGPU_EXECBUF_SYNCOBJ_RESET 0x01
68#define VIRTGPU_EXECBUF_SYNCOBJ_FLAGS ( \
69 VIRTGPU_EXECBUF_SYNCOBJ_RESET | \
70 0)
71struct drm_virtgpu_execbuffer_syncobj {
72 __u32 handle;
73 __u32 flags;
74 __u64 point;
75};
76
67/* fence_fd is modified on success if VIRTGPU_EXECBUF_FENCE_FD_OUT flag is set. */77/* fence_fd is modified on success if VIRTGPU_EXECBUF_FENCE_FD_OUT flag is set. */
68struct drm_virtgpu_execbuffer {78struct drm_virtgpu_execbuffer {
69 __u32 flags;79 __u32 flags;
@@ -73,7 +83,11 @@ struct drm_virtgpu_execbuffer { · 3 unmodified lines
73 __u32 num_bo_handles;83 __u32 num_bo_handles;
74 __s32 fence_fd; /* in/out fence fd (see VIRTGPU_EXECBUF_FENCE_FD_IN/OUT) */84 __s32 fence_fd; /* in/out fence fd (see VIRTGPU_EXECBUF_FENCE_FD_IN/OUT) */
75 __u32 ring_idx; /* command ring index (see VIRTGPU_EXECBUF_RING_IDX) */85 __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;
77};91};
78 92
79#define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */93#define VIRTGPU_PARAM_3D_FEATURES 1 /* do we have 3D features in the hw */