mirror of
https://github.com/linux-msm/laptops-kernel.git
synced 2026-08-13 14:19:53 -07:00
drm/amd/pm: fix torn gpu metrics reads
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:25c933b1c4("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 commit862333bb48) Cc: stable@vger.kernel.org
This commit is contained in:
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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,
|
||||
|
||||
Reference in New Issue
Block a user