Skip to content

Commit 3edd52b

Browse files
Thomas Hellströmlucasdemarchi
authored andcommitted
drm/xe: Move vma rebinding to the drm_exec locking loop
Rebinding might allocate page-table bos, causing evictions. To support blocking locking during these evictions, perform the rebinding in the drm_exec locking loop. Also Reserve fence slots where actually needed rather than trying to predict how many fence slots will be needed over a complete wound-wait transaction. v2: - Remove a leftover call to xe_vm_rebind() (Matt Brost) - Add a helper function xe_vm_validate_rebind() (Matt Brost) v3: - Add comments and squash with previous patch (Matt Brost) Fixes: 24f947d ("drm/xe: Use DRM GPUVM helpers for external- and evicted objects") Fixes: 29f424e ("drm/xe/exec: move fence reservation") Cc: Matthew Auld <[email protected]> Signed-off-by: Thomas Hellström <[email protected]> Reviewed-by: Matthew Brost <[email protected]> Link: https://patchwork.freedesktop.org/patch/msgid/[email protected] (cherry picked from commit 7ee7dd6) Signed-off-by: Lucas De Marchi <[email protected]>
1 parent fd1c808 commit 3edd52b

File tree

5 files changed

+83
-75
lines changed

5 files changed

+83
-75
lines changed

drivers/gpu/drm/xe/xe_exec.c

Lines changed: 6 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -94,48 +94,16 @@
9494
* Unlock all
9595
*/
9696

97+
/*
98+
* Add validation and rebinding to the drm_exec locking loop, since both can
99+
* trigger eviction which may require sleeping dma_resv locks.
100+
*/
97101
static int xe_exec_fn(struct drm_gpuvm_exec *vm_exec)
98102
{
99103
struct xe_vm *vm = container_of(vm_exec->vm, struct xe_vm, gpuvm);
100-
struct drm_gem_object *obj;
101-
unsigned long index;
102-
int num_fences;
103-
int ret;
104-
105-
ret = drm_gpuvm_validate(vm_exec->vm, &vm_exec->exec);
106-
if (ret)
107-
return ret;
108-
109-
/*
110-
* 1 fence slot for the final submit, and 1 more for every per-tile for
111-
* GPU bind and 1 extra for CPU bind. Note that there are potentially
112-
* many vma per object/dma-resv, however the fence slot will just be
113-
* re-used, since they are largely the same timeline and the seqno
114-
* should be in order. In the case of CPU bind there is dummy fence used
115-
* for all CPU binds, so no need to have a per-tile slot for that.
116-
*/
117-
num_fences = 1 + 1 + vm->xe->info.tile_count;
118104

119-
/*
120-
* We don't know upfront exactly how many fence slots we will need at
121-
* the start of the exec, since the TTM bo_validate above can consume
122-
* numerous fence slots. Also due to how the dma_resv_reserve_fences()
123-
* works it only ensures that at least that many fence slots are
124-
* available i.e if there are already 10 slots available and we reserve
125-
* two more, it can just noop without reserving anything. With this it
126-
* is quite possible that TTM steals some of the fence slots and then
127-
* when it comes time to do the vma binding and final exec stage we are
128-
* lacking enough fence slots, leading to some nasty BUG_ON() when
129-
* adding the fences. Hence just add our own fences here, after the
130-
* validate stage.
131-
*/
132-
drm_exec_for_each_locked_object(&vm_exec->exec, index, obj) {
133-
ret = dma_resv_reserve_fences(obj->resv, num_fences);
134-
if (ret)
135-
return ret;
136-
}
137-
138-
return 0;
105+
/* The fence slot added here is intended for the exec sched job. */
106+
return xe_vm_validate_rebind(vm, &vm_exec->exec, 1);
139107
}
140108

141109
int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
@@ -289,14 +257,6 @@ int xe_exec_ioctl(struct drm_device *dev, void *data, struct drm_file *file)
289257
goto err_exec;
290258
}
291259

