diff mbox

drm/i915: Use the LLC mode on gen6 for everything but display.

Message ID 1299874280-2288-1-git-send-email-eric@anholt.net (mailing list archive)
State New, archived
Headers show

Commit Message

Eric Anholt March 11, 2011, 8: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 36e66cc..f4f6de3 100644
--- a/drivers/gpu/drm/i915/i915_gem.c
+++ b/drivers/gpu/drm/i915/i915_gem.c
@@ -3539,7 +3539,23 @@  struct drm_i915_gem_object *i915_gem_alloc_object(struct drm_device *dev,
 	obj->base.write_domain = I915_GEM_DOMAIN_CPU;
 	obj->base.read_domains = I915_GEM_DOMAIN_CPU;
 
-	obj->agp_type = AGP_USER_MEMORY;
+	if (IS_GEN6(dev)) {
+		/* On Gen6, we can have the GPU use the LLC (the CPU
+		 * cache) for about a 10% performance improvement
+		 * compared to uncached.  Graphics requests other than
+		 * display scanout are coherent with the CPU in
+		 * accessing this cache.  This means in this mode we
+		 * don't need to clflush on the CPU side, and on the
+		 * GPU side we only need to flush internal caches to
+		 * get data visible to the CPU.
+		 *
+		 * For display, see intel_pin_and_fence_fb_obj() for
+		 * how we handle changing the caching.
+		 */
+		obj->agp_type = AGP_USER_CACHED_MEMORY;
+	} else {
+		obj->agp_type = AGP_USER_MEMORY;
+	}
 	obj->base.driver_private = NULL;
 	obj->fence_reg = I915_FENCE_REG_NONE;
 	INIT_LIST_HEAD(&obj->mm_list);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 49fb54f..0b3096a 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1456,6 +1456,45 @@  out_disable:
 	}
 }
 
+/* The display engine is not coherent with the LLC cache on gen6.  As
+ * a result, we make sure that the pinning that is about to occur is
+ * done with uncached PTEs.
+ *
+ * We could do this better in a couple of ways.  The most important
+ * would be to use the GFDT bit instead of uncaching, which would
+ * allow us to flush all the LLC-cached data with that bit in the PTE
+ * to main memory with just one PIPE_CONTROL.  The other would be to
+ * update the PTEs by calling i915_gem_gtt_bind_object() and then
+ * flush any existing CPU cache of the object, instead of unbinding.
+ */
+static int
+i915_set_pte_uncached(struct drm_i915_gem_object *obj)
+{
+	int ret;
+
+	if (obj->agp_type == AGP_USER_MEMORY)
+		return 0;
+
+	obj->agp_type = AGP_USER_MEMORY;
+
+	if (obj->pin_count > 0) {
+		static int once = 0;
+		if (!once) {
+			DRM_ERROR("Trying to change caching on pinned fb\n");
+			once = 1;
+		}
+		return -EBUSY;
+	}
+
+	ret = i915_gem_object_unbind(obj);
+	if (ret)
+		return ret;
+
+	obj->agp_type = AGP_USER_MEMORY;
+
+	return 0;
+}
+
 int
 intel_pin_and_fence_fb_obj(struct drm_device *dev,
 			   struct drm_i915_gem_object *obj,
@@ -1485,6 +1524,12 @@  intel_pin_and_fence_fb_obj(struct drm_device *dev,
 		BUG();
 	}
 
+	if (IS_GEN6(dev)) {
+		ret = i915_set_pte_uncached(obj);
+		if (ret)
+			return ret;
+	}
+
 	ret = i915_gem_object_pin(obj, alignment, true);
 	if (ret)
 		return ret;
@@ -4740,6 +4785,12 @@  static int intel_crtc_cursor_set(struct drm_crtc *crtc,
 			goto fail_locked;
 		}
 
+		if (IS_GEN6(dev)) {
+			ret = i915_set_pte_uncached(obj);
+			if (ret)
+				goto fail_locked;
+		}
+
 		ret = i915_gem_object_pin(obj, PAGE_SIZE, true);
 		if (ret) {
 			DRM_ERROR("failed to pin cursor bo\n");