]> git.kernelconcepts.de Git - karo-tx-linux.git/blobdiff - drivers/gpu/drm/i915/i915_gem_evict.c
drm/i915: Eliminate lots of iterations over the execobjects array
[karo-tx-linux.git] / drivers / gpu / drm / i915 / i915_gem_evict.c
index 204a2d9288aea91075e9f7411a4542b5473c328e..a193f1b36c679e3414dc3b7cfb3bc634e6d394c6 100644 (file)
@@ -50,6 +50,29 @@ static bool ggtt_is_idle(struct drm_i915_private *dev_priv)
        return true;
 }
 
+static int ggtt_flush(struct drm_i915_private *i915)
+{
+       int err;
+
+       /* Not everything in the GGTT is tracked via vma (otherwise we
+        * could evict as required with minimal stalling) so we are forced
+        * to idle the GPU and explicitly retire outstanding requests in
+        * the hopes that we can then remove contexts and the like only
+        * bound by their active reference.
+        */
+       err = i915_gem_switch_to_kernel_context(i915);
+       if (err)
+               return err;
+
+       err = i915_gem_wait_for_idle(i915,
+                                    I915_WAIT_INTERRUPTIBLE |
+                                    I915_WAIT_LOCKED);
+       if (err)
+               return err;
+
+       return 0;
+}
+
 static bool
 mark_free(struct drm_mm_scan *scan,
          struct i915_vma *vma,
@@ -175,19 +198,7 @@ search_again:
                return intel_has_pending_fb_unpin(dev_priv) ? -EAGAIN : -ENOSPC;
        }
 
-       /* Not everything in the GGTT is tracked via vma (otherwise we
-        * could evict as required with minimal stalling) so we are forced
-        * to idle the GPU and explicitly retire outstanding requests in
-        * the hopes that we can then remove contexts and the like only
-        * bound by their active reference.
-        */
-       ret = i915_gem_switch_to_kernel_context(dev_priv);
-       if (ret)
-               return ret;
-
-       ret = i915_gem_wait_for_idle(dev_priv,
-                                    I915_WAIT_INTERRUPTIBLE |
-                                    I915_WAIT_LOCKED);
+       ret = ggtt_flush(dev_priv);
        if (ret)
                return ret;
 
@@ -337,10 +348,8 @@ int i915_gem_evict_for_node(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.
+ * This function evicts all vmas from a vm.
  *
  * This is used by the execbuf code as a last-ditch effort to defragment the
  * address space.
@@ -348,37 +357,50 @@ int i915_gem_evict_for_node(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 list_head *phases[] = {
+               &vm->inactive_list,
+               &vm->active_list,
+               NULL
+       }, **phase;
+       struct list_head eviction_list;
        struct i915_vma *vma, *next;
        int ret;
 
        lockdep_assert_held(&vm->i915->drm.struct_mutex);
        trace_i915_gem_evict_vm(vm);
 
-       if (do_idle) {
-               struct drm_i915_private *dev_priv = vm->i915;
-
-               if (i915_is_ggtt(vm)) {
-                       ret = i915_gem_switch_to_kernel_context(dev_priv);
-                       if (ret)
-                               return ret;
-               }
-
-               ret = i915_gem_wait_for_idle(dev_priv,
-                                            I915_WAIT_INTERRUPTIBLE |
-                                            I915_WAIT_LOCKED);
+       /* Switch back to the default context in order to unpin
+        * the existing context objects. However, such objects only
+        * pin themselves inside the global GTT and performing the
+        * switch otherwise is ineffective.
+        */
+       if (i915_is_ggtt(vm)) {
+               ret = ggtt_flush(vm->i915);
                if (ret)
                        return ret;
-
-               WARN_ON(!list_empty(&vm->active_list));
        }
 
-       list_for_each_entry_safe(vma, next, &vm->inactive_list, vm_link)
-               if (!i915_vma_is_pinned(vma))
-                       WARN_ON(i915_vma_unbind(vma));
+       INIT_LIST_HEAD(&eviction_list);
+       phase = phases;
+       do {
+               list_for_each_entry(vma, *phase, vm_link) {
+                       if (i915_vma_is_pinned(vma))
+                               continue;
 
-       return 0;
+                       __i915_vma_pin(vma);
+                       list_add(&vma->evict_link, &eviction_list);
+               }
+       } while (*++phase);
+
+       ret = 0;
+       list_for_each_entry_safe(vma, next, &eviction_list, evict_link) {
+               __i915_vma_unpin(vma);
+               if (ret == 0)
+                       ret = i915_vma_unbind(vma);
+       }
+       return ret;
 }
 
 #if IS_ENABLED(CONFIG_DRM_I915_SELFTEST)