Besides that this should leader to better gtt usage (by not favouring
small objects) this also fixes the eviction-ping-pong-of-doom.

Signed-off-by: Daniel Vetter <daniel.vetter at ffwll.ch>
---
 drivers/gpu/drm/i915/i915_gem.c |   79 +++++++++++++++++++++++++-------------
 1 files changed, 52 insertions(+), 27 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index d5a7db7..71b01b8 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -2120,45 +2120,70 @@ i915_gem_scan_inactive_list_and_evict(struct drm_device 
*dev, int min_size,
                                      unsigned alignment, int *found)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
-       struct drm_gem_object *obj;
-       struct drm_i915_gem_object *obj_priv;
-       struct drm_gem_object *best = NULL;
-       struct drm_gem_object *first = NULL;
+       struct list_head eviction_list;
+       struct drm_i915_gem_object *obj_priv, *tmp_obj_priv;
+       int ret = 0;
+
+       INIT_LIST_HEAD(&eviction_list);
+       *found = 0;
+
+       drm_mm_init_scan(&dev_priv->mm.gtt_space, min_size, alignment);

-       /* Try to find the smallest clean object */
        list_for_each_entry(obj_priv, &dev_priv->mm.inactive_list, list) {
-               struct drm_gem_object *obj = &obj_priv->base;
-               if (obj->size >= min_size) {
-                       if ((!obj_priv->dirty ||
-                            i915_gem_object_is_purgeable(obj_priv)) &&
-                           (!best || obj->size < best->size)) {
-                               best = obj;
-                               if (best->size == min_size)
-                                       break;
-                       }
-                       if (!first)
-                           first = obj;
-               }
+               *found = drm_mm_scan_add_block(obj_priv->gtt_space);
+
+               if (*found)
+                       break;
        }

-       obj = best ? best : first;
+       if (!*found) {
+               /* Nothing found, clean up and bail out! */
+               list_for_each_entry_safe_reverse(obj_priv, tmp_obj_priv,
+                                                &dev_priv->mm.inactive_list,
+                                                list) {
+                       ret = drm_mm_scan_remove_block(obj_priv->gtt_space);
+
+                       BUG_ON(ret);
+               }

-       if (!obj) {
-               *found = 0;
                return 0;
        }

-       *found = 1;
+       list_for_each_entry_safe_from_reverse(obj_priv, tmp_obj_priv,
+                                             &dev_priv->mm.inactive_list,
+                                             list) {
+               if (drm_mm_scan_remove_block(obj_priv->gtt_space)) {
+                       /* drm_mm doesn't allow any other other operations while
+                        * scanning, therefore store to be evicted objects on a
+                        * temporary list. */
+                       list_move(&obj_priv->list, &eviction_list);
+               }
+       }

+       list_for_each_entry_safe(obj_priv, tmp_obj_priv,
+                                &eviction_list, list) {
 #if WATCH_LRU
-       DRM_INFO("%s: evicting %p\n", __func__, obj);
+               DRM_INFO("%s: evicting %p\n", __func__, obj);
 #endif
-       obj_priv = to_intel_bo(obj);
-       BUG_ON(obj_priv->pin_count != 0);
-       BUG_ON(obj_priv->active);
+               ret = i915_gem_object_unbind(&obj_priv->base);
+
+               if (ret != 0)
+                       goto fail;
+       }

-       /* Wait on the rendering and unbind the buffer. */
-       return i915_gem_object_unbind(obj);
+       /* The just created free hole should be on the top of the free stack
+        * maintained by drm_mm, so this BUG_ON actually executes in O(1).
+        * Furthermore all accessed data has just recently been used, so it
+        * should be really fast, too. */
+       BUG_ON(!drm_mm_search_free(&dev_priv->mm.gtt_space, min_size,
+                                  alignment, 0));
+
+       return 0;
+
+fail:
+       list_splice(&eviction_list, &dev_priv->mm.inactive_list);
+
+       return ret;
 }

 static int
-- 
1.7.1

Reply via email to