@@ -2553,7 +2553,7 @@ int __must_check i915_gem_evict_something(struct drm_device *dev,
unsigned long start,
unsigned long end,
unsigned flags);
-int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle);
+int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle, bool interruptible);
int i915_gem_evict_everything(struct drm_device *dev);
/* belongs in i915_gem_gtt.h */
@@ -121,11 +121,10 @@ static void do_ppgtt_cleanup(struct i915_hw_ppgtt *ppgtt)
if (WARN_ON(list_empty(&vma->vma_link) ||
list_is_singular(&vma->vma_link)))
break;
-
- i915_gem_evict_vm(&ppgtt->base, true);
+ i915_gem_evict_vm(&ppgtt->base, true, true);
} else {
i915_gem_retire_requests(dev);
- i915_gem_evict_vm(&ppgtt->base, false);
+ i915_gem_evict_vm(&ppgtt->base, false, true);
}
ppgtt->base.cleanup(&ppgtt->base);
@@ -197,8 +197,9 @@ found:
/**
* i915_gem_evict_vm - Evict all idle vmas from a vm
*
- * @vm: Address space to cleanse
- * @do_idle: Boolean directing whether to idle first.
+ * @vm: Address space to cleanse
+ * @do_idle: Boolean directing whether to idle first.
+ * @interruptible: How to wait
*
* 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.
@@ -209,18 +210,24 @@ found:
* 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, bool do_idle, bool interruptible)
{
+ struct drm_i915_private *dev_priv = to_i915(vm->dev);
+
struct i915_vma *vma, *next;
+ bool was_intr = dev_priv->mm.interruptible;
int ret;
BUG_ON(!mutex_is_locked(&vm->dev->struct_mutex));
trace_i915_gem_evict_vm(vm);
+ if (!interruptible)
+ dev_priv->mm.interruptible = false;
+
if (do_idle) {
ret = i915_gpu_idle(vm->dev);
if (ret)
- return ret;
+ goto out;
i915_gem_retire_requests(vm->dev);
@@ -229,11 +236,20 @@ int i915_gem_evict_vm(struct i915_address_space *vm, bool do_idle)
list_for_each_entry_safe(vma, next, &vm->inactive_list, mm_list) {
WARN_ON(!i915_is_ggtt(vm) && vma->pin_count);
- if (vma->pin_count == 0)
- WARN_ON(i915_vma_unbind(vma));
+ if (vma->pin_count == 0) {
+ ret = i915_vma_unbind(vma);
+ if (ret == -ERESTARTSYS) {
+ BUG_ON(!interruptible);
+ goto out;
+ } else if (ret)
+ WARN(1, "Failed to unbind vma %d\n", ret);
+ }
}
+ ret = 0;
- return 0;
+out:
+ dev_priv->mm.interruptible = was_intr;
+ return ret;
}
/**
@@ -276,7 +292,7 @@ i915_gem_evict_everything(struct drm_device *dev)
/* Having flushed everything, unbind() should never raise an error */
list_for_each_entry(vm, &dev_priv->vm_list, global_link)
- WARN_ON(i915_gem_evict_vm(vm, false));
+ WARN_ON(i915_gem_evict_vm(vm, false, true));
return 0;
}
@@ -722,7 +722,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, true, true);
if (ret)
return ret;
} while (1);
There are no users of this yet, but the idea is presented and split out to find bugs. Also, while here, return -ERESTARTSYS to the caller, in case they want to do something with it. Signed-off-by: Ben Widawsky <ben@bwidawsk.net> --- drivers/gpu/drm/i915/i915_drv.h | 2 +- drivers/gpu/drm/i915/i915_gem_context.c | 5 ++--- drivers/gpu/drm/i915/i915_gem_evict.c | 32 ++++++++++++++++++++++-------- drivers/gpu/drm/i915/i915_gem_execbuffer.c | 2 +- 4 files changed, 28 insertions(+), 13 deletions(-)