While PSR is active hardware will do aux transactions by it self to wakeup sink to receive a new frame when necessary. If that transaction is not acked by sink, hardware will trigger this interruption. So let's disable PSR as it is a hint that there is problem with this sink. The removed FIXME was asking to manually train the link but we don't need to do that as by spec sink should do a short pulse when it is out of sync with source, we just need to make sure it is awaken and the SDP header with PSR disable will trigger this condition. v3: added workarround to fix scheduled work starvation cause by to frequent PSR error interruption Cc: Dhinakaran Pandiyan <dhinakaran.pandiyan@xxxxxxxxx> Signed-off-by: José Roberto de Souza <jose.souza@xxxxxxxxx> --- drivers/gpu/drm/i915/i915_drv.h | 1 + drivers/gpu/drm/i915/intel_psr.c | 53 +++++++++++++++++++++++++++++--- 2 files changed, 50 insertions(+), 4 deletions(-) diff --git a/drivers/gpu/drm/i915/i915_drv.h b/drivers/gpu/drm/i915/i915_drv.h index 2d7761b8ac07..2a2574f34b4a 100644 --- a/drivers/gpu/drm/i915/i915_drv.h +++ b/drivers/gpu/drm/i915/i915_drv.h @@ -638,6 +638,7 @@ struct i915_psr { u8 sink_sync_latency; ktime_t last_entry_attempt; ktime_t last_exit; + u32 irq_aux_error; }; enum intel_pch { diff --git a/drivers/gpu/drm/i915/intel_psr.c b/drivers/gpu/drm/i915/intel_psr.c index 08b5351e4efb..68201cc24d25 100644 --- a/drivers/gpu/drm/i915/intel_psr.c +++ b/drivers/gpu/drm/i915/intel_psr.c @@ -152,6 +152,7 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir) u32 transcoders = BIT(TRANSCODER_EDP); enum transcoder cpu_transcoder; ktime_t time_ns = ktime_get(); + u32 mask = 0; if (INTEL_GEN(dev_priv) >= 8) transcoders |= BIT(TRANSCODER_A) | @@ -159,10 +160,23 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir) BIT(TRANSCODER_C); for_each_cpu_transcoder_masked(dev_priv, cpu_transcoder, transcoders) { - /* FIXME: Exit PSR and link train manually when this happens. */ - if (psr_iir & EDP_PSR_ERROR(cpu_transcoder)) - DRM_DEBUG_KMS("[transcoder %s] PSR aux error\n", - transcoder_name(cpu_transcoder)); + if (psr_iir & EDP_PSR_ERROR(cpu_transcoder)) { + DRM_WARN("[transcoder %s] PSR aux error\n", + transcoder_name(cpu_transcoder)); + + spin_lock(&dev_priv->irq_lock); + dev_priv->psr.irq_aux_error |= BIT(cpu_transcoder); + spin_unlock(&dev_priv->irq_lock); + + /* + * If this interruption is not masked it will keep + * interrupting so fast that it prevents the scheduled + * work to run. + * Also after a PSR error, we don't want to arm PSR + * again so we don't care about unmask the interruption. + */ + mask |= EDP_PSR_ERROR(cpu_transcoder); + } if (psr_iir & EDP_PSR_PRE_ENTRY(cpu_transcoder)) { dev_priv->psr.last_entry_attempt = time_ns; @@ -184,6 +198,13 @@ void intel_psr_irq_handler(struct drm_i915_private *dev_priv, u32 psr_iir) } } } + + if (mask) { + mask |= I915_READ(EDP_PSR_IMR); + I915_WRITE(EDP_PSR_IMR, mask); + + schedule_work(&dev_priv->psr.work); + } } static bool intel_dp_get_colorimetry_status(struct intel_dp *intel_dp) @@ -893,11 +914,35 @@ int intel_psr_set_debugfs_mode(struct drm_i915_private *dev_priv, return ret; } +static void intel_psr_handle_irq(struct drm_i915_private *dev_priv) +{ + struct i915_psr *psr = &dev_priv->psr; + u32 irq_aux_error; + + spin_lock_irq(&dev_priv->irq_lock); + irq_aux_error = psr->irq_aux_error; + psr->irq_aux_error = 0; + spin_unlock_irq(&dev_priv->irq_lock); + + WARN_ON(irq_aux_error & ~BIT(TRANSCODER_EDP)); + + mutex_lock(&psr->lock); + + intel_psr_disable_locked(psr->dp); + /* let's make sure that sink is awaken */ + drm_dp_dpcd_writeb(&psr->dp->aux, DP_SET_POWER, DP_SET_POWER_D0); + + mutex_unlock(&dev_priv->psr.lock); +} + static void intel_psr_work(struct work_struct *work) { struct drm_i915_private *dev_priv = container_of(work, typeof(*dev_priv), psr.work); + if (READ_ONCE(dev_priv->psr.irq_aux_error)) + intel_psr_handle_irq(dev_priv); + mutex_lock(&dev_priv->psr.lock); if (!dev_priv->psr.enabled) -- 2.19.1 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx