diff options
author | Jonathan Gray <jsg@cvs.openbsd.org> | 2022-04-21 09:28:17 +0000 |
---|---|---|
committer | Jonathan Gray <jsg@cvs.openbsd.org> | 2022-04-21 09:28:17 +0000 |
commit | de82b5cdb6f60858b994cacd063f389a2756ffbc (patch) | |
tree | b2a15eef74e82d57dc12ad025969487bfdc5f547 /sys | |
parent | 38ac72abeeae2a4f7a9860a3183c312a0279ec24 (diff) |
drm/amd/display: Add pstate verification and recovery for DCN31
From Nicholas Kazlauskas
685a19fa6ae99dc7a18a9af2a7626162e1db7aff in linux 5.15.y/5.15.35
e7031d8258f1b4d6d50e5e5b5d92ba16f66eb8b4 in mainline linux
Diffstat (limited to 'sys')
7 files changed, 74 insertions, 4 deletions
diff --git a/sys/dev/pci/drm/amd/display/dc/dcn10/dcn10_hubbub.c b/sys/dev/pci/drm/amd/display/dc/dcn10/dcn10_hubbub.c index f4f423d0b8c..80595d7f060 100644 --- a/sys/dev/pci/drm/amd/display/dc/dcn10/dcn10_hubbub.c +++ b/sys/dev/pci/drm/amd/display/dc/dcn10/dcn10_hubbub.c @@ -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, diff --git a/sys/dev/pci/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c b/sys/dev/pci/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c index 3af49cdf89e..b3a0499f855 100644 --- a/sys/dev/pci/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c +++ b/sys/dev/pci/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c @@ -1052,9 +1052,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) @@ -1063,8 +1067,8 @@ void dcn10_verify_allow_pstate_change_high(struct dc *dc) TRACE_DC_PIPE_STATE(pipe_ctx, i, MAX_PIPES); BREAK_TO_DEBUGGER(); if (dcn10_hw_wa_force_recovery(dc)) { - /*check again*/ - if (!hubbub1_verify_allow_pstate_change_high(dc->res_pool->hubbub)) + /*check again*/ + if (!hubbub->funcs->verify_allow_pstate_change_high(hubbub)) BREAK_TO_DEBUGGER(); } } diff --git a/sys/dev/pci/drm/amd/display/dc/dcn30/dcn30_hubbub.c b/sys/dev/pci/drm/amd/display/dc/dcn30/dcn30_hubbub.c index f4414de96ac..152c9c5733f 100644 --- a/sys/dev/pci/drm/amd/display/dc/dcn30/dcn30_hubbub.c +++ b/sys/dev/pci/drm/amd/display/dc/dcn30/dcn30_hubbub.c @@ -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, diff --git a/sys/dev/pci/drm/amd/display/dc/dcn301/dcn301_hubbub.c b/sys/dev/pci/drm/amd/display/dc/dcn301/dcn301_hubbub.c index 1e3bd2e9cdc..a046664e203 100644 --- a/sys/dev/pci/drm/amd/display/dc/dcn301/dcn301_hubbub.c +++ b/sys/dev/pci/drm/amd/display/dc/dcn301/dcn301_hubbub.c @@ -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, diff --git a/sys/dev/pci/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/sys/dev/pci/drm/amd/display/dc/dcn31/dcn31_hubbub.c index 5e3bcaf12ca..f8bc2a5f5ba 100644 --- a/sys/dev/pci/drm/amd/display/dc/dcn31/dcn31_hubbub.c +++ b/sys/dev/pci/drm/amd/display/dc/dcn31/dcn31_hubbub.c @@ -24,6 +24,7 @@ */ +#include <linux/delay.h> #include "dcn30/dcn30_hubbub.h" #include "dcn31_hubbub.h" #include "dm_services.h" @@ -949,6 +950,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 +1021,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, diff --git a/sys/dev/pci/drm/amd/display/dc/dcn31/dcn31_resource.c b/sys/dev/pci/drm/amd/display/dc/dcn31/dcn31_resource.c index d4fe5352421..a5ef9d5e768 100644 --- a/sys/dev/pci/drm/amd/display/dc/dcn31/dcn31_resource.c +++ b/sys/dev/pci/drm/amd/display/dc/dcn31/dcn31_resource.c @@ -940,7 +940,7 @@ static const struct dc_debug_options debug_defaults_drv = { .max_downscale_src_width = 4096,/*upto true 4K*/ .disable_pplib_wm_range = false, .scl_reset_length10 = true, - .sanity_checks = false, + .sanity_checks = true, .underflow_assert_delay_us = 0xFFFFFFFF, .dwb_fi_phase = -1, // -1 = disable, .dmub_command_table = true, diff --git a/sys/dev/pci/drm/amd/display/dc/inc/hw/dchubbub.h b/sys/dev/pci/drm/amd/display/dc/inc/hw/dchubbub.h index 713f5558f5e..9195dec294c 100644 --- a/sys/dev/pci/drm/amd/display/dc/inc/hw/dchubbub.h +++ b/sys/dev/pci/drm/amd/display/dc/inc/hw/dchubbub.h @@ -154,6 +154,8 @@ struct hubbub_funcs { bool (*is_allow_self_refresh_enabled)(struct hubbub *hubbub); 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 (*force_wm_propagate_to_pipes)(struct hubbub *hubbub); |