After a GPU reset the level reported through
power_dpm_force_performance_level no longer matches the hardware. The reset
reinitialises PMFW, which comes back on its default curve, while
smu_dpm.dpm_level still holds the level the user forced.

On an SMU 14.0.1 APU this shows up as gfxclk dropping from 2.8GHz to 600MHz
while sysfs still reports high, with no thermal or power event involved:

  before  level: high   freq: 2799000000
          amdgpu 0000:c5:00.0: MODE2 reset
          amdgpu 0000:c5:00.0: SMU is resumed successfully!
  after   level: high   freq:  600000000

smu_late_init() already tries to re-apply the level after the reset:

  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.

Syncing the cached level with the state PMFW came back in, before
re-applying the forced level, makes that call effective again. The reset
then no longer changes the level the user asked for.

Tested on an SMU 14.0.1 APU, triggering resets through
debugfs/amdgpu_gpu_recover and reading the level and gfxclk either side:

  level              before    reset 1   reset 2   reset 3
  high               2784MHz   2799MHz   2799MHz   2799MHz
  low                 605MHz    600MHz    600MHz
  manual              600MHz    600MHz    603MHz
  profile_peak       2260MHz   2799MHz   2799MHz
  profile_standard    705MHz    700MHz    700MHz
  auto                600MHz    601MHz    600MHz    600MHz

The level is retained across every reset, with no drift over repeats, and
auto is left on its own curve rather than being pinned high. profile_peak
sets a ceiling rather than a floor, so its sampled clock varies with load.
17 MODE2 resets over the run with no instability.

A suspend/resume cycle also keeps the level: high at 2784MHz before suspend,
high at 2799MHz after resume.

The change is scoped to reset recovery. PMFW retains its state across
s2idle, so on resume the forced level still applies and nothing needs
re-applying.

This is the only configuration I have available to test. The change is in
generic SMU code, so it applies to every ASIC going through
smu_late_init().

v2: restore the forced level instead of reporting the default after the
    reset, as the driver is expected to keep the level the user asked for
    and the reset often goes unnoticed (Lijo)

Priya Hosur (1):
  drm/amd/pm: restore the forced performance level after a reset

 drivers/gpu/drm/amd/pm/swsmu/amdgpu_smu.c | 15 ++++++++++-----
 1 file changed, 10 insertions(+), 5 deletions(-)

-- 
2.43.0

Reply via email to