[PATCH 2/2] drm/i915: repin bound framebuffers on resume

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



During suspend 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 when the buffer is unbound after
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 visible 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 repin the fences for all bound fbs on resume, which
ensures the pin count is right.

Signed-off-by: St?phane Marchesin <marcheu at chromium.org>
---
 drivers/gpu/drm/i915/i915_drv.c      |  2 ++
 drivers/gpu/drm/i915/intel_display.c | 32 ++++++++++++++++++++++++++++++++
 drivers/gpu/drm/i915/intel_drv.h     |  1 +
 3 files changed, 35 insertions(+)

diff --git a/drivers/gpu/drm/i915/i915_drv.c b/drivers/gpu/drm/i915/i915_drv.c
index a2e4953..b8e82ab 100644
--- a/drivers/gpu/drm/i915/i915_drv.c
+++ b/drivers/gpu/drm/i915/i915_drv.c
@@ -643,6 +643,8 @@ static int __i915_drm_thaw(struct drm_device *dev)
 		/* We need working interrupts for modeset enabling ... */
 		drm_irq_install(dev);
 
+		/* Repin all live fences before resuming */
+		intel_repin_fences(dev);
 		intel_modeset_init_hw(dev);
 
 		drm_modeset_lock_all(dev);
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index 56746dc..4bf3240 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -2051,6 +2051,38 @@ void intel_unpin_fb_obj(struct drm_i915_gem_object *obj)
 	i915_gem_object_unpin(obj);
 }
 
+/*
+ * Repin the fences for all currently bound fbs. During suspend i915_drm_freeze
+ * calls i915_gem_reset, which in turn calls i915_gem_reset_fences, which
+ * resets the fence pin_counts to 0. So on resume we can call this function to
+ * restore the fences on bound framebuffers.
+ */
+void intel_repin_fences(struct drm_device *dev)
+{
+	struct drm_crtc *crtc;
+	struct drm_i915_gem_object *obj;
+	int ret;
+
+	mutex_lock(&mode_config->mutex);
+	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;
+
+		/* Install a fence for tiled scan-out. */
+		if (obj->tiling_mode != I915_TILING_NONE) {
+			ret = i915_gem_object_get_fence(obj);
+			if (ret)
+				DRM_ERROR("Couldn't get a fence\n");
+			else
+				i915_gem_object_pin_fence(obj);
+		}
+	}
+	mutex_unlock(&mode_config->mutex);
+}
+
 /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel
  * is assumed to be a power-of-two. */
 unsigned long intel_gen4_compute_page_offset(int *x, int *y,
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 624a9e6..b5395ed 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -630,6 +630,7 @@ extern int intel_pin_and_fence_fb_obj(struct drm_device *dev,
 				      struct drm_i915_gem_object *obj,
 				      struct intel_ring_buffer *pipelined);
 extern void intel_unpin_fb_obj(struct drm_i915_gem_object *obj);
+extern void intel_repin_fences(struct drm_device *dev);
 
 extern int intel_framebuffer_init(struct drm_device *dev,
 				  struct intel_framebuffer *ifb,
-- 
1.8.3



[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]
  Powered by Linux