Browse Source

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 <[email protected]>
Steve Cohen 4 years ago
parent
commit
31dd25c623
1 changed files with 11 additions and 9 deletions
  1. 11 9
      msm/sde/sde_crtc.c

+ 11 - 9
msm/sde/sde_crtc.c

@@ -3850,8 +3850,10 @@ static int _sde_crtc_vblank_enable_no_lock(
 		if (ret < 0)
 		if (ret < 0)
 			return ret;
 			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_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable,
 					sde_crtc->enabled);
 					sde_crtc->enabled);
 
 
@@ -3859,8 +3861,10 @@ static int _sde_crtc_vblank_enable_no_lock(
 					sde_crtc_vblank_cb, (void *)crtc);
 					sde_crtc_vblank_cb, (void *)crtc);
 		}
 		}
 	} else {
 	} 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_EVT32(DRMID(&sde_crtc->base), DRMID(enc), enable,
 					sde_crtc->enabled);
 					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,
 	msm_mode_object_event_notify(&crtc->base, crtc->dev, &event,
 			(u8 *)&power_on);
 			(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->static_cache_read_work);
 	kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work);
 	kthread_cancel_delayed_work_sync(&sde_crtc->idle_notify_work);