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

Commit f7291b1b authored by Clarence Ip's avatar Clarence Ip Committed by Steve Cohen
Browse files

drm/msm/sde: perform debug dump before h/w recovery



Perform a single debug log and register dump before initiating
the first hardware recovery request in a series of failures,
rather than on each physical encoder as issues are detected.

Change-Id: Icf710679cf24897fe8aec1ab3ff13bdcb2d65e43
Signed-off-by: default avatarClarence Ip <cip@codeaurora.org>
parent ec5302d2
Loading
Loading
Loading
Loading
+25 −6
Original line number Original line Diff line number Diff line
@@ -3396,16 +3396,18 @@ static void _sde_crtc_remove_pipe_flush(struct sde_crtc *sde_crtc)
 * _sde_crtc_reset_hw - attempt hardware reset on errors
 * _sde_crtc_reset_hw - attempt hardware reset on errors
 * @crtc: Pointer to DRM crtc instance
 * @crtc: Pointer to DRM crtc instance
 * @old_state: Pointer to crtc state for previous commit
 * @old_state: Pointer to crtc state for previous commit
 * @dump_status: Whether or not to dump debug status before reset
 * Returns: Zero if current commit should still be attempted
 * Returns: Zero if current commit should still be attempted
 */
 */
static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
		struct drm_crtc_state *old_state)
		struct drm_crtc_state *old_state, bool dump_status)
{
{
	struct drm_plane *plane_halt[MAX_PLANES];
	struct drm_plane *plane_halt[MAX_PLANES];
	struct drm_plane *plane;
	struct drm_plane *plane;
	const struct drm_plane_state *pstate;
	const struct drm_plane_state *pstate;
	struct sde_crtc *sde_crtc;
	struct sde_crtc *sde_crtc;
	struct sde_hw_ctl *ctl;
	struct sde_hw_ctl *ctl;
	enum sde_ctl_rot_op_mode old_rot_op_mode;
	signed int i, plane_count;
	signed int i, plane_count;
	int rc;
	int rc;


@@ -3413,6 +3415,13 @@ static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
		return -EINVAL;
		return -EINVAL;
	sde_crtc = to_sde_crtc(crtc);
	sde_crtc = to_sde_crtc(crtc);


	old_rot_op_mode = to_sde_crtc_state(old_state)->sbuf_cfg.rot_op_mode;
	SDE_EVT32(DRMID(crtc), old_rot_op_mode,
			dump_status, SDE_EVTLOG_FUNC_ENTRY);

	if (dump_status)
		SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus");

	for (i = 0; i < sde_crtc->num_mixers; ++i) {
	for (i = 0; i < sde_crtc->num_mixers; ++i) {
		ctl = sde_crtc->mixers[i].hw_ctl;
		ctl = sde_crtc->mixers[i].hw_ctl;
		if (!ctl || !ctl->ops.reset)
		if (!ctl || !ctl->ops.reset)
@@ -3428,11 +3437,19 @@ static int _sde_crtc_reset_hw(struct drm_crtc *crtc,
		}
		}
	}
	}


	/* early out if simple ctl reset succeeded */
	/*
	if (i == sde_crtc->num_mixers) {
	 * Early out if simple ctl reset succeeded and previous commit
		SDE_EVT32(DRMID(crtc), i);
	 * did not involve the rotator.
	 *
	 * If the previous commit had rotation enabled, then the ctl
	 * reset would also have reset the rotator h/w. The rotator
	 * programming for the current commit may need to be repeated,
	 * depending on the rotation mode; don't handle this for now
	 * and just force a hard reset in those cases.
	 */
	if (i == sde_crtc->num_mixers &&
			old_rot_op_mode == SDE_CTL_ROT_OP_MODE_OFFLINE)
		return false;
		return false;
	}


	SDE_DEBUG("crtc%d: issuing hard reset\n", DRMID(crtc));
	SDE_DEBUG("crtc%d: issuing hard reset\n", DRMID(crtc));


