Commit e7031d82 authored by Nicholas Kazlauskas's avatar Nicholas Kazlauskas Committed by Alex Deucher
Browse files

drm/amd/display: Add pstate verification and recovery for DCN31



[Why]
To debug when p-state is being blocked and avoid PMFW hangs when
it does occur.

[How]
Re-use the DCN10 hardware sequencer by adding a new interface for
verifying p-state high on the hubbub. The interface is mostly the
same as the DCN10 interface, but the bit definitions have changed for
the debug bus.

Signed-off-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Reviewed-by: default avatarEric Yang <Eric.Yang2@amd.com>
Reviewed-by: default avatarHarry Wentland <harry.wentland@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 65722ff6
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -940,6 +940,7 @@ static const struct hubbub_funcs hubbub1_funcs = {
	.program_watermarks = hubbub1_program_watermarks,
	.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
	.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
	.verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high,
};

void hubbub1_construct(struct hubbub *hubbub,
+7 −3
Original line number Diff line number Diff line
@@ -1112,9 +1112,13 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)

void dcn10_verify_allow_pstate_change_high(struct dc *dc)
{
	struct hubbub *hubbub = dc->res_pool->hubbub;
	static bool should_log_hw_state; /* prevent hw state log by default */

	if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub)) {
	if (!hubbub->funcs->verify_allow_pstate_change_high)
		return;

	if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) {
		int i = 0;

		if (should_log_hw_state)
@@ -1124,7 +1128,7 @@ void dcn10_verify_allow_pstate_change_high(struct dc *dc)
		BREAK_TO_DEBUGGER();
		if (dcn10_hw_wa_force_recovery(dc)) {
			/*check again*/
			if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub))
			if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub))
				BREAK_TO_DEBUGGER();
		}
	}
+1 −0
Original line number Diff line number Diff line
@@ -448,6 +448,7 @@ static const struct hubbub_funcs hubbub30_funcs = {
	.program_watermarks = hubbub3_program_watermarks,
	.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
	.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
	.verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high,
	.force_wm_propagate_to_pipes = hubbub3_force_wm_propagate_to_pipes,
	.force_pstate_change_control = hubbub3_force_pstate_change_control,
	.init_watermarks = hubbub3_init_watermarks,
+1 −0
Original line number Diff line number Diff line
@@ -60,6 +60,7 @@ static const struct hubbub_funcs hubbub301_funcs = {
	.program_watermarks = hubbub3_program_watermarks,
	.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
	.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
	.verify_allow_pstate_change_high = hubbub1_verify_allow_pstate_change_high,
	.force_wm_propagate_to_pipes = hubbub3_force_wm_propagate_to_pipes,
	.force_pstate_change_control = hubbub3_force_pstate_change_control,
	.hubbub_read_state = hubbub2_read_state,
+60 −0
Original line number Diff line number Diff line
@@ -949,6 +949,65 @@ static void hubbub31_get_dchub_ref_freq(struct hubbub *hubbub,
	}
}

static bool hubbub31_verify_allow_pstate_change_high(struct hubbub *hubbub)
{
	struct dcn20_hubbub *hubbub2 = TO_DCN20_HUBBUB(hubbub);

	/*
	 * Pstate latency is ~20us so if we wait over 40us and pstate allow
	 * still not asserted, we are probably stuck and going to hang
	 */
	const unsigned int pstate_wait_timeout_us = 100;
	const unsigned int pstate_wait_expected_timeout_us = 40;

	static unsigned int max_sampled_pstate_wait_us; /* data collection */
	static bool forced_pstate_allow; /* help with revert wa */

	unsigned int debug_data = 0;
	unsigned int i;

	if (forced_pstate_allow) {
		/* we hacked to force pstate allow to prevent hang last time
		 * we verify_allow_pstate_change_high.  so disable force
		 * here so we can check status
		 */
		REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
			     DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 0,
			     DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 0);
		forced_pstate_allow = false;
	}

	REG_WRITE(DCHUBBUB_TEST_DEBUG_INDEX, hubbub2->debug_test_index_pstate);

	for (i = 0; i < pstate_wait_timeout_us; i++) {
		debug_data = REG_READ(DCHUBBUB_TEST_DEBUG_DATA);

		/* Debug bit is specific to ASIC. */
		if (debug_data & (1 << 26)) {
			if (i > pstate_wait_expected_timeout_us)
				DC_LOG_WARNING("pstate took longer than expected ~%dus\n", i);
			return true;
		}
		if (max_sampled_pstate_wait_us < i)
			max_sampled_pstate_wait_us = i;

		udelay(1);
	}

	/* force pstate allow to prevent system hang
	 * and break to debugger to investigate
	 */
	REG_UPDATE_2(DCHUBBUB_ARB_DRAM_STATE_CNTL,
		     DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_VALUE, 1,
		     DCHUBBUB_ARB_ALLOW_PSTATE_CHANGE_FORCE_ENABLE, 1);
	forced_pstate_allow = true;

	DC_LOG_WARNING("pstate TEST_DEBUG_DATA: 0x%X\n",
			debug_data);

	return false;
}

static const struct hubbub_funcs hubbub31_funcs = {
	.update_dchub = hubbub2_update_dchub,
	.init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx,
@@ -961,6 +1020,7 @@ static const struct hubbub_funcs hubbub31_funcs = {
	.program_watermarks = hubbub31_program_watermarks,
	.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
	.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
	.verify_allow_pstate_change_high = hubbub31_verify_allow_pstate_change_high,
	.program_det_size = dcn31_program_det_size,
	.program_compbuf_size = dcn31_program_compbuf_size,
	.init_crb = dcn31_init_crb,
Loading