disp: msm: sde: cache encoder_mask for vblank_work

There is a race between disable commit swap-state on display
thread and vblank work on event thread which may skip applying
the vblank vote if the encoder_mask has already been cleared.
To avoid the race, use a cached encoder_mask that is gauranteed
to be valid between the vblank_on and vblank_off calls.

Also, vblank queue work is initializing a variable that's never
used and msm_disable_outputs has 2 instances of pointers to old
CRTC state. Remove this dead code.

Change-Id: I5e4a482b8f067e272a2aef5afa08cc0e1ab89434
Signed-off-by: Steve Cohen <cohens@codeaurora.org>
Tento commit je obsažen v:
Steve Cohen
2020-11-11 14:37:10 -05:00
rodič 7a98aa2134
revize aa064ada86
4 změnil soubory, kde provedl 23 přidání a 25 odebrání

Zobrazit soubor

@@ -3820,13 +3820,13 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
}
/**
* _sde_crtc_vblank_enable_no_lock - update power resource and vblank request
* _sde_crtc_vblank_enable - update power resource and vblank request
* @sde_crtc: Pointer to sde crtc structure
* @enable: Whether to enable/disable vblanks
*
* @Return: error code
*/
static int _sde_crtc_vblank_enable_no_lock(
static int _sde_crtc_vblank_enable(
struct sde_crtc *sde_crtc, bool enable)
{
struct drm_crtc *crtc;
@@ -3838,38 +3838,38 @@ static int _sde_crtc_vblank_enable_no_lock(
}
crtc = &sde_crtc->base;
SDE_EVT32(DRMID(crtc), enable, sde_crtc->enabled,
crtc->state->encoder_mask,
sde_crtc->cached_encoder_mask);
if (enable) {
int ret;
/* drop lock since power crtc cb may try to re-acquire lock */
mutex_unlock(&sde_crtc->crtc_lock);
ret = pm_runtime_get_sync(crtc->dev->dev);
mutex_lock(&sde_crtc->crtc_lock);
if (ret < 0)
return ret;
mutex_lock(&sde_crtc->crtc_lock);
drm_for_each_encoder_mask(enc, crtc->dev,
crtc->state->encoder_mask) {
SDE_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable,
sde_crtc->enabled);
sde_crtc->cached_encoder_mask) {
SDE_EVT32(DRMID(crtc), DRMID(enc));
sde_encoder_register_vblank_callback(enc,
sde_crtc_vblank_cb, (void *)crtc);
}
mutex_unlock(&sde_crtc->crtc_lock);
} else {
mutex_lock(&sde_crtc->crtc_lock);
drm_for_each_encoder_mask(enc, crtc->dev,
crtc->state->encoder_mask) {
SDE_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable,
sde_crtc->enabled);
sde_crtc->cached_encoder_mask) {
SDE_EVT32(DRMID(crtc), DRMID(enc));
sde_encoder_register_vblank_callback(enc, NULL, NULL);
}
/* drop lock since power crtc cb may try to re-acquire lock */
mutex_unlock(&sde_crtc->crtc_lock);
pm_runtime_put_sync(crtc->dev->dev);
mutex_lock(&sde_crtc->crtc_lock);
}
return 0;
@@ -4165,9 +4165,10 @@ static void sde_crtc_disable(struct drm_crtc *crtc)
kthread_cancel_delayed_work_sync(&sde_crtc->static_cache_read_work);
kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work);
SDE_EVT32(DRMID(crtc), sde_crtc->enabled,
crtc->state->active, crtc->state->enable);
SDE_EVT32(DRMID(crtc), sde_crtc->enabled, crtc->state->active,
crtc->state->enable, sde_crtc->cached_encoder_mask);
sde_crtc->enabled = false;
sde_crtc->cached_encoder_mask = 0;
/* Try to disable uidle */
sde_core_perf_crtc_update_uidle(crtc, false);
@@ -4276,8 +4277,11 @@ static void sde_crtc_enable(struct drm_crtc *crtc,
* Avoid drm_crtc_vblank_on during seamless DMS case
* when CRTC is already in enabled state
*/
if (!sde_crtc->enabled)
if (!sde_crtc->enabled) {
/* cache the encoder mask now for vblank work */
sde_crtc->cached_encoder_mask = crtc->state->encoder_mask;
drm_crtc_vblank_on(crtc);
}
mutex_lock(&sde_crtc->crtc_lock);
SDE_EVT32(DRMID(crtc), sde_crtc->enabled);
@@ -5116,15 +5120,11 @@ int sde_crtc_vblank(struct drm_crtc *crtc, bool en)
}
sde_crtc = to_sde_crtc(crtc);
mutex_lock(&sde_crtc->crtc_lock);
SDE_EVT32(DRMID(&sde_crtc->base), en, sde_crtc->enabled);
ret = _sde_crtc_vblank_enable_no_lock(sde_crtc, en);
ret = _sde_crtc_vblank_enable(sde_crtc, en);
if (ret)
SDE_ERROR("%s vblank enable failed: %d\n",
sde_crtc->name, ret);
mutex_unlock(&sde_crtc->crtc_lock);
return 0;
}