diff mbox

[9/9] drm/i915: implement fair lru eviction

Message ID 1274217111-3882-10-git-send-email-daniel.vetter@ffwll.ch (mailing list archive)
State Deferred, archived
Headers show

Commit Message

Daniel Vetter May 18, 2010, 9:11 p.m. UTC
None
diff mbox

Patch

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