drm/i915/display/psr: Lock and unlock PSR around pipe updates

Frontbuffer rendering and page flips can race with each other
and this can potentialy cause issues with PSR2 selective fetch.

And because pipe/crtc updates are time sentive we can't grab the
PSR lock after intel_pipe_update_start() and before
intel_pipe_update_end().

So here adding the lock and unlock functions and calls, the
proper PSR2 selective fetch handling will come in a separated patch.

v2:
- fixed new functions documentation
Reviewed-by: default avatarJouni Högander <jouni.hogander@intel.com>
Cc: Jouni Högander <jouni.hogander@intel.com>
Cc: Mika Kahola <mika.kahola@intel.com>
Signed-off-by: default avatarJosé Roberto de Souza <jose.souza@intel.com>
Link: https://patchwork.freedesktop.org/patch/msgid/20220405155344.47219-2-jose.souza@intel.com
parent aa94bf30
...@@ -507,6 +507,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) ...@@ -507,6 +507,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state)
VBLANK_EVASION_TIME_US); VBLANK_EVASION_TIME_US);
max = vblank_start - 1; max = vblank_start - 1;
intel_psr_lock(new_crtc_state);
if (min <= 0 || max <= 0) if (min <= 0 || max <= 0)
goto irq_disable; goto irq_disable;
...@@ -518,7 +520,7 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state) ...@@ -518,7 +520,7 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state)
* VBL interrupts will start the PSR exit and prevent a PSR * VBL interrupts will start the PSR exit and prevent a PSR
* re-entry as well. * re-entry as well.
*/ */
intel_psr_wait_for_idle(new_crtc_state); intel_psr_wait_for_idle_locked(new_crtc_state);
local_irq_disable(); local_irq_disable();
...@@ -683,6 +685,8 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state) ...@@ -683,6 +685,8 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)
local_irq_enable(); local_irq_enable();
intel_psr_unlock(new_crtc_state);
if (intel_vgpu_active(dev_priv)) if (intel_vgpu_active(dev_priv))
return; return;
......
...@@ -1548,10 +1548,19 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane, ...@@ -1548,10 +1548,19 @@ void intel_psr2_program_plane_sel_fetch(struct intel_plane *plane,
void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state) void intel_psr2_program_trans_man_trk_ctl(const struct intel_crtc_state *crtc_state)
{ {
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev); struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder;
if (!crtc_state->enable_psr2_sel_fetch) if (!crtc_state->enable_psr2_sel_fetch)
return; return;
for_each_intel_encoder_mask_with_psr(&dev_priv->drm, encoder,
crtc_state->uapi.encoder_mask) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
lockdep_assert_held(&intel_dp->psr.lock);
break;
}
intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder), intel_de_write(dev_priv, PSR2_MAN_TRK_CTL(crtc_state->cpu_transcoder),
crtc_state->psr2_man_track_ctl); crtc_state->psr2_man_track_ctl);
} }
...@@ -1919,13 +1928,13 @@ static int _psr1_ready_for_pipe_update_locked(struct intel_dp *intel_dp) ...@@ -1919,13 +1928,13 @@ static int _psr1_ready_for_pipe_update_locked(struct intel_dp *intel_dp)
} }
/** /**
* intel_psr_wait_for_idle - wait for PSR be ready for a pipe update * intel_psr_wait_for_idle_locked - wait for PSR be ready for a pipe update
* @new_crtc_state: new CRTC state * @new_crtc_state: new CRTC state
* *
* This function is expected to be called from pipe_update_start() where it is * This function is expected to be called from pipe_update_start() where it is
* not expected to race with PSR enable or disable. * not expected to race with PSR enable or disable.
*/ */
void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_state)
{ {
struct drm_i915_private *dev_priv = to_i915(new_crtc_state->uapi.crtc->dev); struct drm_i915_private *dev_priv = to_i915(new_crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder; struct intel_encoder *encoder;
...@@ -1938,12 +1947,10 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) ...@@ -1938,12 +1947,10 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state)
struct intel_dp *intel_dp = enc_to_intel_dp(encoder); struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
int ret; int ret;
mutex_lock(&intel_dp->psr.lock); lockdep_assert_held(&intel_dp->psr.lock);
if (!intel_dp->psr.enabled) { if (!intel_dp->psr.enabled)
mutex_unlock(&intel_dp->psr.lock);
continue; continue;
}
if (intel_dp->psr.psr2_enabled) if (intel_dp->psr.psr2_enabled)
ret = _psr2_ready_for_pipe_update_locked(intel_dp); ret = _psr2_ready_for_pipe_update_locked(intel_dp);
...@@ -1952,8 +1959,6 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state) ...@@ -1952,8 +1959,6 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state)
if (ret) if (ret)
drm_err(&dev_priv->drm, "PSR wait timed out, atomic update may fail\n"); drm_err(&dev_priv->drm, "PSR wait timed out, atomic update may fail\n");
mutex_unlock(&intel_dp->psr.lock);
} }
} }
...@@ -2444,3 +2449,51 @@ bool intel_psr_enabled(struct intel_dp *intel_dp) ...@@ -2444,3 +2449,51 @@ bool intel_psr_enabled(struct intel_dp *intel_dp)
return ret; return ret;
} }
/**
* intel_psr_lock - grab PSR lock
* @crtc_state: the crtc state
*
* This is initially meant to be used by around CRTC update, when
* vblank sensitive registers are updated and we need grab the lock
* before it to avoid vblank evasion.
*/
void intel_psr_lock(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder;
if (!crtc_state->has_psr)
return;
for_each_intel_encoder_mask_with_psr(&i915->drm, encoder,
crtc_state->uapi.encoder_mask) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
mutex_lock(&intel_dp->psr.lock);
break;
}
}
/**
* intel_psr_unlock - release PSR lock
* @crtc_state: the crtc state
*
* Release the PSR lock that was held during pipe update.
*/
void intel_psr_unlock(const struct intel_crtc_state *crtc_state)
{
struct drm_i915_private *i915 = to_i915(crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder;
if (!crtc_state->has_psr)
return;
for_each_intel_encoder_mask_with_psr(&i915->drm, encoder,
crtc_state->uapi.encoder_mask) {
struct intel_dp *intel_dp = enc_to_intel_dp(encoder);
mutex_unlock(&intel_dp->psr.lock);
break;
}
}
...@@ -41,7 +41,7 @@ void intel_psr_get_config(struct intel_encoder *encoder, ...@@ -41,7 +41,7 @@ void intel_psr_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config); struct intel_crtc_state *pipe_config);
void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir); void intel_psr_irq_handler(struct intel_dp *intel_dp, u32 psr_iir);
void intel_psr_short_pulse(struct intel_dp *intel_dp); void intel_psr_short_pulse(struct intel_dp *intel_dp);
void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state); void intel_psr_wait_for_idle_locked(const struct intel_crtc_state *new_crtc_state);
bool intel_psr_enabled(struct intel_dp *intel_dp); bool intel_psr_enabled(struct intel_dp *intel_dp);
int intel_psr2_sel_fetch_update(struct intel_atomic_state *state, int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct intel_crtc *crtc); struct intel_crtc *crtc);
...@@ -55,4 +55,7 @@ void intel_psr2_disable_plane_sel_fetch(struct intel_plane *plane, ...@@ -55,4 +55,7 @@ void intel_psr2_disable_plane_sel_fetch(struct intel_plane *plane,
void intel_psr_pause(struct intel_dp *intel_dp); void intel_psr_pause(struct intel_dp *intel_dp);
void intel_psr_resume(struct intel_dp *intel_dp); void intel_psr_resume(struct intel_dp *intel_dp);
void intel_psr_lock(const struct intel_crtc_state *crtc_state);
void intel_psr_unlock(const struct intel_crtc_state *crtc_state);
#endif /* __INTEL_PSR_H__ */ #endif /* __INTEL_PSR_H__ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment