CHROMIUM: drm/i915: repin bound framebuffers on resume
authorStéphane Marchesin <marcheu@chromium.org>
Fri, 12 Apr 2013 00:23:44 +0000 (17:23 -0700)
committerChromeBot <chrome-bot@google.com>
Fri, 12 Apr 2013 04:20:13 +0000 (21:20 -0700)
During suspend/resume all fences are reset, including their pin
count which is reset to 0. However a framebuffer can be bound across
suspend/resume, which means that after the buffer is unbound on
resume, the pin count for the buffer will be negative. Since the
fence pin count is now negative when available and zero when in use,
the buffer's fence will get recycled when the fence is in use which
is the opposite of what we want. The adverse effect is that since the
fence is recycled the tiling mode goes away while the buffer is being
displayed and we get lines/screens of garbage.

To fix this, we reallocate and repin the fences for all bound fbs on
resume, which ensures the pin count is right.

BUG=chromium:219172,chromium:225056
TEST=by hand, suspend/resume on alex, the artifacts are gone

Signed-off-by: Stéphane Marchesin <marcheu@chromium.org>
Change-Id: I9113078b0eb56e671dcca8dc9557a0c0c37f12e0
Reviewed-on: https://gerrit.chromium.org/gerrit/47933

drivers/gpu/drm/i915/i915_drv.c

index f3fde3c..384f109 100644 (file)
@@ -459,6 +459,22 @@ int __gen6_gt_wait_for_fifo(struct drm_i915_private *dev_priv)
        return ret;
 }
 
+/* Repin all fbs which are currently bound to a crtc on resume */
+static void i915_repin_bound_fbs(struct drm_device *dev)
+{
+       struct drm_crtc *crtc;
+       struct drm_i915_gem_object *obj;
+
+       list_for_each_entry(crtc, &dev->mode_config.crtc_list, head) {
+               if (!crtc || !crtc->fb)
+                       continue;
+               obj = to_intel_framebuffer(crtc->fb)->obj;
+               if (!obj)
+                       continue;
+               intel_pin_and_fence_fb_obj(dev, obj, NULL);
+       }
+}
+
 static int i915_drm_freeze(struct drm_device *dev)
 {
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -547,6 +563,7 @@ static int i915_drm_thaw(struct drm_device *dev)
                if (HAS_PCH_SPLIT(dev))
                        ironlake_init_pch_refclk(dev);
 
+               i915_repin_bound_fbs(dev);
                drm_mode_config_reset(dev);
                drm_irq_install(dev);