smu_late_init() re-applies the DPM level after a reset with

  smu_handle_task(smu, smu->smu_dpm.dpm_level, AMD_PP_TASK_COMPLETE_INIT);

but smu_adjust_power_state_dynamic() only programs the hardware when

  if (smu_dpm_ctx->dpm_level != level)

and smu_dpm_ctx is &smu->smu_dpm, so the level is compared against itself.
The branch is never taken for this caller and
smu_asic_set_performance_level() is never called.

PMFW is reinitialised by the reset and comes back on its default curve,
while smu_dpm.dpm_level still holds the level the user forced. The device
therefore runs at the default level while sysfs keeps reporting the forced
one. On an SMU 14.0.1 APU gfxclk drops from 2.8GHz to 600MHz while sysfs
still reports high. Writing the same level again does not help either, as
amdgpu_dpm_force_performance_level() returns early when the requested level
matches the cached one.

Sync the cached level with the state PMFW came back in before re-applying
the forced level, so that it is programmed again. Suspend/resume is not
covered, as PMFW retains its state across s2idle and the forced level still
applies on resume.

Signed-off-by: Priya Hosur <[email protected]>
---
 drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 15 ++++++++++++---
 1 file changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c 
b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
index a65aa2129845..2d318726c521 100644
--- a/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
+++ b/drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c
@@ -998,9 +998,18 @@ static int smu_late_init(struct amdgpu_ip_block *ip_block)
 
        smu_get_fan_parameters(smu);
 
-       smu_handle_task(smu,
-                       smu->smu_dpm.dpm_level,
-                       AMD_PP_TASK_COMPLETE_INIT);
+       if (amdgpu_reset_in_recovery(adev)) {
+               enum amd_dpm_forced_level level = smu->smu_dpm.dpm_level;
+
+               /* PMFW is reinitialised by the reset, so sync the cached level
+                * before re-applying the forced one
+                */
+               smu->smu_dpm.dpm_level = AMD_DPM_FORCED_LEVEL_AUTO;
+               smu_handle_task(smu, level, AMD_PP_TASK_COMPLETE_INIT);
+       } else {
+               smu_handle_task(smu, smu->smu_dpm.dpm_level,
+                               AMD_PP_TASK_COMPLETE_INIT);
+       }
 
        ret = smu_apply_default_config_table_settings(smu);
        if (ret && (ret != -EOPNOTSUPP)) {
-- 
2.43.0

Reply via email to