Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit fb0adea1 authored by Veera Sundaram Sankaran's avatar Veera Sundaram Sankaran Committed by Gerrit - the friendly Code Review server
Browse files

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: default avatarVeera Sundaram Sankaran <veeras@codeaurora.org>
Signed-off-by: default avatarDhaval Patel <pdhaval@codeaurora.org>
Signed-off-by: default avatarBruce Hoo <bingchua@codeaurora.org>
Signed-off-by: default avatarRay Zhang <rayz@codeaurora.org>
parent 3b888b44
Loading
Loading
Loading
Loading
+2 −2
Original line number Diff line number Diff line
@@ -3455,6 +3455,7 @@ static void sde_encoder_virt_disable(struct drm_encoder *drm_enc)
			sde_enc->phys_encs[i]->cont_splash_single_flush = 0;
			sde_enc->phys_encs[i]->connector = NULL;
		}
		atomic_set(&sde_enc->frame_done_cnt[i], 0);
	}

	sde_enc->cur_master = NULL;
@@ -3680,8 +3681,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]));
+2 −1
Original line number Diff line number Diff line
@@ -379,12 +379,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;
@@ -393,6 +393,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 −28
Original line number Diff line number Diff line
@@ -481,20 +481,18 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
	conn = phys_enc->connector;
	sde_conn = to_sde_connector(conn);

	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) ||
	    sde_conn->panel_dead)
@@ -672,13 +670,28 @@ 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;
@@ -692,8 +705,6 @@ 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,
				recovery_events);
	} else if (!ret) {
@@ -1386,20 +1397,10 @@ 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) &&
	  atomic_read(&phys_enc->pending_kickoff_cnt) &&
	  ctl->ops.get_scheduler_status &&
	  (ctl->ops.get_scheduler_status(ctl) & BIT(0)) &&
	  phys_enc->parent_ops.handle_frame_done) {
		atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);

		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;
}

@@ -1427,7 +1428,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)
@@ -1440,11 +1441,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) ||
@@ -1453,14 +1454,16 @@ static int sde_encoder_phys_cmd_wait_for_commit_done(
		goto wait_for_idle;

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)