Commit b9d06dd9 authored by Michel Thierry's avatar Michel Thierry Committed by Daniel Vetter

drm/i915: vma/ppgtt lifetime rules

VMAs should take a reference of the address space they use.

Now, when the fd is closed, it will release the ref that the context was
holding, but it will still be referenced by any vmas that are still
active.

ppgtt_release() should then only be called when the last thing referencing
it releases the ref, and it can just call the base cleanup and free the
ppgtt.

Note that with this we will extend the lifetime of ppgtts which
contain shared objects. But all the non-shared objects will get
removed as soon as they drop of the active list and for the shared
ones the shrinker can eventually reap them. Since we currently can't
evict ppgtt pagetables either I don't think that temporary leak is
important.
Signed-off-by: default avatarMichel Thierry <michel.thierry@intel.com>
[danvet: Add note about potential ppgtt leak with this approach.]
Signed-off-by: default avatarDaniel Vetter <daniel.vetter@ffwll.ch>
parent 14bf993e
...@@ -2547,7 +2547,9 @@ void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj); ...@@ -2547,7 +2547,9 @@ void i915_gem_object_ggtt_unpin(struct drm_i915_gem_object *obj);
/* i915_gem_context.c */ /* i915_gem_context.c */
#define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base) #define ctx_to_ppgtt(ctx) container_of((ctx)->vm, struct i915_hw_ppgtt, base)
#define vm_to_ppgtt(vm) container_of(vm, struct i915_hw_ppgtt, base)
int __must_check i915_gem_context_init(struct drm_device *dev); int __must_check i915_gem_context_init(struct drm_device *dev);
void ppgtt_release(struct kref *kref);
void i915_gem_context_fini(struct drm_device *dev); void i915_gem_context_fini(struct drm_device *dev);
void i915_gem_context_reset(struct drm_device *dev); void i915_gem_context_reset(struct drm_device *dev);
int i915_gem_context_open(struct drm_device *dev, struct drm_file *file); int i915_gem_context_open(struct drm_device *dev, struct drm_file *file);
......
...@@ -4476,12 +4476,20 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj, ...@@ -4476,12 +4476,20 @@ struct i915_vma *i915_gem_obj_to_vma(struct drm_i915_gem_object *obj,
void i915_gem_vma_destroy(struct i915_vma *vma) void i915_gem_vma_destroy(struct i915_vma *vma)
{ {
struct i915_address_space *vm = NULL;
struct i915_hw_ppgtt *ppgtt = NULL;
WARN_ON(vma->node.allocated); WARN_ON(vma->node.allocated);
/* Keep the vma as a placeholder in the execbuffer reservation lists */ /* Keep the vma as a placeholder in the execbuffer reservation lists */
if (!list_empty(&vma->exec_list)) if (!list_empty(&vma->exec_list))
return; return;
vm = vma->vm;
ppgtt = vm_to_ppgtt(vm);
if (ppgtt)
kref_put(&ppgtt->ref, ppgtt_release);
list_del(&vma->vma_link); list_del(&vma->vma_link);
kfree(vma); kfree(vma);
......
...@@ -108,30 +108,13 @@ static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt) ...@@ -108,30 +108,13 @@ static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
return; return;
} }
/* /* vmas should already be unbound */
* Make sure vmas are unbound before we take down the drm_mm WARN_ON(!list_empty(&vm->active_list));
*
* FIXME: Proper refcounting should take care of this, this shouldn't be
* needed at all.
*/
if (!list_empty(&vm->active_list)) {
struct i915_vma *vma;
list_for_each_entry(vma, &vm->active_list, mm_list)
if (WARN_ON(list_empty(&vma->vma_link) ||
list_is_singular(&vma->vma_link)))
break;
i915_gem_evict_vm(&ppgtt->base, true);
} else {
i915_gem_retire_requests(dev);
i915_gem_evict_vm(&ppgtt->base, false);
}
ppgtt->base.cleanup(&ppgtt->base); ppgtt->base.cleanup(&ppgtt->base);
} }
static void ppgtt_release(struct kref *kref) void ppgtt_release(struct kref *kref)
{ {
struct i915_hw_ppgtt *ppgtt = struct i915_hw_ppgtt *ppgtt =
container_of(kref, struct i915_hw_ppgtt, ref); container_of(kref, struct i915_hw_ppgtt, ref);
......
...@@ -2148,10 +2148,15 @@ i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj, ...@@ -2148,10 +2148,15 @@ i915_gem_obj_lookup_or_create_vma(struct drm_i915_gem_object *obj,
struct i915_address_space *vm) struct i915_address_space *vm)
{ {
struct i915_vma *vma; struct i915_vma *vma;
struct i915_hw_ppgtt *ppgtt = NULL;
vma = i915_gem_obj_to_vma(obj, vm); vma = i915_gem_obj_to_vma(obj, vm);
if (!vma) if (!vma)
vma = __i915_gem_vma_create(obj, vm); vma = __i915_gem_vma_create(obj, vm);
ppgtt = vm_to_ppgtt(vm);
if (ppgtt)
kref_get(&ppgtt->ref);
return vma; return vma;
} }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment