Skip to content

Commit

Permalink
drm/i915/display/psr: Lock and unlock PSR around pipe updates
Browse files Browse the repository at this point in the history
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.

Cc: Jouni Högander <jouni.hogander@intel.com>
Cc: Mika Kahola <mika.kahola@intel.com>
Signed-off-by: José Roberto de Souza <jose.souza@intel.com>
  • Loading branch information
zehortigoza authored and intel-lab-lkp committed Apr 1, 2022
1 parent 9faf0e5 commit 955b4bf
Show file tree
Hide file tree
Showing 3 changed files with 70 additions and 10 deletions.
6 changes: 5 additions & 1 deletion drivers/gpu/drm/i915/display/intel_crtc.c
Original file line number Diff line number Diff line change
Expand Up @@ -507,6 +507,8 @@ void intel_pipe_update_start(struct intel_crtc_state *new_crtc_state)
VBLANK_EVASION_TIME_US);
max = vblank_start - 1;

intel_psr_lock(new_crtc_state);

if (min <= 0 || max <= 0)
goto irq_disable;

Expand All @@ -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
* re-entry as well.
*/
intel_psr_wait_for_idle(new_crtc_state);
intel_psr_wait_for_idle_locked(new_crtc_state);

local_irq_disable();

Expand Down Expand Up @@ -683,6 +685,8 @@ void intel_pipe_update_end(struct intel_crtc_state *new_crtc_state)

local_irq_enable();

intel_psr_unlock(new_crtc_state);

if (intel_vgpu_active(dev_priv))
return;

Expand Down
69 changes: 61 additions & 8 deletions drivers/gpu/drm/i915/display/intel_psr.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
{
struct drm_i915_private *dev_priv = to_i915(crtc_state->uapi.crtc->dev);
struct intel_encoder *encoder;

if (!crtc_state->enable_psr2_sel_fetch)
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),
crtc_state->psr2_man_track_ctl);
}
Expand Down Expand Up @@ -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
*
* This function is expected to be called from pipe_update_start() where it is
* 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 intel_encoder *encoder;
Expand All @@ -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);
int ret;

mutex_lock(&intel_dp->psr.lock);
lockdep_assert_held(&intel_dp->psr.lock);

if (!intel_dp->psr.enabled) {
mutex_unlock(&intel_dp->psr.lock);
if (!intel_dp->psr.enabled)
continue;
}

if (intel_dp->psr.psr2_enabled)
ret = _psr2_ready_for_pipe_update_locked(intel_dp);
Expand All @@ -1952,8 +1959,6 @@ void intel_psr_wait_for_idle(const struct intel_crtc_state *new_crtc_state)

if (ret)
drm_err(&dev_priv->drm, "PSR wait timed out, atomic update may fail\n");

mutex_unlock(&intel_dp->psr.lock);
}
}

Expand Down Expand Up @@ -2444,3 +2449,51 @@ bool intel_psr_enabled(struct intel_dp *intel_dp)

return ret;
}

/**
* intel_psr_lock - grab psr.lock mutex
* @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_lock - grab psr.lock mutex
* @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;
}
}
5 changes: 4 additions & 1 deletion drivers/gpu/drm/i915/display/intel_psr.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ void intel_psr_get_config(struct intel_encoder *encoder,
struct intel_crtc_state *pipe_config);
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_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);
int intel_psr2_sel_fetch_update(struct intel_atomic_state *state,
struct intel_crtc *crtc);
Expand All @@ -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_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__ */

0 comments on commit 955b4bf

Please sign in to comment.