[PATCH 1/5] drm/i915: Asynchronously unpin the old framebuffer after the next vblank

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

 



Upon completion of a modeset, we must wait for the next vblank before
releasing the old framebufer. (The scanout registers are double-buffered
and update on the next vblank. If we unpin the old scanout too soon we
run the risk of accessing invalid memory, so we first need to wait until
the scanout is reading from the new framebuffer.) As the unpinning is
then deferred, we need to make sure we hold a reference to the object
until we execute the callback.

Signed-off-by: Chris Wilson <chris at chris-wilson.co.uk>
---
 drivers/gpu/drm/i915/intel_display.c | 29 +++++++++++++++++++++++++++--
 1 file changed, 27 insertions(+), 2 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index dff3b93..4b50d5f 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -1921,6 +1921,7 @@ intel_pin_and_fence_fb_obj(struct drm_device *dev,
 		goto err_unpin;
 
 	i915_gem_object_pin_fence(obj);
+	drm_gem_object_reference(&obj->base);
 
 	dev_priv->mm.interruptible = true;
 	return 0;
@@ -1936,6 +1937,7 @@ void intel_unpin_fb_obj(struct drm_i915_gem_object *obj)
 {
 	i915_gem_object_unpin_fence(obj);
 	i915_gem_object_unpin(obj);
+	drm_gem_object_unreference(&obj->base);
 }
 
 /* Computes the linear offset to the base tile and adjusts x, y. bytes per pixel
@@ -2259,6 +2261,26 @@ static void intel_crtc_update_sarea_pos(struct drm_crtc *crtc, int x, int y)
 	}
 }
 
+static void intel_crtc_unpin_work_fn(struct intel_crtc *crtc, void *obj)
+{
+	struct drm_device *dev = crtc->base.dev;
+
+	mutex_lock(&dev->struct_mutex);
+	intel_unpin_fb_obj(obj);
+	mutex_unlock(&dev->struct_mutex);
+}
+
+static void
+intel_crtc_queue_unpin(struct intel_crtc *crtc,
+		       struct drm_i915_gem_object *obj)
+{
+	if (intel_crtc_add_vblank_task(crtc, false,
+				       intel_crtc_unpin_work_fn, obj)) {
+		intel_wait_for_vblank(crtc->base.dev, crtc->pipe);
+		intel_unpin_fb_obj(obj);
+	}
+}
+
 static int
 intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 		    struct drm_framebuffer *fb)
@@ -2321,9 +2343,12 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
 	crtc->y = y;
 
 	if (old_fb) {
+		struct drm_i915_gem_object *old_obj =
+			to_intel_framebuffer(old_fb)->obj;
 		if (intel_crtc->active && old_fb != fb)
-			intel_wait_for_vblank(dev, intel_crtc->pipe);
-		intel_unpin_fb_obj(to_intel_framebuffer(old_fb)->obj);
+			intel_crtc_queue_unpin(intel_crtc, old_obj);
+		else
+			intel_unpin_fb_obj(old_obj);
 	}
 
 	intel_update_fbc(dev);
-- 
1.8.3.2



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