Skip to content

Commit

Permalink
drm/i915: Remove the vm open count
Browse files Browse the repository at this point in the history
vms are not getting properly closed. Rather than fixing that,
Remove the vm open count and instead rely on the vm refcount.

The vm open count existed solely to break the strong references the
vmas had on the vms. Now instead make those references weak and
ensure vmas are destroyed when the vm is destroyed.

Unfortunately if the vm destructor and the object destructor both
wants to destroy a vma, that may lead to a race in that the vm
destructor just unbinds the vma and leaves the actual vma destruction
to the object destructor. However in order for the object destructor
to ensure the vma is unbound it needs to grab the vm mutex. In order
to keep the vm mutex alive until the object destructor is done with
it, somewhat hackishly grab a vm_resv refcount that is released late
in the vma destruction process, when the vm mutex is no longer needed.

v2: Address review-comments from Niranjana
- Clarify that the struct i915_address_space::skip_pte_rewrite is a hack
  and should ideally be replaced in an upcoming patch.
- Remove an unneeded continue in clear_vm_list and update comment.

v3:
- Documentation update
- Commit message formatting

Co-developed-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Signed-off-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Signed-off-by: Thomas Hellström <thomas.hellstrom@linux.intel.com>
Reviewed-by: Niranjana Vishwanathapura <niranjana.vishwanathapura@intel.com>
Reviewed-by: Matthew Auld <matthew.auld@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220304082641.308069-2-thomas.hellstrom@linux.intel.com
  • Loading branch information
Thomas Hellström committed Mar 7, 2022
1 parent d028a76 commit e1a7ab4
Show file tree
Hide file tree
Showing 15 changed files with 192 additions and 166 deletions.
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/display/intel_dpt.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,5 +300,5 @@ void intel_dpt_destroy(struct i915_address_space *vm)
{
struct i915_dpt *dpt = i915_vm_to_dpt(vm);

i915_vm_close(&dpt->vm);
i915_vm_put(&dpt->vm);
}
29 changes: 6 additions & 23 deletions drivers/gpu/drm/i915/gem/i915_gem_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -1466,8 +1466,6 @@ static void set_closed_name(struct i915_gem_context *ctx)

static void context_close(struct i915_gem_context *ctx)
{
struct i915_address_space *vm;

/* Flush any concurrent set_engines() */
mutex_lock(&ctx->engines_mutex);
unpin_engines(__context_engines_static(ctx));
Expand All @@ -1479,26 +1477,15 @@ static void context_close(struct i915_gem_context *ctx)

set_closed_name(ctx);

vm = ctx->vm;
if (vm) {
/* i915_vm_close drops the final reference, which is a bit too
* early and could result in surprises with concurrent
* operations racing with thist ctx close. Keep a full reference
* until the end.
*/
i915_vm_get(vm);
i915_vm_close(vm);
}

ctx->file_priv = ERR_PTR(-EBADF);

/*
* The LUT uses the VMA as a backpointer to unref the object,
* so we need to clear the LUT before we close all the VMA (inside
* the ppgtt).
*/
lut_close(ctx);

ctx->file_priv = ERR_PTR(-EBADF);

spin_lock(&ctx->i915->gem.contexts.lock);
list_del(&ctx->link);
spin_unlock(&ctx->i915->gem.contexts.lock);
Expand Down Expand Up @@ -1597,12 +1584,8 @@ i915_gem_create_context(struct drm_i915_private *i915,
}
vm = &ppgtt->vm;
}
if (vm) {
ctx->vm = i915_vm_open(vm);

/* i915_vm_open() takes a reference */
i915_vm_put(vm);
}
if (vm)
ctx->vm = vm;

