]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
drm/amd/pm: fix torn gpu metrics reads
authorYang Wang <kevinyang.wang@amd.com>
Thu, 23 Jul 2026 15:18:33 +0000 (23:18 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 29 Jul 2026 00:00:06 +0000 (20:00 -0400)
amdgpu_dpm_get_gpu_metrics() returns a pointer to the shared metrics cache
after dropping adev->pm.mutex. The sysfs path then copies from that pointer.
Another reader can refresh the cache in place during the copy and return a
snapshot containing data from two generations.

Pass caller-provided storage through the DPM interface and copy the metrics
while the mutex is held. This keeps the cache pointer private and makes each
sysfs read observe one complete sample.

Fixes: 25c933b1c4fc ("drm/amd/powerplay: add new sysfs interface for retrieving gpu metrics(V2)")
Signed-off-by: Yang Wang <kevinyang.wang@amd.com>
Reviewed-by: Kenneth Feng <kenneth.feng@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 862333bb48693ecafcae25af0c9d9ec31015ac77)
Cc: stable@vger.kernel.org
drivers/gpu/drm/amd/pm/amdgpu_dpm.c
drivers/gpu/drm/amd/pm/amdgpu_pm.c
drivers/gpu/drm/amd/pm/inc/amdgpu_dpm.h

index c787e772b3cc2a8c5e767bb95e00b18c61d24ddf..6d1ad4d5b8f0412e24a75889d3bf701cab176615 100644 (file)
@@ -1434,17 +1434,23 @@ int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev,
        return ret;
 }
 
-int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table)
+ssize_t amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void *buf,
+                                  size_t size)
 {
        const struct amd_pm_funcs *pp_funcs = adev->powerplay.pp_funcs;
-       int ret = 0;
+       void *table;
+       ssize_t ret;
 
        if (!pp_funcs->get_gpu_metrics)
                return 0;
 
        mutex_lock(&adev->pm.mutex);
        ret = pp_funcs->get_gpu_metrics(adev->powerplay.pp_handle,
-                                       table);
+                                       &table);
+       if (ret > 0) {
+               ret = min_t(ssize_t, ret, size);
+               memcpy(buf, table, ret);
+       }
        mutex_unlock(&adev->pm.mutex);
 
        return ret;
index d94ea54c33c39bac159924ebe4eb89a9af480f9d..763947fbf16f65239a70efe7d0f31d2fb72a5226 100644 (file)
@@ -1774,7 +1774,6 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
 {
        struct drm_device *ddev = dev_get_drvdata(dev);
        struct amdgpu_device *adev = drm_to_adev(ddev);
-       void *gpu_metrics;
        ssize_t size = 0;
        int ret;
 
@@ -1782,15 +1781,10 @@ static ssize_t amdgpu_get_gpu_metrics(struct device *dev,
        if (ret)
                return ret;
 
-       size = amdgpu_dpm_get_gpu_metrics(adev, &gpu_metrics);
+       size = amdgpu_dpm_get_gpu_metrics(adev, buf, PAGE_SIZE - 1);
        if (size <= 0)
                goto out;
 
-       if (size >= PAGE_SIZE)
-               size = PAGE_SIZE - 1;
-
-       memcpy(buf, gpu_metrics, size);
-
 out:
        amdgpu_pm_put_access(adev);
 
index e95cd22a31cfdb395a0a47f264a418f0085ac98f..8d1b097a3c3c9900062bb8b468d1885f44b65cb8 100644 (file)
@@ -518,7 +518,8 @@ int amdgpu_dpm_get_power_profile_mode(struct amdgpu_device *adev,
                                      char *buf);
 int amdgpu_dpm_set_power_profile_mode(struct amdgpu_device *adev,
                                      long *input, uint32_t size);
-int amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void **table);
+ssize_t amdgpu_dpm_get_gpu_metrics(struct amdgpu_device *adev, void *buf,
+                                  size_t size);
 ssize_t amdgpu_dpm_get_xcp_metrics(struct amdgpu_device *adev, int xcp_id,
                                   void *table);
 ssize_t amdgpu_dpm_get_temp_metrics(struct amdgpu_device *adev,