292-
/*
293-
* Rebind any invalidated userptr or evicted BOs in the VM, non-compute
294-
* VM mode only.
295-
*/
296-
err = xe_vm_rebind(vm, false);
297-
if (err)
298-
goto err_put_job;
299-
300260
/* Wait behind rebinds */
301261
if (!xe_vm_in_lr_mode(vm)) {
302262
err = drm_sched_job_add_resv_dependencies(&job->drm,

drivers/gpu/drm/xe/xe_gt_pagefault.c

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,9 @@ static int xe_pf_begin(struct drm_exec *exec, struct xe_vma *vma,
100100
{
101101
struct xe_bo *bo = xe_vma_bo(vma);
102102
struct xe_vm *vm = xe_vma_vm(vma);
103-
unsigned int num_shared = 2; /* slots for bind + move */
104103
int err;
105104

106-
err = xe_vm_prepare_vma(exec, vma, num_shared);
105+
err = xe_vm_lock_vma(exec, vma);
107106
if (err)
108107
return err;
109108

drivers/gpu/drm/xe/xe_pt.c

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1235,6 +1235,13 @@ __xe_pt_bind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queue
12351235
err = xe_pt_prepare_bind(tile, vma, entries, &num_entries);
12361236
if (err)
12371237
goto err;
1238+
1239+
err = dma_resv_reserve_fences(xe_vm_resv(vm), 1);
1240+
if (!err && !xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm)
1241+
err = dma_resv_reserve_fences(xe_vma_bo(vma)->ttm.base.resv, 1);
1242+
if (err)
1243+
goto err;
1244+
12381245
xe_tile_assert(tile, num_entries <= ARRAY_SIZE(entries));
12391246

12401247
xe_vm_dbg_print_entries(tile_to_xe(tile), entries, num_entries);
@@ -1577,6 +1584,7 @@ __xe_pt_unbind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queu
15771584
struct dma_fence *fence = NULL;
15781585
struct invalidation_fence *ifence;
15791586
struct xe_range_fence *rfence;
1587+
int err;
15801588

15811589
LLIST_HEAD(deferred);
15821590

@@ -1594,6 +1602,12 @@ __xe_pt_unbind_vma(struct xe_tile *tile, struct xe_vma *vma, struct xe_exec_queu
15941602
xe_pt_calc_rfence_interval(vma, &unbind_pt_update, entries,
15951603
num_entries);
15961604

1605+
err = dma_resv_reserve_fences(xe_vm_resv(vm), 1);
1606+
if (!err && !xe_vma_has_no_bo(vma) && !xe_vma_bo(vma)->vm)
1607+
err = dma_resv_reserve_fences(xe_vma_bo(vma)->ttm.base.resv, 1);
1608+
if (err)
1609+
return ERR_PTR(err);
1610+
15971611
ifence = kzalloc(sizeof(*ifence), GFP_KERNEL);
15981612
if (!ifence)
15991613
return ERR_PTR(-ENOMEM);

drivers/gpu/drm/xe/xe_vm.c

Lines changed: 58 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -482,17 +482,53 @@ static int xe_gpuvm_validate(struct drm_gpuvm_bo *vm_bo, struct drm_exec *exec)
482482
return 0;
483483
}
484484

485+
/**
486+
* xe_vm_validate_rebind() - Validate buffer objects and rebind vmas
487+
* @vm: The vm for which we are rebinding.
488+
* @exec: The struct drm_exec with the locked GEM objects.
489+
* @num_fences: The number of fences to reserve for the operation, not
490+
* including rebinds and validations.
491+
*
492+
* Validates all evicted gem objects and rebinds their vmas. Note that
493+
* rebindings may cause evictions and hence the validation-rebind
494+
* sequence is rerun until there are no more objects to validate.
495+
*
496+
* Return: 0 on success, negative error code on error. In particular,
497+
* may return -EINTR or -ERESTARTSYS if interrupted, and -EDEADLK if
498+
* the drm_exec transaction needs to be restarted.
499+
*/
500+
int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec,
501+
unsigned int num_fences)
502+
{
503+
struct drm_gem_object *obj;
504+
unsigned long index;
505+
int ret;
506+
507+
do {
508+
ret = drm_gpuvm_validate(&vm->gpuvm, exec);
509+
if (ret)
510+
return ret;
511+
512+
ret = xe_vm_rebind(vm, false);
513+
if (ret)
514+
return ret;
515+
} while (!list_empty(&vm->gpuvm.evict.list));
516+
517+
drm_exec_for_each_locked_object(exec, index, obj) {
518+
ret = dma_resv_reserve_fences(obj->resv, num_fences);
519+
if (ret)
520+
return ret;
521+
}
522+
523+
return 0;
524+
}
525+
485526
static int xe_preempt_work_begin(struct drm_exec *exec, struct xe_vm *vm,
486527
bool *done)
487528
{
488529
int err;
489530

490-
/*
491-
* 1 fence for each preempt fence plus a fence for each tile from a
492-
* possible rebind
493-
*/
494-
err = drm_gpuvm_prepare_vm(&vm->gpuvm, exec, vm->preempt.num_exec_queues +
495-
vm->xe->info.tile_count);
531+
err = drm_gpuvm_prepare_vm(&vm->gpuvm, exec, 0);
496532
if (err)
497533
return err;
498534

@@ -507,15 +543,21 @@ static int xe_preempt_work_begin(struct drm_exec *exec, struct xe_vm *vm,
507543
return 0;
508544
}
509545

510-
err = drm_gpuvm_prepare_objects(&vm->gpuvm, exec, vm->preempt.num_exec_queues);
546+
err = drm_gpuvm_prepare_objects(&vm->gpuvm, exec, 0);
511547
if (err)
512548
return err;
513549

514550
err = wait_for_existing_preempt_fences(vm);
515551
if (err)
516552
return err;
517553

518-
return drm_gpuvm_validate(&vm->gpuvm, exec);
554+
/*
555+
* Add validation and rebinding to the locking loop since both can
556+
* cause evictions which may require blocing dma_resv locks.
557+
* The fence reservation here is intended for the new preempt fences
558+
* we attach at the end of the rebind work.
559+
*/
560+
return xe_vm_validate_rebind(vm, exec, vm->preempt.num_exec_queues);
519561
}
520562

521563
static void preempt_rebind_work_func(struct work_struct *w)
@@ -996,35 +1038,26 @@ static void xe_vma_destroy(struct xe_vma *vma, struct dma_fence *fence)
9961038
}
9971039

9981040
/**
999-
* xe_vm_prepare_vma() - drm_exec utility to lock a vma
1041+
* xe_vm_lock_vma() - drm_exec utility to lock a vma
10001042
* @exec: The drm_exec object we're currently locking for.
10011043
* @vma: The vma for witch we want to lock the vm resv and any attached
10021044
* object's resv.
1003-
* @num_shared: The number of dma-fence slots to pre-allocate in the
1004-
* objects' reservation objects.
10051045
*
10061046
* Return: 0 on success, negative error code on error. In particular
10071047
* may return -EDEADLK on WW transaction contention and -EINTR if
10081048
* an interruptible wait is terminated by a signal.
10091049
*/
1010-
int xe_vm_prepare_vma(struct drm_exec *exec, struct xe_vma *vma,
1011-
unsigned int num_shared)
1050+
int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma)
10121051
{
10131052
struct xe_vm *vm = xe_vma_vm(vma);
10141053
struct xe_bo *bo = xe_vma_bo(vma);
10151054
int err;
10161055

10171056
XE_WARN_ON(!vm);
1018-
if (num_shared)
1019-
err = drm_exec_prepare_obj(exec, xe_vm_obj(vm), num_shared);
1020-
else
1021-
err = drm_exec_lock_obj(exec, xe_vm_obj(vm));
1022-
if (!err && bo && !bo->vm) {
1023-
if (num_shared)
1024-
err = drm_exec_prepare_obj(exec, &bo->ttm.base, num_shared);
1025-
else
1026-
err = drm_exec_lock_obj(exec, &bo->ttm.base);
1027-
}
1057+
1058+
err = drm_exec_lock_obj(exec, xe_vm_obj(vm));
1059+
if (!err && bo && !bo->vm)
1060+
err = drm_exec_lock_obj(exec, &bo->ttm.base);
10281061

10291062
return err;
10301063
}
@@ -1036,7 +1069,7 @@ static void xe_vma_destroy_unlocked(struct xe_vma *vma)
10361069

10371070
drm_exec_init(&exec, 0, 0);
10381071
drm_exec_until_all_locked(&exec) {
1039-
err = xe_vm_prepare_vma(&exec, vma, 0);
1072+
err = xe_vm_lock_vma(&exec, vma);
10401073
drm_exec_retry_on_contention(&exec);
10411074
if (XE_WARN_ON(err))
10421075
break;
@@ -2503,7 +2536,7 @@ static int op_execute(struct drm_exec *exec, struct xe_vm *vm,
25032536

25042537
lockdep_assert_held_write(&vm->lock);
25052538

2506-
err = xe_vm_prepare_vma(exec, vma, 1);
2539+
err = xe_vm_lock_vma(exec, vma);
25072540
if (err)
25082541
return err;
25092542

drivers/gpu/drm/xe/xe_vm.h

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -242,8 +242,10 @@ bool xe_vm_validate_should_retry(struct drm_exec *exec, int err, ktime_t *end);
242242

243243
int xe_analyze_vm(struct drm_printer *p, struct xe_vm *vm, int gt_id);
244244

245-
int xe_vm_prepare_vma(struct drm_exec *exec, struct xe_vma *vma,
246-
unsigned int num_shared);
245+
int xe_vm_lock_vma(struct drm_exec *exec, struct xe_vma *vma);
246+
247+
int xe_vm_validate_rebind(struct xe_vm *vm, struct drm_exec *exec,
248+
unsigned int num_fences);
247249

248250
/**
249251
* xe_vm_resv() - Return's the vm's reservation object

0 commit comments

Comments
 (0)