]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
drm/amd: Forbid suspending into non-default suspend states
authorMario Limonciello <mario.limonciello@amd.com>
Tue, 8 Apr 2025 18:09:57 +0000 (13:09 -0500)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 2 May 2025 06:02:13 +0000 (08:02 +0200)
[ Upstream commit 1657793def101dac7c9d3b2250391f6a3dd934ba ]

On systems that default to 'deep' some userspace software likes
to try to suspend in 'deep' first.  If there is a failure for any
reason (such as -ENOMEM) the failure is ignored and then it will
try to use 's2idle' as a fallback. This fails, but more importantly
it leads to graphical problems.

Forbid this behavior and only allow suspending in the last state
supported by the system.

Closes: https://gitlab.freedesktop.org/drm/amd/-/issues/4093
Acked-by: Alex Deucher <alexander.deucher@amd.com>
Link: https://lore.kernel.org/r/20250408180957.4027643-1-superm1@kernel.org
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 2aabd44aa8a3c08da3d43264c168370f6da5e81d)
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/gpu/drm/amd/amdgpu/amdgpu.h
drivers/gpu/drm/amd/amdgpu/amdgpu_drv.c

index ab04d56b4fe367b9f39bc63e86a09735d44b66b1..98f0c12df12bc1af0eced62cfdc8cb27444ba2c4 100644 (file)
@@ -1118,6 +1118,7 @@ struct amdgpu_device {
        bool                            in_s3;
        bool                            in_s4;
        bool                            in_s0ix;
+       suspend_state_t                 last_suspend_state;
 
        enum pp_mp1_state               mp1_state;
        struct amdgpu_doorbell_index doorbell_index;
index 24c255e05079e035bfcb7ca6b4a42d162a5ffc33..f2d77bc04e4a986b0147bc752353683002b35061 100644 (file)
@@ -2515,8 +2515,20 @@ static int amdgpu_pmops_suspend(struct device *dev)
                adev->in_s0ix = true;
        else if (amdgpu_acpi_is_s3_active(adev))
                adev->in_s3 = true;
-       if (!adev->in_s0ix && !adev->in_s3)
+       if (!adev->in_s0ix && !adev->in_s3) {
+               /* don't allow going deep first time followed by s2idle the next time */
+               if (adev->last_suspend_state != PM_SUSPEND_ON &&
+                   adev->last_suspend_state != pm_suspend_target_state) {
+                       drm_err_once(drm_dev, "Unsupported suspend state %d\n",
+                                    pm_suspend_target_state);
+                       return -EINVAL;
+               }
                return 0;
+       }
+
+       /* cache the state last used for suspend */
+       adev->last_suspend_state = pm_suspend_target_state;
+
        return amdgpu_device_suspend(drm_dev, true);
 }