소스 검색

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 년 전
부모
커밋
31dd25c623
1개의 변경된 파일11개의 추가작업 그리고 9개의 파일을 삭제
  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)
 			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);