[Intel-gfx] [RFC] drm/i915: Rework "Potential atomic update error" to handle PSR exit

tarun.vyas at intel.com tarun.vyas at intel.com
Thu Apr 26 02:10:09 UTC 2018


From: Tarun <tarun.vyas at intel.com>

The Display scanline counter freezes on PSR entry. Inside
intel_pipe_update_start, once Vblank interrupts are enabled, we start
exiting PSR, but by the time the scanline counter is read, we may not
have completely exited PSR which leads us to schedule out and check back
later.
On ChromeOS-4.4 kernel, which is fairly up-to-date w.r.t drm/i915 but
lags w.r.t core kernel code, hot plugging an external display triggers
tons of "potential atomic update errors" in the dmesg, on *pipe A*. A
closer analysis reveals that we try to read the scanline 3 times and
eventually timeout, b/c PSR hasn't exited fully leading to a PIPEDSL stuck @
1599.
This issue is not seen on upstream kernels, b/c for *some* reason we
loop inside intel_pipe_update start for ~2+ msec which in this case is
more than enough to exit PSR fully, hence an *unstuck* PIPEDSL counter,
hence no error. On the other hand, the ChromeOS kernel spends ~1.1 msec
looping inside intel_pipe_update_start and hence errors out b/c the
source is still in PSR.

If PSR is enabled, then we should *wait* for  the PSR
state to move to IDLE before re-reading the PIPEDSL so as to avoid bogus
and annoying "potential atomic update error" messages.

P.S: This scenario applies to a configuration with an additional pipe,
as of now.

Signed-off-by: Tarun <tarun.vyas at intel.com>
---
 drivers/gpu/drm/i915/intel_sprite.c | 19 +++++++++++++++----
 1 file changed, 15 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_sprite.c b/drivers/gpu/drm/i915/intel_sprite.c
index aa1dfaa692b9..77dd3b936131 100644
--- a/drivers/gpu/drm/i915/intel_sprite.c
+++ b/drivers/gpu/drm/i915/intel_sprite.c
@@ -92,11 +92,13 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
 	struct drm_i915_private *dev_priv = to_i915(crtc->base.dev);
 	const struct drm_display_mode *adjusted_mode = &new_crtc_state->base.adjusted_mode;
 	long timeout = msecs_to_jiffies_timeout(1);
-	int scanline, min, max, vblank_start;
+	int scanline, min, max, vblank_start, old_scanline, new_scanline;
+	bool retried = false;
 	wait_queue_head_t *wq = drm_crtc_vblank_waitqueue(&crtc->base);
 	bool need_vlv_dsi_wa = (IS_VALLEYVIEW(dev_priv) || IS_CHERRYVIEW(dev_priv)) &&
 		intel_crtc_has_type(new_crtc_state, INTEL_OUTPUT_DSI);
 	DEFINE_WAIT(wait);
+	old_scanline = new_scanline = -1;
 
 	vblank_start = adjusted_mode->crtc_vblank_start;
 	if (adjusted_mode->flags & DRM_MODE_FLAG_INTERLACE)
@@ -126,15 +128,24 @@ void intel_pipe_update_start(const struct intel_crtc_state *new_crtc_state)
 		 * read the scanline.
 		 */
 		prepare_to_wait(wq, &wait, TASK_UNINTERRUPTIBLE);
-
+retry:
 		scanline = intel_get_crtc_scanline(crtc);
+		old_scanline = new_scanline, new_scanline = scanline;
+
 		if (scanline < min || scanline > max)
 			break;
 
 		if (timeout <= 0) {
-			DRM_ERROR("Potential atomic update failure on pipe %c\n",
+			if(!i915.enable_psr || retried) {
+				DRM_ERROR("Potential atomic update failure on pipe %c\n",
 				  pipe_name(crtc->pipe));
-			break;
+				break;
+			}
+			else if(old_scanline == new_scanline && !retried) {
+				retried = true;
+				intel_wait_for_register(dev_priv, EDP_PSR_STATUS_CTL, EDP_PSR_STATUS_STATE_MASK, EDP_PSR_STATUS_STATE_IDLE, 10);
+				goto retry;
+			}
 		}
 
 		local_irq_enable();
-- 
2.13.5



More information about the Intel-gfx mailing list