]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/pm/smu7: Add SCLK cap for quirky Hawaii board
authorTimur Kristóf <timur.kristof@gmail.com>
Sun, 29 Mar 2026 16:03:05 +0000 (18:03 +0200)
committerAlex Deucher <alexander.deucher@amd.com>
Mon, 30 Mar 2026 20:49:01 +0000 (16:49 -0400)
On a specific Radeon R9 390X board, the GPU can "randomly" hang
while gaming. Initially I thought this was a RADV bug and tried
to work around this in Mesa:
commit 8ea08747b86b ("radv: Mitigate GPU hang on Hawaii in Dota 2 and RotTR")

However, I got some feedback from other users who are reporting
that the above mitigation causes a significant performance
regression for them, and they didn't experience the hang on their
GPU in the first place.

After some further investigation, it turns out that the problem
is that the highest SCLK DPM level on this board isn't stable.
Lowering SCLK to 1040 MHz (from 1070 MHz) works around the issue,
and has a negligible impact on performance compared to the Mesa
patch. (Note that increasing the voltage can also work around it,
but we felt that lowering the SCLK is the safer option.)

To solve the above issue, add an "sclk_cap" field to smu7_hwmgr
and set this field for the affected board. The capped SCLK value
correctly appears on the sysfs interface and shows up in GUI
tools such as LACT.

Fixes: 9f4b35411cfe ("drm/amd/powerplay: add CI asics support to smumgr (v3)")
Signed-off-by: Timur Kristóf <timur.kristof@gmail.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.c
drivers/gpu/drm/amd/pm/powerplay/hwmgr/smu7_hwmgr.h

index 2f3090182267fedd2f7474c84ab2c5a596575ede..8c37aa452569544ba83a9a3c966141fc8844e00c 100644 (file)
@@ -787,7 +787,7 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr)
                hwmgr->dyn_state.vddc_dependency_on_mclk;
        struct phm_cac_leakage_table *std_voltage_table =
                hwmgr->dyn_state.cac_leakage_table;
-       uint32_t i;
+       uint32_t i, clk;
 
        PP_ASSERT_WITH_CODE(allowed_vdd_sclk_table != NULL,
                "SCLK dependency table is missing. This table is mandatory", return -EINVAL);
@@ -804,10 +804,12 @@ static int smu7_setup_dpm_tables_v0(struct pp_hwmgr *hwmgr)
        data->dpm_table.sclk_table.count = 0;
 
        for (i = 0; i < allowed_vdd_sclk_table->count; i++) {
+               clk = min(allowed_vdd_sclk_table->entries[i].clk, data->sclk_cap);
+
                if (i == 0 || data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count-1].value !=
-                               allowed_vdd_sclk_table->entries[i].clk) {
+                               clk) {
                        data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].value =
-                               allowed_vdd_sclk_table->entries[i].clk;
+                               clk;
                        data->dpm_table.sclk_table.dpm_levels[data->dpm_table.sclk_table.count].enabled = (i == 0) ? 1 : 0;
                        data->dpm_table.sclk_table.count++;
                }
@@ -3000,6 +3002,25 @@ static int smu7_init_voltage_dependency_on_display_clock_table(struct pp_hwmgr *
        return 0;
 }
 
+static void smu7_set_sclk_cap(struct pp_hwmgr *hwmgr)
+{
+       struct amdgpu_device *adev = hwmgr->adev;
+       struct smu7_hwmgr *data = (struct smu7_hwmgr *)(hwmgr->backend);
+
+       data->sclk_cap = 0xffffffff;
+
+       if (hwmgr->od_enabled)
+               return;
+
+       /* R9 390X board: last sclk dpm level is unstable, use lower sclk */
+       if (adev->pdev->device == 0x67B0 &&
+           adev->pdev->subsystem_vendor == 0x1043)
+               data->sclk_cap = 104000; /* 1040 MHz */
+
+       if (data->sclk_cap != 0xffffffff)
+               dev_info(adev->dev, "sclk cap: %u kHz on quirky ASIC\n", data->sclk_cap * 10);
+}
+
 static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
 {
        struct amdgpu_device *adev = hwmgr->adev;
@@ -3011,6 +3032,7 @@ static int smu7_hwmgr_backend_init(struct pp_hwmgr *hwmgr)
                return -ENOMEM;
 
        hwmgr->backend = data;
+       smu7_set_sclk_cap(hwmgr);
        smu7_patch_voltage_workaround(hwmgr);
        smu7_init_dpm_defaults(hwmgr);
 
@@ -3894,7 +3916,7 @@ static int smu7_get_pp_table_entry_callback_func_v0(struct pp_hwmgr *hwmgr,
 
        /* Performance levels are arranged from low to high. */
        performance_level->memory_clock = memory_clock;
-       performance_level->engine_clock = engine_clock;
+       performance_level->engine_clock = min(engine_clock, data->sclk_cap);
 
        pcie_gen_from_bios = visland_clk_info->ucPCIEGen;
 
index d9e8b386bd4d38080e465e4e00728b43083c30ad..66adabeab6a3aa9e7cf13375e7793ee106c9645a 100644 (file)
@@ -234,6 +234,7 @@ struct smu7_hwmgr {
        uint32_t                       pcie_gen_cap;
        uint32_t                       pcie_lane_cap;
        uint32_t                       pcie_spc_cap;
+       uint32_t                       sclk_cap;
        struct smu7_leakage_voltage          vddc_leakage;
        struct smu7_leakage_voltage          vddci_leakage;
        struct smu7_leakage_voltage          vddcgfx_leakage;