@@ -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);
@@ -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");