[Intel-gfx] [PATCH] drm/i915: Protect mmaped buffers from casual eviction.

Chris Wilson chris at chris-wilson.co.uk
Tue May 11 17:55:27 CEST 2010


By keeping buffers that are in use by the CPU, having been mmapped and
moved to the CPU or GTT domain since their last rendering on a separate
inactive list, prevents the first-pass eviction process from unbinding
one of these buffers. Those buffers are evicted as normal during
evict-everything so that the memory can be recovered under high pressure
or a forced idle.

References:

  Bug 20152 - [G45/GM965 UXA] cannot view JPG in firefox when running UXA
  https://bugs.freedesktop.org/show_bug.cgi?id=20152

  Bug 24369 - Hang when scrolling firefox page with window in front
  https://bugs.freedesktop.org/show_bug.cgi?id=24369

  Bug 15911 -  Intermittent X crash (freeze)
  https://bugzilla.kernel.org/show_bug.cgi?id=15911

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
Tested-by: Christian von Schultz <kernel at vonschultz.se>
---
 drivers/gpu/drm/i915/i915_drv.h |   13 +++++++
 drivers/gpu/drm/i915/i915_gem.c |   71 ++++++++++++++++++++++++++++++++++----
 2 files changed, 76 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h
index 317c9bf..f99936f 100644
--- a/drivers/gpu/drm/i915/i915_drv.h
+++ b/drivers/gpu/drm/i915/i915_drv.h
@@ -557,6 +557,19 @@ typedef struct drm_i915_private {
 		 */
 		struct list_head inactive_list;
 
+		/**
+		 * LRU list of objects which are not in the ringbuffer and
+		 * are ready to unbind, but are still in the GTT and currently
+		 * mapped and in use by the CPU.
+		 *
+		 * last_rendering_seqno is 0 while an object is in this list.
+		 *
+		 * A reference is not held on the buffer while on this list,
+		 * as merely being GTT-bound shouldn't prevent its being
+		 * freed, and we'll pull it off the list in the free path.
+		 */
+		struct list_head mmap_list;
+
 		/** LRU list of objects with fence regs on them. */
 		struct list_head fence_list;
 
diff --git a/drivers/gpu/drm/i915/i915_gem.c b/drivers/gpu/drm/i915/i915_gem.c
index 229354e..9a73b20 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -52,6 +52,7 @@ static int i915_gem_object_bind_to_gtt(struct drm_gem_object *obj,
 static void i915_gem_clear_fence_reg(struct drm_gem_object *obj);
 static int i915_gem_evict_something(struct drm_device *dev, int min_size);
 static int i915_gem_evict_from_inactive_list(struct drm_device *dev);
+static int i915_gem_evict_from_mmap_list(struct drm_device *dev);
 static int i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
 				struct drm_i915_gem_pwrite *args,
 				struct drm_file *file_priv);
@@ -1064,6 +1065,9 @@ i915_gem_set_domain_ioctl(struct drm_device *dev, void *data,
 		ret = i915_gem_object_set_to_cpu_domain(obj, write_domain != 0);
 	}
 
+	if (ret == 0 && obj_priv->gtt_space && !obj_priv->active)
+	    list_move_tail(&obj_priv->list, &dev_priv->mm.mmap_list);
+
 	drm_gem_object_unreference(obj);
 	mutex_unlock(&dev->struct_mutex);
 	return ret;
@@ -1197,6 +1201,9 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
 			goto unlock;
 	}
 
+	if (!obj_priv->active)
+		list_move_tail(&obj_priv->list, &dev_priv->mm.mmap_list);
+
 	pfn = ((dev->agp->base + obj_priv->gtt_offset) >> PAGE_SHIFT) +
 		page_offset;
 
@@ -2162,7 +2169,8 @@ i915_gem_evict_everything(struct drm_device *dev)
 	bool lists_empty;
 
 	spin_lock(&dev_priv->mm.active_list_lock);
-	lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
+	lists_empty = (list_empty(&dev_priv->mm.mmap_list) &&
+		       list_empty(&dev_priv->mm.inactive_list) &&
 		       list_empty(&dev_priv->mm.flushing_list) &&
 		       list_empty(&dev_priv->mm.active_list));
 	spin_unlock(&dev_priv->mm.active_list_lock);
@@ -2177,12 +2185,17 @@ i915_gem_evict_everything(struct drm_device *dev)
 
 	BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
 
+	ret = i915_gem_evict_from_mmap_list(dev);
+	if (ret)
+		return ret;
+
 	ret = i915_gem_evict_from_inactive_list(dev);
 	if (ret)
 		return ret;
 
 	spin_lock(&dev_priv->mm.active_list_lock);