@@ -3605,7 +3622,8 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
	 * preparing for the kickoff
	 * preparing for the kickoff
	 */
	 */
	if (reset_req) {
	if (reset_req) {
		if (_sde_crtc_reset_hw(crtc, old_state))
		if (_sde_crtc_reset_hw(crtc, old_state,
					!sde_crtc->reset_request))
			is_error = true;
			is_error = true;


		/* force offline rotation mode since the commit has no pipes */
		/* force offline rotation mode since the commit has no pipes */
@@ -3613,6 +3631,7 @@ void sde_crtc_commit_kickoff(struct drm_crtc *crtc,
			cstate->sbuf_cfg.rot_op_mode =
			cstate->sbuf_cfg.rot_op_mode =
				SDE_CTL_ROT_OP_MODE_OFFLINE;
				SDE_CTL_ROT_OP_MODE_OFFLINE;
	}
	}
	sde_crtc->reset_request = reset_req;


	/* wait for frame_event_done completion */
	/* wait for frame_event_done completion */
	SDE_ATRACE_BEGIN("wait_for_frame_done_event");
	SDE_ATRACE_BEGIN("wait_for_frame_done_event");
+3 −0
Original line number Original line Diff line number Diff line
@@ -188,6 +188,8 @@ struct sde_crtc_event {
 * @enabled       : whether the SDE CRTC is currently enabled. updated in the
 * @enabled       : whether the SDE CRTC is currently enabled. updated in the
 *                  commit-thread, not state-swap time which is earlier, so
 *                  commit-thread, not state-swap time which is earlier, so
 *                  safe to make decisions on during VBLANK on/off work
 *                  safe to make decisions on during VBLANK on/off work
 * @reset_request : whether or not a h/w request was requested for the previous
 *                  frame
 * @ds_reconfig   : force reconfiguration of the destination scaler block
 * @ds_reconfig   : force reconfiguration of the destination scaler block
 * @feature_list  : list of color processing features supported on a crtc
 * @feature_list  : list of color processing features supported on a crtc
 * @active_list   : list of color processing features are active
 * @active_list   : list of color processing features are active
@@ -247,6 +249,7 @@ struct sde_crtc {
	bool vblank_requested;
	bool vblank_requested;
	bool suspend;
	bool suspend;
	bool enabled;
	bool enabled;
	bool reset_request;


	bool ds_reconfig;
	bool ds_reconfig;
	struct list_head feature_list;
	struct list_head feature_list;
+18 −1
Original line number Original line Diff line number Diff line
@@ -3271,6 +3271,7 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
	struct sde_encoder_virt *sde_enc;
	struct sde_encoder_virt *sde_enc;
	struct sde_encoder_phys *phys;
	struct sde_encoder_phys *phys;
	bool needs_hw_reset = false;
	bool needs_hw_reset = false;
	uint32_t ln_cnt1, ln_cnt2;
	unsigned int i;
	unsigned int i;
	int rc, ret = 0;
	int rc, ret = 0;


@@ -3283,6 +3284,13 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,
	SDE_DEBUG_ENC(sde_enc, "\n");
	SDE_DEBUG_ENC(sde_enc, "\n");
	SDE_EVT32(DRMID(drm_enc));
	SDE_EVT32(DRMID(drm_enc));


	/* save this for later, in case of errors */
	if (sde_enc->cur_master && sde_enc->cur_master->ops.get_wr_line_count)
		ln_cnt1 = sde_enc->cur_master->ops.get_wr_line_count(
				sde_enc->cur_master);
	else
		ln_cnt1 = -EINVAL;

	/* prepare for next kickoff, may include waiting on previous kickoff */
	/* prepare for next kickoff, may include waiting on previous kickoff */
	SDE_ATRACE_BEGIN("enc_prepare_for_kickoff");
	SDE_ATRACE_BEGIN("enc_prepare_for_kickoff");
	for (i = 0; i < sde_enc->num_phys_encs; i++) {
	for (i = 0; i < sde_enc->num_phys_encs; i++) {
@@ -3305,7 +3313,16 @@ int sde_encoder_prepare_for_kickoff(struct drm_encoder *drm_enc,


	/* if any phys needs reset, reset all phys, in-order */
	/* if any phys needs reset, reset all phys, in-order */
	if (needs_hw_reset) {
	if (needs_hw_reset) {
		SDE_EVT32(DRMID(drm_enc), SDE_EVTLOG_FUNC_CASE1);
		/* query line count before cur_master is updated */
		if (sde_enc->cur_master &&
				sde_enc->cur_master->ops.get_wr_line_count)
			ln_cnt2 = sde_enc->cur_master->ops.get_wr_line_count(
					sde_enc->cur_master);
		else
			ln_cnt2 = -EINVAL;

		SDE_EVT32(DRMID(drm_enc), ln_cnt1, ln_cnt2,
				SDE_EVTLOG_FUNC_CASE1);
		for (i = 0; i < sde_enc->num_phys_encs; i++) {
		for (i = 0; i < sde_enc->num_phys_encs; i++) {
			phys = sde_enc->phys_encs[i];
			phys = sde_enc->phys_encs[i];
			if (phys && phys->ops.hw_reset)
			if (phys && phys->ops.hw_reset)
+3 −1
Original line number Original line Diff line number Diff line
@@ -132,7 +132,8 @@ struct sde_encoder_virt_ops {
 * @restore:			Restore all the encoder configs.
 * @restore:			Restore all the encoder configs.
 * @is_autorefresh_enabled:	provides the autorefresh current
 * @is_autorefresh_enabled:	provides the autorefresh current
 *                              enable/disable state.
 *                              enable/disable state.
 * @get_line_count:		Obtain current vertical line count
 * @get_line_count:		Obtain current internal vertical line count
 * @get_wr_line_count:		Obtain current output vertical line count
 * @wait_dma_trigger:		Returns true if lut dma has to trigger and wait
 * @wait_dma_trigger:		Returns true if lut dma has to trigger and wait
 *                              unitl transaction is complete.
 *                              unitl transaction is complete.
 * @wait_for_active:		Wait for display scan line to be in active area
 * @wait_for_active:		Wait for display scan line to be in active area
@@ -182,6 +183,7 @@ struct sde_encoder_phys_ops {
	void (*restore)(struct sde_encoder_phys *phys);
	void (*restore)(struct sde_encoder_phys *phys);
	bool (*is_autorefresh_enabled)(struct sde_encoder_phys *phys);
	bool (*is_autorefresh_enabled)(struct sde_encoder_phys *phys);
	int (*get_line_count)(struct sde_encoder_phys *phys);
	int (*get_line_count)(struct sde_encoder_phys *phys);
	int (*get_wr_line_count)(struct sde_encoder_phys *phys);
	bool (*wait_dma_trigger)(struct sde_encoder_phys *phys);
	bool (*wait_dma_trigger)(struct sde_encoder_phys *phys);
	int (*wait_for_active)(struct sde_encoder_phys *phys);
	int (*wait_for_active)(struct sde_encoder_phys *phys);
};
};
+23 −6
Original line number Original line Diff line number Diff line
@@ -448,9 +448,7 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
		cmd_enc->pp_timeout_report_cnt = PP_TIMEOUT_MAX_TRIALS;
		cmd_enc->pp_timeout_report_cnt = PP_TIMEOUT_MAX_TRIALS;
		frame_event |= SDE_ENCODER_FRAME_EVENT_PANEL_DEAD;
		frame_event |= SDE_ENCODER_FRAME_EVENT_PANEL_DEAD;


		sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_RDPTR);
		SDE_DBG_DUMP("panic");
		SDE_DBG_DUMP("panic");
		sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR);
	} else if (cmd_enc->pp_timeout_report_cnt == 1) {
	} else if (cmd_enc->pp_timeout_report_cnt == 1) {
		/* to avoid flooding, only log first time, and "dead" time */
		/* to avoid flooding, only log first time, and "dead" time */
		SDE_ERROR_CMDENC(cmd_enc,
		SDE_ERROR_CMDENC(cmd_enc,
@@ -461,10 +459,6 @@ static int _sde_encoder_phys_cmd_handle_ppdone_timeout(
				atomic_read(&phys_enc->pending_kickoff_cnt));
				atomic_read(&phys_enc->pending_kickoff_cnt));


		SDE_EVT32(DRMID(phys_enc->parent), SDE_EVTLOG_FATAL);
		SDE_EVT32(DRMID(phys_enc->parent), SDE_EVTLOG_FATAL);

		sde_encoder_helper_unregister_irq(phys_enc, INTR_IDX_RDPTR);
		SDE_DBG_DUMP("all", "dbg_bus", "vbif_dbg_bus");
		sde_encoder_helper_register_irq(phys_enc, INTR_IDX_RDPTR);
	}
	}


	atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
	atomic_add_unless(&phys_enc->pending_kickoff_cnt, -1, 0);
@@ -958,6 +952,28 @@ static int sde_encoder_phys_cmd_get_line_count(
	return hw_pp->ops.get_line_count(hw_pp);
	return hw_pp->ops.get_line_count(hw_pp);
}
}


static int sde_encoder_phys_cmd_get_write_line_count(
		struct sde_encoder_phys *phys_enc)
{
	struct sde_hw_pingpong *hw_pp;
	struct sde_hw_pp_vsync_info info;

	if (!phys_enc || !phys_enc->hw_pp)
		return -EINVAL;

	if (!sde_encoder_phys_cmd_is_master(phys_enc))
		return -EINVAL;

	hw_pp = phys_enc->hw_pp;
	if (!hw_pp->ops.get_vsync_info)
		return -EINVAL;

	if (hw_pp->ops.get_vsync_info(hw_pp, &info))
		return -EINVAL;

	return (int)info.wr_ptr_line_count;
}

static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc)
static void sde_encoder_phys_cmd_disable(struct sde_encoder_phys *phys_enc)
{
{
	struct sde_encoder_phys_cmd *cmd_enc =
	struct sde_encoder_phys_cmd *cmd_enc =
@@ -1302,6 +1318,7 @@ static void sde_encoder_phys_cmd_init_ops(
	ops->is_autorefresh_enabled =
	ops->is_autorefresh_enabled =
			sde_encoder_phys_cmd_is_autorefresh_enabled;
			sde_encoder_phys_cmd_is_autorefresh_enabled;
	ops->get_line_count = sde_encoder_phys_cmd_get_line_count;
	ops->get_line_count = sde_encoder_phys_cmd_get_line_count;
	ops->get_wr_line_count = sde_encoder_phys_cmd_get_write_line_count;
	ops->wait_for_active = NULL;
	ops->wait_for_active = NULL;
}
}


Loading