mutex_init(&ctx->engines_mutex);
if (pc->num_user_engines >= 0) {
Expand Down Expand Up @@ -1652,7 +1635,7 @@ i915_gem_create_context(struct drm_i915_private *i915,
free_engines(e);
err_vm:
if (ctx->vm)
i915_vm_close(ctx->vm);
i915_vm_put(ctx->vm);
err_ctx:
kfree(ctx);
return ERR_PTR(err);
Expand Down Expand Up @@ -1836,7 +1819,7 @@ static int get_ppgtt(struct drm_i915_file_private *file_priv,
if (err)
return err;

i915_vm_open(vm);
i915_vm_get(vm);

GEM_BUG_ON(id == 0); /* reserved for invalid/unassigned ppgtt */
args->value = id;
Expand Down
6 changes: 6 additions & 0 deletions drivers/gpu/drm/i915/gem/i915_gem_execbuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -2691,6 +2691,11 @@ eb_select_engine(struct i915_execbuffer *eb)
if (err)
goto err;

if (!i915_vm_tryget(ce->vm)) {
err = -ENOENT;
goto err;
}

eb->context = ce;
eb->gt = ce->engine->gt;

Expand All @@ -2714,6 +2719,7 @@ eb_put_engine(struct i915_execbuffer *eb)
{
struct intel_context *child;

i915_vm_put(eb->context->vm);
intel_gt_pm_put(eb->gt);
for_each_child(eb->context, child)
intel_context_put(child);
Expand Down
5 changes: 2 additions & 3 deletions drivers/gpu/drm/i915/gem/selftests/mock_context.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,7 @@ mock_context(struct drm_i915_private *i915,
if (!ppgtt)
goto err_free;

ctx->vm = i915_vm_open(&ppgtt->vm);
i915_vm_put(&ppgtt->vm);
ctx->vm = &ppgtt->vm;
}

mutex_init(&ctx->engines_mutex);
Expand All @@ -59,7 +58,7 @@ mock_context(struct drm_i915_private *i915,

err_vm:
if (ctx->vm)
i915_vm_close(ctx->vm);
i915_vm_put(ctx->vm);
err_free:
kfree(ctx);
return NULL;
Expand Down
2 changes: 1 addition & 1 deletion drivers/gpu/drm/i915/gt/gen6_ppgtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -322,7 +322,7 @@ int gen6_ppgtt_pin(struct i915_ppgtt *base, struct i915_gem_ww_ctx *ww)
struct gen6_ppgtt *ppgtt = to_gen6_ppgtt(base);
int err;

GEM_BUG_ON(!atomic_read(&ppgtt->base.vm.open));
GEM_BUG_ON(!kref_read(&ppgtt->base.vm.ref));

/*
* Workaround the limited maximum vma->pin_count and the aliasing_ppgtt
Expand Down
30 changes: 13 additions & 17 deletions drivers/gpu/drm/i915/gt/intel_ggtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ static bool needs_idle_maps(struct drm_i915_private *i915)
void i915_ggtt_suspend_vm(struct i915_address_space *vm)
{
struct i915_vma *vma, *vn;
int open;
int save_skip_rewrite;

drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);

Expand All @@ -135,8 +135,12 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)

mutex_lock(&vm->mutex);

/* Skip rewriting PTE on VMA unbind. */
open = atomic_xchg(&vm->open, 0);
/*
* Skip rewriting PTE on VMA unbind.
* FIXME: Use an argument to i915_vma_unbind() instead?
*/
save_skip_rewrite = vm->skip_pte_rewrite;
vm->skip_pte_rewrite = true;

list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
struct drm_i915_gem_object *obj = vma->obj;
Expand All @@ -154,16 +158,14 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)
*/
i915_gem_object_get(obj);

atomic_set(&vm->open, open);
mutex_unlock(&vm->mutex);

i915_gem_object_lock(obj, NULL);
open = i915_vma_unbind(vma);
GEM_WARN_ON(i915_vma_unbind(vma));
i915_gem_object_unlock(obj);

GEM_WARN_ON(open);

i915_gem_object_put(obj);

vm->skip_pte_rewrite = save_skip_rewrite;
goto retry;
}

Expand All @@ -179,7 +181,7 @@ void i915_ggtt_suspend_vm(struct i915_address_space *vm)

vm->clear_range(vm, 0, vm->total);

atomic_set(&vm->open, open);
vm->skip_pte_rewrite = save_skip_rewrite;

mutex_unlock(&vm->mutex);
}
Expand Down Expand Up @@ -773,13 +775,13 @@ static void ggtt_cleanup_hw(struct i915_ggtt *ggtt)
{
struct i915_vma *vma, *vn;

atomic_set(&ggtt->vm.open, 0);

flush_workqueue(ggtt->vm.i915->wq);
i915_gem_drain_freed_objects(ggtt->vm.i915);

mutex_lock(&ggtt->vm.mutex);

ggtt->vm.skip_pte_rewrite = true;

list_for_each_entry_safe(vma, vn, &ggtt->vm.bound_list, vm_link) {
struct drm_i915_gem_object *obj = vma->obj;
bool trylock;
Expand Down Expand Up @@ -1307,16 +1309,12 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
{
struct i915_vma *vma;
bool write_domain_objs = false;
int open;

drm_WARN_ON(&vm->i915->drm, !vm->is_ggtt && !vm->is_dpt);

/* First fill our portion of the GTT with scratch pages */
vm->clear_range(vm, 0, vm->total);

/* Skip rewriting PTE on VMA unbind. */
open = atomic_xchg(&vm->open, 0);

/* clflush objects bound into the GGTT and rebind them. */
list_for_each_entry(vma, &vm->bound_list, vm_link) {
struct drm_i915_gem_object *obj = vma->obj;
Expand All @@ -1333,8 +1331,6 @@ bool i915_ggtt_resume_vm(struct i915_address_space *vm)
}
}

atomic_set(&vm->open, open);

return write_domain_objs;
}

Expand Down
54 changes: 39 additions & 15 deletions drivers/gpu/drm/i915/gt/intel_gtt.c
Original file line number Diff line number Diff line change
Expand Up @@ -97,32 +97,52 @@ int map_pt_dma_locked(struct i915_address_space *vm, struct drm_i915_gem_object
return 0;
}

void __i915_vm_close(struct i915_address_space *vm)
static void clear_vm_list(struct list_head *list)
{
struct i915_vma *vma, *vn;

if (!atomic_dec_and_mutex_lock(&vm->open, &vm->mutex))
return;

list_for_each_entry_safe(vma, vn, &vm->bound_list, vm_link) {
list_for_each_entry_safe(vma, vn, list, vm_link) {
struct drm_i915_gem_object *obj = vma->obj;

if (!kref_get_unless_zero(&obj->base.refcount)) {
if (!i915_gem_object_get_rcu(obj)) {
/*
* Unbind the dying vma to ensure the bound_list
* Object is dying, but has not yet cleared its
* vma list.
* Unbind the dying vma to ensure our list
* is completely drained. We leave the destruction to
* the object destructor.
* the object destructor to avoid the vma
* disappearing under it.
*/
atomic_and(~I915_VMA_PIN_MASK, &vma->flags);
WARN_ON(__i915_vma_unbind(vma));
continue;

/* Remove from the unbound list */
list_del_init(&vma->vm_link);

/*
* Delay the vm and vm mutex freeing until the
* object is done with destruction.
*/
i915_vm_resv_get(vma->vm);
vma->vm_ddestroy = true;
} else {
i915_vma_destroy_locked(vma);
i915_gem_object_put(obj);
}

/* Keep the obj (and hence the vma) alive as _we_ destroy it */
i915_vma_destroy_locked(vma);
i915_gem_object_put(obj);
}
}

static void __i915_vm_close(struct i915_address_space *vm)
{
mutex_lock(&vm->mutex);

clear_vm_list(&vm->bound_list);
clear_vm_list(&vm->unbound_list);

/* Check for must-fix unanticipated side-effects */
GEM_BUG_ON(!list_empty(&vm->bound_list));
GEM_BUG_ON(!list_empty(&vm->unbound_list));

mutex_unlock(&vm->mutex);
}
Expand All @@ -144,22 +164,24 @@ int i915_vm_lock_objects(struct i915_address_space *vm,
void i915_address_space_fini(struct i915_address_space *vm)
{
drm_mm_takedown(&vm->mm);
mutex_destroy(&vm->mutex);
}

/**
* i915_vm_resv_release - Final struct i915_address_space destructor
* @kref: Pointer to the &i915_address_space.resv_ref member.
*
* This function is called when the last lock sharer no longer shares the
* &i915_address_space._resv lock.
* &i915_address_space._resv lock, and also if we raced when
* destroying a vma by the vma destruction
*/
void i915_vm_resv_release(struct kref *kref)
{
struct i915_address_space *vm =
container_of(kref, typeof(*vm), resv_ref);

dma_resv_fini(&vm->_resv);
mutex_destroy(&vm->mutex);

kfree(vm);
}

Expand All @@ -168,6 +190,8 @@ static void __i915_vm_release(struct work_struct *work)
struct i915_address_space *vm =
container_of(work, struct i915_address_space, release_work);

__i915_vm_close(vm);

/* Synchronize async unbinds. */
i915_vma_resource_bind_dep_sync_all(vm);

Expand Down Expand Up @@ -201,7 +225,6 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)

vm->pending_unbind = RB_ROOT_CACHED;
INIT_WORK(&vm->release_work, __i915_vm_release);
atomic_set(&vm->open, 1);

/*
* The vm->mutex must be reclaim safe (for use in the shrinker).
Expand Down Expand Up @@ -245,6 +268,7 @@ void i915_address_space_init(struct i915_address_space *vm, int subclass)
vm->mm.head_node.color = I915_COLOR_UNEVICTABLE;

INIT_LIST_HEAD(&vm->bound_list);
INIT_LIST_HEAD(&vm->unbound_list);
}

void *__px_vaddr(struct drm_i915_gem_object *p)
Expand Down
Loading

0 comments on commit e1a7ab4

Please sign in to comment.