[PATCH 5/5] drm/i915: Allow vblank interrupts during modeset and eliminate some vblank races

ville.syrjala at linux.intel.com ville.syrjala at linux.intel.com
Fri Feb 21 11:03:35 PST 2014


From: Ville Syrjälä <ville.syrjala at linux.intel.com>

Tell the drm core vblank code to reject drm_vblank_get()s only between
drm_vblank_off() and drm_vblank_on() calls, and sprinkle the appropriate
drm_vblank_on() calls to the .crtc_enable() hooks. At this time I kept
the off calls in their current position, and added the on calls to the
end of .crtc_enable(). Later on these will be moved inwards a bit to
allow vblank interrupts during plane enable/disable steps.

We can kill of the drm_vblank_{pre,post}_modeset() calls since those are
there simply to make drm_vblank_get() fail during a modeset. The way
they do it is by grabbing a vblank reference, and after drm_vblank_off()
gets called this will results in drm_vblank_get() failing due to the
elevated refcount while vblank interrupts are disabled. Unfortunately
this means there's no point during modeset where the behaviour can be
restored back to the normal state until the vblank refcount drops to 0.
There's no gurantee of that happening even after the modeset has
completed, so simply dropping the drm_vblank_{pre,post}_modeset() calls
is the best option. The new reject mechanism will take care of things
in a much more consistent and race free manner.

Testcase: igt/kms_flip/{dpms,modeset}-vs-vblank-race
Signed-off-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
---
 drivers/gpu/drm/i915/i915_dma.c      |  6 ++++++
 drivers/gpu/drm/i915/intel_display.c | 23 +++++++++++++++--------
 2 files changed, 21 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/i915/i915_dma.c b/drivers/gpu/drm/i915/i915_dma.c
index 7688abc..d5e27bb 100644
--- a/drivers/gpu/drm/i915/i915_dma.c
+++ b/drivers/gpu/drm/i915/i915_dma.c
@@ -1293,6 +1293,12 @@ static int i915_load_modeset_init(struct drm_device *dev)
 	struct drm_i915_private *dev_priv = dev->dev_private;
 	int ret;
 
+	/*
+	 * Allow the use of vblank interrupts during modeset,
+	 * and make the vblank code behaviour more consistent
+	 */
+	dev->vblank_always_enable_on_get = true;
+
 	ret = intel_parse_bios(dev);
 	if (ret)
 		DRM_INFO("failed to find VBIOS tables\n");
diff --git a/drivers/gpu/drm/i915/intel_display.c b/drivers/gpu/drm/i915/intel_display.c
index bab0d08..2933540 100644
--- a/drivers/gpu/drm/i915/intel_display.c
+++ b/drivers/gpu/drm/i915/intel_display.c
@@ -3607,6 +3607,8 @@ static void ironlake_crtc_enable(struct drm_crtc *crtc)
 	 * happening.
 	 */
 	intel_wait_for_vblank(dev, intel_crtc->pipe);
+
+	drm_vblank_on(dev, pipe);
 }
 
 /* IPS only exists on ULT machines and is tied to pipe A. */
@@ -3632,6 +3634,8 @@ static void haswell_crtc_enable_planes(struct drm_crtc *crtc)
 	mutex_lock(&dev->struct_mutex);
 	intel_update_fbc(dev);
 	mutex_unlock(&dev->struct_mutex);
+
+	drm_vblank_on(dev, pipe);
 }
 
 static void haswell_crtc_disable_planes(struct drm_crtc *crtc)
@@ -3643,7 +3647,7 @@ static void haswell_crtc_disable_planes(struct drm_crtc *crtc)
 	int plane = intel_crtc->plane;
 
 	intel_crtc_wait_for_pending_flips(crtc);
-	drm_vblank_off(dev, pipe, false);
+	drm_vblank_off(dev, pipe, true);
 
 	/* FBC must be disabled before disabling the plane on HSW. */
 	if (dev_priv->fbc.plane == plane)
@@ -3774,7 +3778,7 @@ static void ironlake_crtc_disable(struct drm_crtc *crtc)
 		encoder->disable(encoder);
 
 	intel_crtc_wait_for_pending_flips(crtc);
-	drm_vblank_off(dev, pipe, false);
+	drm_vblank_off(dev, pipe, true);
 
 	if (dev_priv->fbc.plane == plane)
 		intel_disable_fbc(dev);
@@ -4160,6 +4164,8 @@ static void valleyview_crtc_enable(struct drm_crtc *crtc)
 
 	for_each_encoder_on_crtc(dev, crtc, encoder)
 		encoder->enable(encoder);
+
+	drm_vblank_on(dev, pipe);
 }
 
 static void i9xx_crtc_enable(struct drm_crtc *crtc)
@@ -4205,6 +4211,8 @@ static void i9xx_crtc_enable(struct drm_crtc *crtc)
 
 	for_each_encoder_on_crtc(dev, crtc, encoder)
 		encoder->enable(encoder);
+
+	drm_vblank_on(dev, pipe);
 }
 
 static void i9xx_pfit_disable(struct intel_crtc *crtc)
@@ -4239,7 +4247,7 @@ static void i9xx_crtc_disable(struct drm_crtc *crtc)
 
 	/* Give the overlay scaler a chance to disable if it's on this pipe */
 	intel_crtc_wait_for_pending_flips(crtc);
-	drm_vblank_off(dev, pipe, false);
+	drm_vblank_off(dev, pipe, true);
 
 	if (dev_priv->fbc.plane == plane)
 		intel_disable_fbc(dev);
@@ -7035,15 +7043,10 @@ static int intel_crtc_mode_set(struct drm_crtc *crtc,
 	struct intel_encoder *encoder;
 	struct intel_crtc *intel_crtc = to_intel_crtc(crtc);
 	struct drm_display_mode *mode = &intel_crtc->config.requested_mode;
-	int pipe = intel_crtc->pipe;
 	int ret;
 
-	drm_vblank_pre_modeset(dev, pipe);
-
 	ret = dev_priv->display.crtc_mode_set(crtc, x, y, fb);
 
-	drm_vblank_post_modeset(dev, pipe);
-
 	if (ret != 0)
 		return ret;
 
@@ -11380,6 +11383,10 @@ void intel_modeset_setup_hw_state(struct drm_device *dev,
 		crtc = to_intel_crtc(dev_priv->pipe_to_crtc_mapping[pipe]);
 		intel_sanitize_crtc(crtc);
 		intel_dump_pipe_config(crtc, &crtc->config, "[setup_hw_state]");
+		if (crtc->active)
+			drm_vblank_on(dev, crtc->pipe);
+		else
+			drm_vblank_off(dev, crtc->pipe, true);
 	}
 
 	for (i = 0; i < dev_priv->num_shared_dpll; i++) {
-- 
1.8.3.2



More information about the dri-devel mailing list