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
+
+ 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