From 31dd25c623babc9b53d70e028c6499ed4673d227 Mon Sep 17 00:00:00 2001 From: Steve Cohen Date: Fri, 6 Nov 2020 01:15:29 -0500 Subject: [PATCH] disp: msm: sde: fix race between disable commit and vblank work This patch addresses the following sequence: 1. DRM framework drops vblank reference, work is queued on event thread 2. Lastclose stages disable commit, swap-state occurs on display thread 3. vblank worker runs on event thread encoder cannot drop the FW vblank reference since it's no longer in crtc->encoder_mask Instead, iterate through all encoders and match the enc->crtc back-pointer to be sure the vblank vote is applied. Also, flush the event thread in all cases during the CRTC disable to be sure the vblank work is complete before the back-pointer is removed. Change-Id: Ib307e9aefc2d4f729a3af7a6140bc887684f4489 Signed-off-by: Steve Cohen --- msm/sde/sde_crtc.c | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/msm/sde/sde_crtc.c b/msm/sde/sde_crtc.c index f7d531d01c02..44a48041d66a 100644 --- a/msm/sde/sde_crtc.c +++ b/msm/sde/sde_crtc.c @@ -3850,8 +3850,10 @@ static int _sde_crtc_vblank_enable_no_lock( if (ret < 0) return ret; - drm_for_each_encoder_mask(enc, crtc->dev, - crtc->state->encoder_mask) { + drm_for_each_encoder(enc, crtc->dev) { + if (enc->crtc != crtc) + continue; + SDE_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable, sde_crtc->enabled); @@ -3859,8 +3861,10 @@ static int _sde_crtc_vblank_enable_no_lock( sde_crtc_vblank_cb, (void *)crtc); } } else { - drm_for_each_encoder_mask(enc, crtc->dev, - crtc->state->encoder_mask) { + drm_for_each_encoder(enc, crtc->dev) { + if (enc->crtc != crtc) + continue; + SDE_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable, sde_crtc->enabled); @@ -4159,11 +4163,9 @@ static void sde_crtc_disable(struct drm_crtc *crtc) msm_mode_object_event_notify(&crtc->base, crtc->dev, &event, (u8 *)&power_on); - if (atomic_read(&sde_crtc->frame_pending)) { - mutex_unlock(&sde_crtc->crtc_lock); - _sde_crtc_flush_event_thread(crtc); - mutex_lock(&sde_crtc->crtc_lock); - } + mutex_unlock(&sde_crtc->crtc_lock); + _sde_crtc_flush_event_thread(crtc); + mutex_lock(&sde_crtc->crtc_lock); kthread_cancel_delayed_work_sync(&sde_crtc->static_cache_read_work); kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work);