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: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Reviewed-by: Eric Yang <Eric.Yang2@amd.com> Reviewed-by: Harry Wentland <harry.wentland@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
This commit is contained in:
Родитель
65722ff618
Коммит
e7031d8258
|
@ -940,6 +940,7 @@ static const struct hubbub_funcs hubbub1_funcs = {
|
||||||
.program_watermarks = hubbub1_program_watermarks,
|
.program_watermarks = hubbub1_program_watermarks,
|
||||||
.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
|
.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
|
||||||
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
|
.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,
|
void hubbub1_construct(struct hubbub *hubbub,
|
||||||
|
|
|
@ -1112,9 +1112,13 @@ static bool dcn10_hw_wa_force_recovery(struct dc *dc)
|
||||||
|
|
||||||
void dcn10_verify_allow_pstate_change_high(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 */
|
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;
|
int i = 0;
|
||||||
|
|
||||||
if (should_log_hw_state)
|
if (should_log_hw_state)
|
||||||
|
@ -1123,8 +1127,8 @@ void dcn10_verify_allow_pstate_change_high(struct dc *dc)
|
||||||
TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES);
|
TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES);
|
||||||
BREAK_TO_DEBUGGER();
|
BREAK_TO_DEBUGGER();
|
||||||
if (dcn10_hw_wa_force_recovery(dc)) {
|
if (dcn10_hw_wa_force_recovery(dc)) {
|
||||||
/*check again*/
|
/*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();
|
BREAK_TO_DEBUGGER();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -448,6 +448,7 @@ static const struct hubbub_funcs hubbub30_funcs = {
|
||||||
.program_watermarks = hubbub3_program_watermarks,
|
.program_watermarks = hubbub3_program_watermarks,
|
||||||
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
|
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
|
||||||
.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
|
.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_wm_propagate_to_pipes = hubbub3_force_wm_propagate_to_pipes,
|
||||||
.force_pstate_change_control = hubbub3_force_pstate_change_control,
|
.force_pstate_change_control = hubbub3_force_pstate_change_control,
|
||||||
.init_watermarks = hubbub3_init_watermarks,
|
.init_watermarks = hubbub3_init_watermarks,
|
||||||
|
|
|
@ -60,6 +60,7 @@ static const struct hubbub_funcs hubbub301_funcs = {
|
||||||
.program_watermarks = hubbub3_program_watermarks,
|
.program_watermarks = hubbub3_program_watermarks,
|
||||||
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
|
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
|
||||||
.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
|
.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_wm_propagate_to_pipes = hubbub3_force_wm_propagate_to_pipes,
|
||||||
.force_pstate_change_control = hubbub3_force_pstate_change_control,
|
.force_pstate_change_control = hubbub3_force_pstate_change_control,
|
||||||
.hubbub_read_state = hubbub2_read_state,
|
.hubbub_read_state = hubbub2_read_state,
|
||||||
|
|
|
@ -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 = {
|
static const struct hubbub_funcs hubbub31_funcs = {
|
||||||
.update_dchub = hubbub2_update_dchub,
|
.update_dchub = hubbub2_update_dchub,
|
||||||
.init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx,
|
.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,
|
.program_watermarks = hubbub31_program_watermarks,
|
||||||
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
|
.allow_self_refresh_control = hubbub1_allow_self_refresh_control,
|
||||||
.is_allow_self_refresh_enabled = hubbub1_is_allow_self_refresh_enabled,
|
.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_det_size = dcn31_program_det_size,
|
||||||
.program_compbuf_size = dcn31_program_compbuf_size,
|
.program_compbuf_size = dcn31_program_compbuf_size,
|
||||||
.init_crb = dcn31_init_crb,
|
.init_crb = dcn31_init_crb,
|
||||||
|
|
|
@ -1011,7 +1011,7 @@ static const struct dc_debug_options debug_defaults_drv = {
|
||||||
.max_downscale_src_width = 4096,/*upto true 4K*/
|
.max_downscale_src_width = 4096,/*upto true 4K*/
|
||||||
.disable_pplib_wm_range = false,
|
.disable_pplib_wm_range = false,
|
||||||
.scl_reset_length10 = true,
|
.scl_reset_length10 = true,
|
||||||
.sanity_checks = false,
|
.sanity_checks = true,
|
||||||
.underflow_assert_delay_us = 0xFFFFFFFF,
|
.underflow_assert_delay_us = 0xFFFFFFFF,
|
||||||
.dwb_fi_phase = -1, // -1 = disable,
|
.dwb_fi_phase = -1, // -1 = disable,
|
||||||
.dmub_command_table = true,
|
.dmub_command_table = true,
|
||||||
|
|
|
@ -154,6 +154,8 @@ struct hubbub_funcs {
|
||||||
bool (*is_allow_self_refresh_enabled)(struct hubbub *hubbub);
|
bool (*is_allow_self_refresh_enabled)(struct hubbub *hubbub);
|
||||||
void (*allow_self_refresh_control)(struct hubbub *hubbub, bool allow);
|
void (*allow_self_refresh_control)(struct hubbub *hubbub, bool allow);
|
||||||
|
|
||||||
|
bool (*verify_allow_pstate_change_high)(struct hubbub *hubbub);
|
||||||
|
|
||||||
void (*apply_DEDCN21_147_wa)(struct hubbub *hubbub);
|
void (*apply_DEDCN21_147_wa)(struct hubbub *hubbub);
|
||||||
|
|
||||||
void (*force_wm_propagate_to_pipes)(struct hubbub *hubbub);
|
void (*force_wm_propagate_to_pipes)(struct hubbub *hubbub);
|
||||||
|
|
Загрузка…
Ссылка в новой задаче