Преглед изворни кода

disp: msm: sde: fix release fence signaling in error cases

Handle release fence/frame-done error signalling for
error case like esd failure, pp_done timeout, interrupt
disable on cpu, etc. It fixes the race condition for
pending_frame count update and also triggers correct
wait function for wr_ptr wait failure.

Change-Id: Iad08f20592c97221a1626bb40e607c398a9812b6
Signed-off-by: Veera Sundaram Sankaran <[email protected]>
Signed-off-by: Dhaval Patel <[email protected]>
Veera Sundaram Sankaran пре 6 година
родитељ
комит
5a2dfc1e83
3 измењених фајлова са 35 додато и 30 уклоњено
  1. 2 2
      msm/sde/sde_encoder.c
  2. 2 1
      msm/sde/sde_encoder_phys.h
  3. 31 27
      msm/sde/sde_encoder_phys_cmd.c

+ 2 - 2
msm/sde/sde_encoder.c

@@ -3362,6 +3362,7 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
 			sde_enc->phys_encs[i]->cont_splash_enabled = false;
 			sde_enc->phys_encs[i]->connector = NULL;
 		}
+		atomic_set(&sde_enc->frame_done_cnt[i], 0);
 	}
 
 	sde_enc->cur_master = NULL;
@@ -3647,8 +3648,7 @@ static void sde_encoder_frame_done_callback(
 
 		/* One of the physical encoders has become idle */
 		for (i = 0; i < sde_enc->num_phys_encs; i++) {
-			if ((sde_enc->phys_encs[i] == ready_phys) ||
-			     (event & SDE_ENCODER_FRAME_EVENT_ERROR)) {
+			if (sde_enc->phys_encs[i] == ready_phys) {
 				SDE_EVT32_VERBOSE(DRMID(drm_enc), i,
 				     atomic_read(&sde_enc->frame_done_cnt[i]));
 				if (!atomic_add_unless(

+ 2 - 1
msm/sde/sde_encoder_phys.h

@@ -365,12 +365,12 @@ struct sde_encoder_phys_cmd_autorefresh {
  * struct sde_encoder_phys_cmd - sub-class of sde_encoder_phys to handle command
  *	mode specific operations
  * @base:	Baseclass physical encoder structure
- * @intf_idx:	Intf Block index used by this phys encoder
  * @stream_sel:	Stream selection for multi-stream interfaces
  * @pp_timeout_report_cnt: number of pingpong done irq timeout errors
  * @autorefresh: autorefresh feature state
  * @pending_vblank_cnt: Atomic counter tracking pending wait for VBLANK
  * @pending_vblank_wq: Wait queue for blocking until VBLANK received
+ * @wr_ptr_wait_success: log wr_ptr_wait success for release fence trigger
  */
 struct sde_encoder_phys_cmd {
 	struct sde_encoder_phys base;
@@ -379,6 +379,7 @@ struct sde_encoder_phys_cmd {
 	struct sde_encoder_phys_cmd_autorefresh autorefresh;
 	atomic_t pending_vblank_cnt;
 	wait_queue_head_t pending_vblank_wq;
+	bool wr_ptr_wait_success;
 };
 
 /**

+ 31 - 27
msm/sde/sde_encoder_phys_cmd.c

@@ -461,20 +461,18 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
 
 	conn = phys_enc->connector;
 
-	if (atomic_read(&phys_enc->pending_kickoff_cnt) == 0)
+	/* decrement the kickoff_cnt before checking for ESD status */
+	if (!atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0))
 		return 0;
 
 	cmd_enc->pp_timeout_report_cnt++;
-	pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);
+	pending_kickoff_cnt = atomic_read(&phys_enc->pending_kickoff_cnt) + 1;
 
 	SDE_EVT32(DRMID(phys_enc->parent), phys_enc->hw_pp->idx - PINGPONG_0,
 			cmd_enc->pp_timeout_report_cnt,
 			pending_kickoff_cnt,
 			frame_event);
 
-	/* decrement the kickoff_cnt before checking for ESD status */
-	atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
-
 	/* check if panel is still sending TE signal or not */
 	if (sde_connector_esd_status(phys_enc->connector))
 		goto exit;
@@ -651,13 +649,29 @@ static int _sde_encoder_phys_cmd_wait_for_idle(
 			to_sde_encoder_phys_cmd(phys_enc);
 	struct sde_encoder_wait_info wait_info;
 	bool recovery_events;
-	int ret, i, pending_cnt;
+	int ret;
+	struct sde_hw_ctl *ctl;
 
 	if (!phys_enc) {
 		SDE_ERROR("invalid encoder\n");
 		return -EINVAL;
 	}
 
+	ctl = phys_enc->hw_ctl;
+	if (cmd_enc->wr_ptr_wait_success &&
+	    (phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START) &&
+	    ctl->ops.get_scheduler_status &&
+	    (ctl->ops.get_scheduler_status(ctl) & BIT(0)) &&
+	    atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0) &&
+	    phys_enc->parent_ops.handle_frame_done) {
+
+		phys_enc->parent_ops.handle_frame_done(
+			phys_enc->parent, phys_enc,
+			SDE_ENCODER_FRAME_EVENT_DONE |
+			SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE);
+		return 0;
+	}
+
 	wait_info.wq = &phys_enc->pending_kickoff_wq;
 	wait_info.atomic_cnt = &phys_enc->pending_kickoff_cnt;
 	wait_info.timeout_ms = KICKOFF_TIMEOUT_MS;
@@ -671,9 +685,7 @@ static int _sde_encoder_phys_cmd_wait_for_idle(
 	ret = sde_encoder_helper_wait_for_irq(phys_enc, INTR_IDX_PINGPONG,
 			&wait_info);
 	if (ret == -ETIMEDOUT) {
-		pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);
-		for (i = 0; i < pending_cnt; i++)
-			_sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc,
+		_sde_encoder_phys_cmd_handle_ppdone_timeout(phys_enc,
 				recovery_events);
 	} else if (!ret) {
 		if (cmd_enc->pp_timeout_report_cnt && recovery_events) {
@@ -1368,19 +1380,9 @@ static int _sde_encoder_phys_cmd_wait_for_wr_ptr(
 			phys_enc->parent_ops.handle_frame_done(
 				phys_enc->parent, phys_enc,
 				SDE_ENCODER_FRAME_EVENT_SIGNAL_RETIRE_FENCE);
-
-	} else if ((ret == 0) &&
-		(phys_enc->frame_trigger_mode == FRAME_DONE_WAIT_POSTED_START)
-		  && ctl->ops.get_scheduler_status
-		  && (ctl->ops.get_scheduler_status(ctl) & BIT(0))
-		  && atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0)
-		  && phys_enc->parent_ops.handle_frame_done) {
-		phys_enc->parent_ops.handle_frame_done(
-			phys_enc->parent, phys_enc,
-			SDE_ENCODER_FRAME_EVENT_DONE |
-			SDE_ENCODER_FRAME_EVENT_SIGNAL_RELEASE_FENCE);
 	}
 
+	cmd_enc->wr_ptr_wait_success = (ret == 0) ? true : false;
 	return ret;
 }
 
@@ -1408,7 +1410,7 @@ static int sde_encoder_phys_cmd_wait_for_tx_complete(
 static int sde_encoder_phys_cmd_wait_for_commit_done(
 		struct sde_encoder_phys *phys_enc)
 {
-	int rc = 0;
+	int rc = 0, i, pending_cnt;
 	struct sde_encoder_phys_cmd *cmd_enc;
 
 	if (!phys_enc)
@@ -1421,11 +1423,11 @@ static int sde_encoder_phys_cmd_wait_for_commit_done(
 		rc = _sde_encoder_phys_cmd_wait_for_wr_ptr(phys_enc);
 		if (rc == -ETIMEDOUT)
 			goto wait_for_idle;
-	}
 
-	if (!rc && sde_encoder_phys_cmd_is_master(phys_enc) &&
-			cmd_enc->autorefresh.cfg.enable)
-		rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(phys_enc);
+		if (cmd_enc->autorefresh.cfg.enable)
+			rc = _sde_encoder_phys_cmd_wait_for_autorefresh_done(
+								phys_enc);
+	}
 
 	/* wait for posted start or serialize trigger */
 	if ((atomic_read(&phys_enc->pending_kickoff_cnt) > 1) ||
@@ -1435,14 +1437,16 @@ static int sde_encoder_phys_cmd_wait_for_commit_done(
 	return rc;
 
 wait_for_idle:
-	rc = _sde_encoder_phys_cmd_wait_for_idle(phys_enc);
+	pending_cnt = atomic_read(&phys_enc->pending_kickoff_cnt);
+	for (i = 0; i < pending_cnt; i++)
+		rc |= sde_encoder_wait_for_event(phys_enc->parent,
+				MSM_ENC_TX_COMPLETE);
 	if (rc) {
 		SDE_EVT32(DRMID(phys_enc->parent),
 			phys_enc->hw_pp->idx - PINGPONG_0,
 			phys_enc->frame_trigger_mode,
 			atomic_read(&phys_enc->pending_kickoff_cnt),
 			phys_enc->enable_state, rc);
-		atomic_set(&phys_enc->pending_kickoff_cnt, 0);
 		SDE_ERROR("pp:%d failed wait_for_idle: %d\n",
 				phys_enc->hw_pp->idx - PINGPONG_0, rc);
 		if (phys_enc->enable_state == SDE_ENC_ERR_NEEDS_HW_RESET)