Skip to content

Commit 92395af

Browse files
robclarkRob Clark
authored andcommitted
drm/msm: Add VM_BIND submitqueue
This submitqueue type isn't tied to a hw ringbuffer, but instead executes on the CPU for performing async VM_BIND ops. Signed-off-by: Rob Clark <robdclark@chromium.org> Signed-off-by: Rob Clark <robin.clark@oss.qualcomm.com> Tested-by: Antonino Maniscalco <antomani103@gmail.com> Reviewed-by: Antonino Maniscalco <antomani103@gmail.com> Patchwork: https://patchwork.freedesktop.org/patch/661517/
1 parent cefb919 commit 92395af

6 files changed

Lines changed: 201 additions & 24 deletions

File tree

drivers/gpu/drm/msm/msm_gem.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,13 @@ struct msm_gem_vm {
5353
/** @base: Inherit from drm_gpuvm. */
5454
struct drm_gpuvm base;
5555

56+
/**
57+
* @sched: Scheduler used for asynchronous VM_BIND request.
58+
*
59+
* Unused for kernel managed VMs (where all operations are synchronous).
60+
*/
61+
struct drm_gpu_scheduler sched;
62+
5663
/**
5764
* @mm: Memory management for kernel managed VA allocations
5865
*
@@ -71,6 +78,9 @@ struct msm_gem_vm {
7178
*/
7279
struct pid *pid;
7380

81+
/** @last_fence: Fence for last pending work scheduled on the VM */
82+
struct dma_fence *last_fence;
83+
7484
/** @faults: the number of GPU hangs associated with this address space */
7585
int faults;
7686

@@ -100,6 +110,8 @@ struct drm_gpuvm *
100110
msm_gem_vm_create(struct drm_device *drm, struct msm_mmu *mmu, const char *name,
101111
u64 va_start, u64 va_size, bool managed);
102112

113+
void msm_gem_vm_close(struct drm_gpuvm *gpuvm);
114+
103115
struct msm_fence_context;
104116

105117
#define MSM_VMA_DUMP (DRM_GPUVA_USERBITS << 0)

drivers/gpu/drm/msm/msm_gem_submit.c

Lines changed: 56 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
* Author: Rob Clark <robdclark@gmail.com>
55
*/
66

7+
#include <linux/dma-fence-unwrap.h>
78
#include <linux/file.h>
89
#include <linux/sync_file.h>
910
#include <linux/uaccess.h>
@@ -259,29 +260,47 @@ static int submit_lookup_cmds(struct msm_gem_submit *submit,
259260
static int submit_lock_objects(struct msm_gem_submit *submit)
260261
{
261262
unsigned flags = DRM_EXEC_INTERRUPTIBLE_WAIT;
263+
struct drm_exec *exec = &submit->exec;
262264
int ret;
263265

266+
if (msm_context_is_vmbind(submit->queue->ctx)) {
267+
flags |= DRM_EXEC_IGNORE_DUPLICATES;
268+
269+
drm_exec_init(&submit->exec, flags, submit->nr_bos);
270+
271+
drm_exec_until_all_locked (&submit->exec) {
272+
ret = drm_gpuvm_prepare_vm(submit->vm, exec, 1);
273+
drm_exec_retry_on_contention(exec);
274+
if (ret)
275+
return ret;
276+
277+
ret = drm_gpuvm_prepare_objects(submit->vm, exec, 1);
278+
drm_exec_retry_on_contention(exec);
279+
if (ret)
280+
return ret;
281+
}
282+
283+
return 0;
284+
}
285+
264286
drm_exec_init(&submit->exec, flags, submit->nr_bos);
265287

266288
drm_exec_until_all_locked (&submit->exec) {
267289
ret = drm_exec_lock_obj(&submit->exec,
268290
drm_gpuvm_resv_obj(submit->vm));
269291
drm_exec_retry_on_contention(&submit->exec);
270292
if (ret)
271-
goto error;
293+
return ret;
272294
for (unsigned i = 0; i < submit->nr_bos; i++) {
273295
struct drm_gem_object *obj = submit->bos[i].obj;
274296
ret = drm_exec_prepare_obj(&submit->exec, obj, 1);
275297
drm_exec_retry_on_contention(&submit->exec);
276298
if (ret)
277-
goto error;
299+
return ret;
278300
}
279301
}
280302

281303
return 0;
282-
283-
error:
284-
return ret;
285304
}
286305

287306
static int submit_fence_sync(struct msm_gem_submit *submit)
@@ -367,9 +386,18 @@ static void submit_unpin_objects(struct msm_gem_submit *submit)
367386

368387
static void submit_attach_object_fences(struct msm_gem_submit *submit)
369388
{
370-
int i;
389+
struct msm_gem_vm *vm = to_msm_vm(submit->vm);
390+
struct dma_fence *last_fence;
391+
392+
if (msm_context_is_vmbind(submit->queue->ctx)) {
393+
drm_gpuvm_resv_add_fence(submit->vm, &submit->exec,
394+
submit->user_fence,
395+
DMA_RESV_USAGE_BOOKKEEP,
396+
DMA_RESV_USAGE_BOOKKEEP);
397+
return;
398+
}
371399

372-
for (i = 0; i < submit->nr_bos; i++) {
400+
for (unsigned i = 0; i < submit->nr_bos; i++) {
373401
struct drm_gem_object *obj = submit->bos[i].obj;
374402

375403
if (submit->bos[i].flags & MSM_SUBMIT_BO_WRITE)
@@ -379,6 +407,10 @@ static void submit_attach_object_fences(struct msm_gem_submit *submit)
379407
dma_resv_add_fence(obj->resv, submit->user_fence,
380408
DMA_RESV_USAGE_READ);
381409
}
410+
411+
last_fence = vm->last_fence;
412+
vm->last_fence = dma_fence_unwrap_merge(submit->user_fence, last_fence);
413+
dma_fence_put(last_fence);
382414
}
383415

384416
static int submit_bo(struct msm_gem_submit *submit, uint32_t idx,
@@ -537,6 +569,11 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
537569
if (!queue)
538570
return -ENOENT;
539571

572+
if (queue->flags & MSM_SUBMITQUEUE_VM_BIND) {
573+
ret = UERR(EINVAL, dev, "Invalid queue type");
574+
goto out_post_unlock;
575+
}
576+
540577
ring = gpu->rb[queue->ring_nr];
541578

542579
if (args->flags & MSM_SUBMIT_FENCE_FD_OUT) {
@@ -727,6 +764,18 @@ int msm_ioctl_gem_submit(struct drm_device *dev, void *data,
727764

728765
submit_attach_object_fences(submit);
729766

767+
if (msm_context_is_vmbind(ctx)) {
768+
/*
769+
* If we are not using VM_BIND, submit_pin_vmas() will validate
770+
* just the BOs attached to the submit. In that case we don't
771+
* need to validate the _entire_ vm, because userspace tracked
772+
* what BOs are associated with the submit.
773+
*/
774+
ret = drm_gpuvm_validate(submit->vm, &submit->exec);
775+
if (ret)
776+
goto out;
777+
}
778+
730779
/* The scheduler owns a ref now: */
731780
msm_gem_submit_get(submit);
732781

drivers/gpu/drm/msm/msm_gem_vma.c

Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ msm_gem_vm_free(struct drm_gpuvm *gpuvm)
1616
drm_mm_takedown(&vm->mm);
1717
if (vm->mmu)
1818
vm->mmu->funcs->destroy(vm->mmu);
19+
dma_fence_put(vm->last_fence);
1920
put_pid(vm->pid);
2021
kfree(vm);
2122
}
@@ -154,6 +155,9 @@ static const struct drm_gpuvm_ops msm_gpuvm_ops = {
154155
.vm_free = msm_gem_vm_free,
155156
};
156157

158+
static const struct drm_sched_backend_ops msm_vm_bind_ops = {
159+
};
160+
157161
/**
158162
* msm_gem_vm_create() - Create and initialize a &msm_gem_vm
159163
* @drm: the drm device
@@ -195,6 +199,21 @@ msm_gem_vm_create(struct drm_device *drm, struct msm_mmu *mmu, const char *name,
195199
goto err_free_vm;
196200
}
197201

202+
if (!managed) {
203+
struct drm_sched_init_args args = {
204+
.ops = &msm_vm_bind_ops,
205+
.num_rqs = 1,
206+
.credit_limit = 1,
207+
.timeout = MAX_SCHEDULE_TIMEOUT,
208+
.name = "msm-vm-bind",
209+
.dev = drm->dev,
210+
};
211+
212+
ret = drm_sched_init(&vm->sched, &args);
213+
if (ret)
214+
goto err_free_dummy;
215+
}
216+
198217
drm_gpuvm_init(&vm->base, name, flags, drm, dummy_gem,
199218
va_start, va_size, 0, 0, &msm_gpuvm_ops);
200219
drm_gem_object_put(dummy_gem);
@@ -206,8 +225,60 @@ msm_gem_vm_create(struct drm_device *drm, struct msm_mmu *mmu, const char *name,
206225

207226
return &vm->base;
208227

228+
err_free_dummy:
229+
drm_gem_object_put(dummy_gem);
230+
209231
err_free_vm:
210232
kfree(vm);
211233
return ERR_PTR(ret);
212234

213235
}
236+
237+
/**
238+
* msm_gem_vm_close() - Close a VM
239+
* @gpuvm: The VM to close
240+
*
241+
* Called when the drm device file is closed, to tear down VM related resources
242+
* (which will drop refcounts to GEM objects that were still mapped into the
243+
* VM at the time).
244+
*/
245+
void
246+
msm_gem_vm_close(struct drm_gpuvm *gpuvm)
247+
{
248+
struct msm_gem_vm *vm = to_msm_vm(gpuvm);
249+
struct drm_gpuva *vma, *tmp;
250+
251+
/*
252+
* For kernel managed VMs, the VMAs are torn down when the handle is
253+
* closed, so nothing more to do.
254+
*/
255+
if (vm->managed)
256+
return;
257+
258+
if (vm->last_fence)
259+
dma_fence_wait(vm->last_fence, false);
260+
261+
/* Kill the scheduler now, so we aren't racing with it for cleanup: */
262+
drm_sched_stop(&vm->sched, NULL);
263+
drm_sched_fini(&vm->sched);
264+
265+
/* Tear down any remaining mappings: */
266+
dma_resv_lock(drm_gpuvm_resv(gpuvm), NULL);
267+
drm_gpuvm_for_each_va_safe (vma, tmp, gpuvm) {
268+
struct drm_gem_object *obj = vma->gem.obj;
269+
270+
if (obj && obj->resv != drm_gpuvm_resv(gpuvm)) {
271+
drm_gem_object_get(obj);
272+
msm_gem_lock(obj);
273+
}
274+
275+
msm_gem_vma_unmap(vma);
276+
msm_gem_vma_close(vma);
277+
278+
if (obj && obj->resv != drm_gpuvm_resv(gpuvm)) {
279+
msm_gem_unlock(obj);
280+
drm_gem_object_put(obj);
281+
}
282+
}
283+
dma_resv_unlock(drm_gpuvm_resv(gpuvm));
284+
}

drivers/gpu/drm/msm/msm_gpu.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -564,6 +564,9 @@ struct msm_gpu_submitqueue {
564564
struct mutex lock;
565565
struct kref ref;
566566
struct drm_sched_entity *entity;
567+
568+
/** @_vm_bind_entity: used for @entity pointer for VM_BIND queues */
569+
struct drm_sched_entity _vm_bind_entity[0];
567570
};
568571

569572
struct msm_gpu_state_bo {

drivers/gpu/drm/msm/msm_submitqueue.c

Lines changed: 51 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,9 @@ void msm_submitqueue_destroy(struct kref *kref)
7272

7373
idr_destroy(&queue->fence_idr);
7474

75+
if (queue->entity == &queue->_vm_bind_entity[0])
76+
drm_sched_entity_destroy(queue->entity);
77+
7578
msm_context_put(queue->ctx);
7679

7780
kfree(queue);
@@ -102,7 +105,7 @@ struct msm_gpu_submitqueue *msm_submitqueue_get(struct msm_context *ctx,
102105

103106
void msm_submitqueue_close(struct msm_context *ctx)
104107
{
105-
struct msm_gpu_submitqueue *entry, *tmp;
108+
struct msm_gpu_submitqueue *queue, *tmp;
106109

107110
if (!ctx)
108111
return;
@@ -111,10 +114,17 @@ void msm_submitqueue_close(struct msm_context *ctx)
111114
* No lock needed in close and there won't
112115
* be any more user ioctls coming our way
113116
*/
114-
list_for_each_entry_safe(entry, tmp, &ctx->submitqueues, node) {
115-
list_del(&entry->node);
116-
msm_submitqueue_put(entry);
117+
list_for_each_entry_safe(queue, tmp, &ctx->submitqueues, node) {
118+
if (queue->entity == &queue->_vm_bind_entity[0])
119+
drm_sched_entity_flush(queue->entity, MAX_WAIT_SCHED_ENTITY_Q_EMPTY);
120+
list_del(&queue->node);
121+
msm_submitqueue_put(queue);
117122
}
123+
124+
if (!ctx->vm)
125+
return;
126+
127+
msm_gem_vm_close(ctx->vm);
118128
}
119129

120130
static struct drm_sched_entity *
@@ -160,8 +170,6 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
160170
struct msm_drm_private *priv = drm->dev_private;
161171
struct msm_gpu_submitqueue *queue;
162172
enum drm_sched_priority sched_prio;
163-
extern int enable_preemption;
164-
bool preemption_supported;
165173
unsigned ring_nr;
166174
int ret;
167175

@@ -171,26 +179,53 @@ int msm_submitqueue_create(struct drm_device *drm, struct msm_context *ctx,
171179
if (!priv->gpu)
172180
return -ENODEV;
173181

174-
preemption_supported = priv->gpu->nr_rings == 1 && enable_preemption != 0;
182+
if (flags & MSM_SUBMITQUEUE_VM_BIND) {
183+
unsigned sz;
175184

176-
if (flags & MSM_SUBMITQUEUE_ALLOW_PREEMPT && preemption_supported)
177-
return -EINVAL;
185+
/* Not allowed for kernel managed VMs (ie. kernel allocs VA) */
186+
if (!msm_context_is_vmbind(ctx))
187+
return -EINVAL;
178188

179-
ret = msm_gpu_convert_priority(priv->gpu, prio, &ring_nr, &sched_prio);
180-
if (ret)
181-
return ret;
189+
if (prio)
190+
return -EINVAL;
191+
192+
sz = struct_size(queue, _vm_bind_entity, 1);
193+
queue = kzalloc(sz, GFP_KERNEL);
194+
} else {
195+
extern int enable_preemption;
196+
bool preemption_supported =
197+
priv->gpu->nr_rings == 1 && enable_preemption != 0;
198+
199+
if (flags & MSM_SUBMITQUEUE_ALLOW_PREEMPT && preemption_supported)
200+
return -EINVAL;
182201

183-
queue = kzalloc(sizeof(*queue), GFP_KERNEL);
202+
ret = msm_gpu_convert_priority(priv->gpu, prio, &ring_nr, &sched_prio);
203+
if (ret)
204+
return ret;
205+
206+
queue = kzalloc(sizeof(*queue), GFP_KERNEL);
207+
}
184208

185209
if (!queue)
186210
return -ENOMEM;
187211

188212
kref_init(&queue->ref);
189213
queue->flags = flags;
190-
queue->ring_nr = ring_nr;
191214

192-
queue->entity = get_sched_entity(ctx, priv->gpu->rb[ring_nr],
193-
ring_nr, sched_prio);
215+
if (flags & MSM_SUBMITQUEUE_VM_BIND) {
216+
struct drm_gpu_scheduler *sched = &to_msm_vm(msm_context_vm(drm, ctx))->sched;
217+
218+
queue->entity = &queue->_vm_bind_entity[0];
219+
220+
drm_sched_entity_init(queue->entity, DRM_SCHED_PRIORITY_KERNEL,
221+
&sched, 1, NULL);
222+
} else {
223+
queue->ring_nr = ring_nr;
224+
225+
queue->entity = get_sched_entity(ctx, priv->gpu->rb[ring_nr],
226+
ring_nr, sched_prio);
227+
}
228+
194229
if (IS_ERR(queue->entity)) {
195230
ret = PTR_ERR(queue->entity);
196231
kfree(queue);

0 commit comments

Comments
 (0)