aboutsummaryrefslogtreecommitdiff
path: root/drivers
diff options
context:
space:
mode:
authorJesse Zhang <Jesse.Zhang@amd.com>2026-10-09 13:21:33 +0800
committerAlex Deucher <alexander.deucher@amd.com>2026-10-15 12:46:01 -0400
commitde9f6bcdb44f0e410031002e2f103826ea6b6259 (patch)
tree74a3305897bec10727c5685f7df18212f04aeb8f /drivers
parent3c516a5646285442e1cd71dff2584b77eb4fc421 (diff)
drm/amdgpu: don't drop the runtime PM reference twice in amdgpu_gpr
amdgpu_debugfs_gpr_read() drops its runtime PM reference right after reading the wave registers. When copying them to userspace fails, it jumps to the err label, which drops the reference a second time. A read into a bad buffer on Navi31 either steals a reference somebody else holds (power/runtime_usage goes from 1 to 0) or underflows the count: amdgpu 0000:03:00.0: Runtime PM usage count underflow! The registers are already in the kernel buffer at that point, so finish the hardware access first and copy the buffer with a single copy_to_user() instead of the put_user() loop with its own error path. Fixes: 9eee152aab56 ("drm/amdgpu/debugfs: fix ref count leak when pm_runtime_get_sync fails") Reviewed-by: Alex Deucher <alexander.deucher@amd.com> Signed-off-by: Jesse Zhang <Jesse.Zhang@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> (cherry picked from commit 31035bbd74f7c3e10c163db875b8e67f8b50ee6a) Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers')
-rw-r--r--drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c21
1 files changed, 3 insertions, 18 deletions
diff --git a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
index ab7ccfaea22a..4f9b72ac5698 100644
--- a/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
+++ b/drivers/gpu/drm/amd/amdgpu/amdgpu_debugfs.c
@@ -1266,7 +1266,6 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
{
struct amdgpu_device *adev = f->f_inode->i_private;
int r;
- ssize_t result = 0;
uint32_t offset, se, sh, cu, wave, simd, thread, bank, *data;
if (size > 4096 || size & 3 || *pos & 3)
@@ -1310,25 +1309,11 @@ static ssize_t amdgpu_debugfs_gpr_read(struct file *f, char __user *buf,
mutex_unlock(&adev->grbm_idx_mutex);
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);
+ amdgpu_virt_disable_access_debugfs(adev);
- while (size) {
- uint32_t value;
-
- value = data[result >> 2];
- r = put_user(value, (uint32_t *)buf);
- if (r) {
- amdgpu_virt_disable_access_debugfs(adev);
- goto err;
- }
-
- result += 4;
- buf += 4;
- size -= 4;
- }
-
+ r = copy_to_user(buf, data, size) ? -EFAULT : size;
kfree(data);
- amdgpu_virt_disable_access_debugfs(adev);
- return result;
+ return r;
err:
pm_runtime_put_autosuspend(adev_to_drm(adev)->dev);