-	lists_empty = (list_empty(&dev_priv->mm.inactive_list) &&
+	lists_empty = (list_empty(&dev_priv->mm.mmap_list) &&
+		       list_empty(&dev_priv->mm.inactive_list) &&
 		       list_empty(&dev_priv->mm.flushing_list) &&
 		       list_empty(&dev_priv->mm.active_list));
 	spin_unlock(&dev_priv->mm.active_list_lock);
@@ -4624,17 +4637,15 @@ void i915_gem_free_object(struct drm_gem_object *obj)
 	kfree(obj->driver_private);
 }
 
-/** Unbinds all inactive objects. */
 static int
-i915_gem_evict_from_inactive_list(struct drm_device *dev)
+i915_gem_evict_from_list(struct drm_device *dev,
+			 struct list_head *list)
 {
-	drm_i915_private_t *dev_priv = dev->dev_private;
-
-	while (!list_empty(&dev_priv->mm.inactive_list)) {
+	while (!list_empty(list)) {
 		struct drm_gem_object *obj;
 		int ret;
 
-		obj = list_first_entry(&dev_priv->mm.inactive_list,
+		obj = list_first_entry(list,
 				       struct drm_i915_gem_object,
 				       list)->obj;
 
@@ -4648,6 +4659,23 @@ i915_gem_evict_from_inactive_list(struct drm_device *dev)
 	return 0;
 }
 
+/** Unbinds all inactive objects. */
+static int
+i915_gem_evict_from_inactive_list(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	return i915_gem_evict_from_list(dev, &dev_priv->mm.inactive_list);
+}
+
+static int
+i915_gem_evict_from_mmap_list(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	return i915_gem_evict_from_list(dev, &dev_priv->mm.mmap_list);
+}
+
 int
 i915_gem_idle(struct drm_device *dev)
 {
@@ -4674,6 +4702,12 @@ i915_gem_idle(struct drm_device *dev)
 			mutex_unlock(&dev->struct_mutex);
 			return ret;
 		}
+
+		ret = i915_gem_evict_from_mmap_list(dev);
+		if (ret) {
+			mutex_unlock(&dev->struct_mutex);
+			return ret;
+		}
 	}
 
 	/* Hack!  Don't let anybody do execbuf while we don't control the chip.
@@ -5010,6 +5044,7 @@ i915_gem_entervt_ioctl(struct drm_device *dev, void *data,
 
 	BUG_ON(!list_empty(&dev_priv->mm.flushing_list));
 	BUG_ON(!list_empty(&dev_priv->mm.inactive_list));
+	BUG_ON(!list_empty(&dev_priv->mm.mmap_list));
 	BUG_ON(!list_empty(&dev_priv->mm.request_list));
 	mutex_unlock(&dev->struct_mutex);
 
@@ -5053,6 +5088,7 @@ i915_gem_load(struct drm_device *dev)
 	INIT_LIST_HEAD(&dev_priv->mm.flushing_list);
 	INIT_LIST_HEAD(&dev_priv->mm.gpu_write_list);
 	INIT_LIST_HEAD(&dev_priv->mm.inactive_list);
+	INIT_LIST_HEAD(&dev_priv->mm.mmap_list);
 	INIT_LIST_HEAD(&dev_priv->mm.request_list);
 	INIT_LIST_HEAD(&dev_priv->mm.fence_list);
 	INIT_DELAYED_WORK(&dev_priv->mm.retire_work,
@@ -5308,6 +5344,22 @@ i915_gpu_is_active(struct drm_device *dev)
 }
 
 static int
+i915_move_mmap_onto_inactive_list(struct drm_device *dev)
+{
+	drm_i915_private_t *dev_priv = dev->dev_private;
+
+	if (list_empty(&dev_priv->mm.mmap_list))
+		return 0;
+
+	do {
+		list_move_tail(dev_priv->mm.mmap_list.next,
+			       &dev_priv->mm.inactive_list);
+	} while (!list_empty(&dev_priv->mm.mmap_list));
+
+	return 1;
+}
+
+static int
 i915_gem_shrink(int nr_to_scan, gfp_t gfp_mask)
 {
 	drm_i915_private_t *dev_priv, *next_dev;
@@ -5416,6 +5468,9 @@ rescan:
 				active++;
 			}
 
+			if (i915_move_mmap_onto_inactive_list(dev))
+				active++;
+
 			spin_lock(&shrink_list_lock);
 			mutex_unlock(&dev->struct_mutex);
 		}
-- 
1.7.1




More information about the Intel-gfx mailing list