AMD General

-----Original Message-----
From: Lazar, Lijo <[email protected]>
Sent: Wednesday, July 22, 2026 8:11 PM
To: Zhang, Hawking <[email protected]>; Li, Candice <[email protected]>; 
[email protected]
Subject: Re: [PATCH] drm/amdgpu: restore perf state after runtime resume



On 22-Jul-26 4:43 PM, Zhang, Hawking wrote:
> AMD General
>
> Reviewed-by: Hawking Zhang <[email protected]>
>
> Regards,
> Hawking
> -----Original Message-----
> From: amd-gfx <[email protected]> On Behalf Of Candice Li
> Sent: Wednesday, July 22, 2026 6:36 PM
> To: [email protected]
> Cc: Li, Candice <[email protected]>
> Subject: [PATCH] drm/amdgpu: restore perf state after runtime resume
>
> Runtime suspend runs GFX hw_fini and clears perfmon clock gating while KFD 
> keeps running, so block perf counters read zero after resume even though 
> profiling remains enabled in software.
>
> Re-apply UMD stable pstate for profile DPM modes and re-enable KFD perfcount 
> after a successful runtime resume.
>
> Signed-off-by: Candice Li <[email protected]>
> ---
>   drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c | 46 ++++++++++++++++++++++  
> drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h |  1 +
>   drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c    | 17 ++++++++
>   drivers/gpu/drm/amd/amdkfd/kfd_chardev.c   |  8 ++++
>   drivers/gpu/drm/amd/amdkfd/kfd_priv.h      |  2 +
>   drivers/gpu/drm/amd/amdkfd/kfd_process.c   |  1 +
>   6 files changed, 75 insertions(+)
>
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
> index 121282dd30c161..38974beb98ef88 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.c
> @@ -38,6 +38,7 @@
>   #include "amdgpu_reset.h"
>   #if IS_ENABLED(CONFIG_HSA_AMD)
>   #include "kfd_priv.h"
> +#include "kfd_device_queue_manager.h"
>   #endif
>
>   /* Total memory size in system memory and all GPU VRAM. Used to @@ -280,6 
> +281,51 @@ int amdgpu_amdkfd_resume(struct amdgpu_device *adev, bool 
> resume_proc)
>          return r;
>   }
>
> +void amdgpu_amdkfd_restore_profiler_after_runpm(struct amdgpu_device
> +*adev) { #if IS_ENABLED(CONFIG_HSA_AMD)
> +       struct kfd_dev *kfd;
> +       struct kfd_process *p;
> +       struct kfd_process_device *pdd;
> +       struct device_queue_manager *dqm;
> +       int i;
> +
> +       if (!adev->kfd.dev || !adev->kfd.init_complete)
> +               return;
> +
> +       kfd = adev->kfd.dev;
> +
> +       mutex_lock(&kfd->profiler_lock);
> +       p = kfd->profiler_process;
> +       if (!p || !kfd->profiler_perfcount_enabled) {
> +               mutex_unlock(&kfd->profiler_lock);
> +               return;
> +       }
> +       mutex_unlock(&kfd->profiler_lock);
> +
> +       mutex_lock(&p->mutex);
> +
> +       mutex_lock(&kfd->profiler_lock);
> +       if (kfd->profiler_process != p || !kfd->profiler_perfcount_enabled) {
> +               mutex_unlock(&kfd->profiler_lock);
> +               mutex_unlock(&p->mutex);
> +               return;
> +       }
> +       mutex_unlock(&kfd->profiler_lock);
> +
> +       for (i = 0; i < p->n_pdds; i++) {
> +               pdd = p->pdds[i];
> +               if (!pdd || !pdd->dev || pdd->dev->kfd != kfd)
> +                       continue;
> +
> +               dqm = pdd->dev->dqm;
> +               if (dqm && dqm->ops.set_perfcount)
> +                       dqm->ops.set_perfcount(dqm, 1);
> +       }
> +       mutex_unlock(&p->mutex);
> +#endif
> +}
> +
>   void amdgpu_amdkfd_suspend_process(struct amdgpu_device *adev)  {
>          if (adev->kfd.dev)
> diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
> index 338412a750edf0..1be9d5ef97d6d0 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_amdkfd.h
> @@ -164,6 +164,7 @@ void amdgpu_amdkfd_teardown_processes(struct 
> amdgpu_device *adev);
>
>   void amdgpu_amdkfd_suspend(struct amdgpu_device *adev, bool suspend_proc);  
> int amdgpu_amdkfd_resume(struct amdgpu_device *adev, bool resume_proc);
> +void amdgpu_amdkfd_restore_profiler_after_runpm(struct amdgpu_device
> +*adev);
>   void amdgpu_amdkfd_suspend_process(struct amdgpu_device *adev);  int 
> amdgpu_amdkfd_resume_process(struct amdgpu_device *adev);  void 
> amdgpu_amdkfd_interrupt(struct amdgpu_device *adev, diff --git 
> a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c 
> b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> index 5362705143bc75..f7a1064c340692 100644
> --- a/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> +++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c
> @@ -2920,6 +2920,21 @@ static int amdgpu_pmops_runtime_suspend(struct device 
> *dev)
>          return 0;
>   }
>
> +static void amdgpu_restore_perf_state_after_runpm(struct amdgpu_device
> +*adev) {
> +       enum amd_dpm_forced_level level;
> +       uint32_t profile_mode_mask = AMD_DPM_FORCED_LEVEL_PROFILE_STANDARD |
> +               AMD_DPM_FORCED_LEVEL_PROFILE_MIN_SCLK |
> +               AMD_DPM_FORCED_LEVEL_PROFILE_MIN_MCLK |
> +               AMD_DPM_FORCED_LEVEL_PROFILE_PEAK;
> +
> +       level = amdgpu_dpm_get_performance_level(adev);
> +       if (level & profile_mode_mask)
> +               amdgpu_asic_update_umd_stable_pstate(adev, true);

This is supposed to be called before entering the force dpm level mode.
It's better to move this logic inside swsmu late_init before reapplying
the level.

Thanks,
Lijo

Thanks, Lijo.

I think this logic should remain in runtime resume. The 
amdgpu_asic_update_umd_stable_pstate(adev, true) call here is a 
restore/re-apply step for an already-selected profile forced level, not a 
force-level entry.
Enter/exit behavior is already covered by the regular DPM force path 
(amdgpu_dpm_force_performance_level() / SMU force handling) when level 
transitions occur.

During runpm suspend/resume, the software forced level can remain profile mode, 
but HW-side stable pstate (and KFD profiler state) may be cleared by 
hw_fini/hw_init.
That is why this restore is done after amdgpu_device_resume().

Moving this into swsmu late_init would apply the logic to broader flows (not 
only runpm), so I’d prefer to keep it in runpm resume.


Thanks,
Candice

> +
> +       amdgpu_amdkfd_restore_profiler_after_runpm(adev);
> +}
> +
>   static int amdgpu_pmops_runtime_resume(struct device *dev)  {
>          struct pci_dev *pdev = to_pci_dev(dev); @@ -2964,6 +2979,8 @@ static 
> int amdgpu_pmops_runtime_resume(struct device *dev)
>
>          if (adev->pm.rpm_mode == AMDGPU_RUNPM_PX)
>                  drm_dev->switch_power_state = DRM_SWITCH_POWER_ON;
> +
> +       amdgpu_restore_perf_state_after_runpm(adev);
>          adev->in_runpm = false;
>          return 0;
>   }
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c 
> b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> index 2c1a936459ac87..2a140c40b53f9c 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_chardev.c
> @@ -3347,6 +3347,7 @@ static inline uint32_t profile_lock_device(struct 
> kfd_process *p,
>          if (op == 1) {
>                  if (!kfd->profiler_process) {
>                          kfd->profiler_process = p;
> +                       kfd->profiler_perfcount_enabled = false;
>                          status = 0;
>                          mutex_unlock(&kfd->profiler_lock);
>                          if (ptl->hw_supported) {
> @@ -3364,6 +3365,7 @@ static inline uint32_t profile_lock_device(struct 
> kfd_process *p,
>                  }
>          } else if (op == 0 && kfd->profiler_process == p) {
>                  kfd->profiler_process = NULL;
> +               kfd->profiler_perfcount_enabled = false;
>                  status = 0;
>                  mutex_unlock(&kfd->profiler_lock);
>
> @@ -3404,6 +3406,12 @@ static inline int kfd_profiler_pmc(struct kfd_process 
> *p,
>          mutex_unlock(&p->mutex);
>
>          dqm->ops.set_perfcount(dqm, args->perfcount_enable);
> +
> +       mutex_lock(&pdd->dev->kfd->profiler_lock);
> +       if (pdd->dev->kfd->profiler_process == p)
> +               pdd->dev->kfd->profiler_perfcount_enabled = 
> !!args->perfcount_enable;
> +       mutex_unlock(&pdd->dev->kfd->profiler_lock);
> +
>          return status;
>   }
>
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h 
> b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> index 88191a4c165796..81055ada4f80b8 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_priv.h
> @@ -389,6 +389,8 @@ struct kfd_dev {
>          struct mutex profiler_lock;
>          /* Process currently holding the lock */
>          struct kfd_process *profiler_process;
> +       /* Whether perfcount is enabled for profiler_process */
> +       bool profiler_perfcount_enabled;
>   };
>
>   enum kfd_mempool {
> diff --git a/drivers/gpu/drm/amd/amdkfd/kfd_process.c 
> b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> index eb508fe3ded780..8b7020fc0577a2 100644
> --- a/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> +++ b/drivers/gpu/drm/amd/amdkfd/kfd_process.c
> @@ -1180,6 +1180,7 @@ static void kfd_process_profiler_release(struct 
> kfd_process *p, struct kfd_proce
>          if (pdd->dev->kfd->profiler_process == p) {
>                  pdd->qpd.dqm->ops.set_perfcount(pdd->qpd.dqm, 0);
>                  pdd->dev->kfd->profiler_process = NULL;
> +               pdd->dev->kfd->profiler_perfcount_enabled = false;
>          }
>          mutex_unlock(&pdd->dev->kfd->profiler_lock);
>   }
> --
> 2.25.1
>

Reply via email to