[Intel-gfx] [PATCH 60/70] drm/i915: Make evict-everything more robust

Chris Wilson chris at chris-wilson.co.uk
Tue Apr 7 09:28:18 PDT 2015


Since we are operating at the global level, we can simply iterate over
the bound list using the robust method developed for the shrinker.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/i915_drv.h            |  2 +-
 drivers/gpu/drm/i915/i915_gem_evict.c      | 54 +++++++++++++++++-------------
 drivers/gpu/drm/i915/i915_gem_execbuffer.c |  2 +-
 3 files changed, 32 insertions(+), 26 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index c48909f6baa2..97372869097f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -2994,7 +2994,7 @@ int __must_check i915_gem_evict_something(struct drm_device *dev,
 int __must_check
 i915_gem_evict_range(struct drm_device *dev, struct i915_address_space *vm,
 		     unsigned long start, unsigned long end);
-int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
+int i915_gem_evict_vm(struct i915_address_space *vm);
 int i915_gem_evict_everything(struct drm_device *dev);
 
 /* belongs in i915_gem_gtt.h */
diff --git a/drivers/gpu/drm/i915/i915_gem_evict.c b/drivers/gpu/drm/i915/i915_gem_evict.c
index 9754740edecd..cf33f982da8e 100644
--- a/drivers/gpu/drm/i915/i915_gem_evict.c
+++ b/drivers/gpu/drm/i915/i915_gem_evict.c
@@ -254,7 +254,6 @@ i915_gem_evict_range(struct drm_device *dev, struct i915_address_space *vm,
 /**
  * i915_gem_evict_vm - Evict all idle vmas from a vm
  * @vm: Address space to cleanse
- * @do_idle: Boolean directing whether to idle first.
  *
  * This function evicts all idles vmas from a vm. If all unpinned vmas should be
  * evicted the @do_idle needs to be set to true.
@@ -265,7 +264,7 @@ i915_gem_evict_range(struct drm_device *dev, struct i915_address_space *vm,
  * To clarify: This is for freeing up virtual address space, not for freeing
  * memory in e.g. the shrinker.
  */
-int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
+int i915_gem_evict_vm(struct i915_address_space *vm)
 {
 	struct i915_vma *vma, *next;
 	int ret;
@@ -273,16 +272,14 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
 	WARN_ON(!mutex_is_locked(&vm->dev->struct_mutex));
 	trace_i915_gem_evict_vm(vm);
 
-	if (do_idle) {
-		ret = i915_gpu_idle(vm->dev);
-		if (ret)
-			return ret;
-
-		i915_gem_retire_requests(vm->dev);
+	ret = i915_gpu_idle(vm->dev);
+	if (ret)
+		return ret;
 
-		WARN_ON(!list_empty(&vm->active_list));
-	}
+	i915_gem_retire_requests(vm->dev);
+	WARN_ON(!list_empty(&vm->active_list));
 
+	/* Having flushed everything, unbind() should never raise an error */
 	list_for_each_entry_safe(vma, next, &vm->inactive_list, mm_list)
 		if (vma->pin_count == 0)
 			WARN_ON(i915_vma_unbind(vma));
@@ -297,23 +294,19 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
  * This functions tries to evict all gem objects from all address spaces. Used
  * by the shrinker as a last-ditch effort and for suspend, before releasing the
  * backing storage of all unbound objects.
+ *
+ * This is similar to i915_gem_shrink_all() with the important exception that
+ * we keep a reference to the obj->pages after unbinding (so we can avoid
+ * any expensive migration between the CPU and GPU).
  */
 int
 i915_gem_evict_everything(struct drm_device *dev)
 {
-	struct drm_i915_private *dev_priv = dev->dev_private;
-	struct i915_address_space *vm, *v;
-	bool lists_empty = true;
+	struct drm_i915_private *dev_priv = to_i915(dev);
+	struct list_head still_in_list;
 	int ret;
 
-	list_for_each_entry(vm, &dev_priv->vm_list, global_link) {
-		lists_empty = (list_empty(&vm->inactive_list) &&
-			       list_empty(&vm->active_list));
-		if (!lists_empty)
-			lists_empty = false;
-	}
-
-	if (lists_empty)
+	if (list_empty(&dev_priv->mm.bound_list))
 		return -ENOSPC;
 
 	trace_i915_gem_evict_everything(dev);
@@ -328,9 +321,22 @@ i915_gem_evict_everything(struct drm_device *dev)
 
 	i915_gem_retire_requests(dev);
 
-	/* Having flushed everything, unbind() should never raise an error */
-	list_for_each_entry_safe(vm, v, &dev_priv->vm_list, global_link)
-		WARN_ON(i915_gem_evict_vm(vm, false));
+	INIT_LIST_HEAD(&still_in_list);
+	while (!list_empty(&dev_priv->mm.bound_list)) {
+		struct drm_i915_gem_object *obj;
+		struct i915_vma *vma, *v;
+
+		obj = list_first_entry(&dev_priv->mm.bound_list,
+				       typeof(*obj), global_list);
+		list_move_tail(&obj->global_list, &still_in_list);
+
+		drm_gem_object_reference(&obj->base);
+		list_for_each_entry_safe(vma, v, &obj->vma_list, vma_link)
+			if (WARN_ON(i915_vma_unbind(vma)))
+				break;
+		drm_gem_object_unreference(&obj->base);
+	}
+	list_splice(&still_in_list, &dev_priv->mm.bound_list);
 
 	return 0;
 }
diff --git a/drivers/gpu/drm/i915/i915_gem_execbuffer.c b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
index 9afd2dcba43b..bd48393fb91f 100644
--- a/drivers/gpu/drm/i915/i915_gem_execbuffer.c
+++ b/drivers/gpu/drm/i915/i915_gem_execbuffer.c
@@ -820,7 +820,7 @@ err:
 		list_for_each_entry(vma, vmas, exec_list)
 			i915_gem_execbuffer_unreserve_vma(vma);
 
-		ret = i915_gem_evict_vm(vm, true);
+		ret = i915_gem_evict_vm(vm);
 		if (ret)
 			return ret;
 	} while (1);
-- 
2.1.4



More information about the Intel-gfx mailing list