drm/amd/display: Add pstate verification and recovery for DCN31
authorNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Fri, 17 Dec 2021 14:55:54 +0000 (09:55 -0500)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 15 Mar 2022 18:33:57 +0000 (14:33 -0400)
[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>
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hubbub.c
drivers/gpu/drm/amd/display/dc/dcn10/dcn10_hw_sequencer.c
drivers/gpu/drm/amd/display/dc/dcn30/dcn30_hubbub.c
drivers/gpu/drm/amd/display/dc/dcn301/dcn301_hubbub.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_resource.c
drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h

index f4f423d0b8c3f85894c085de7edbfcfd8f1f5c7d..80595d7f060c32eb309384f8369649c670c6d474 100644 (file)
@@ -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,
index bc9dd48258e32c3a6adcb29434b12a152118366c..c3e141c19a77e4957eb3a9debdddcb4ba8ac8ed3 100644 (file)
@@ -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)
@@ -1123,8 +1127,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();
                }
        }
index f4414de96acc586e4323c2233dae5aacd9a6671f..152c9c5733f1cd5ad6d3636260d41337a1126e4c 100644 (file)
@@ -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,
index 1e3bd2e9cdcc47cb8a84eb352717c670fb1a590b..a046664e2031631dc66b351b371c39018cacbc9e 100644 (file)
@@ -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,
index 5e3bcaf12cac4b55460981dd2e4b79586187b2e4..3e6d6ebd199ee79b7c2c72c57d6de6ca7e20641b 100644 (file)
@@ -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,
index 7dbe301a994a47517cf5408dba95dfa6dc92f093..89b7b6b7254ac8ea97d1bac7acce2fd14d44349f 100644 (file)
@@ -1011,7 +1011,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,
index 713f5558f5e17cbbc01ccdcecac83f6cbc5c0143..9195dec294c2d12eb275839bc66dab202d049f39 100644 (file)
@@ -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);