]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
drm/amd/display: Fix mem_type change detection for async flips
authorMatthew Schwartz <matthew.schwartz@linux.dev>
Thu, 11 Jun 2026 15:44:38 +0000 (08:44 -0700)
committerAlex Deucher <alexander.deucher@amd.com>
Wed, 17 Jun 2026 22:17:33 +0000 (18:17 -0400)
[Why]
amdgpu_dm_crtc_mem_type_changed() fetches the "old" and "new" plane state
with two drm_atomic_get_plane_state() calls, which both return the new
state. It compares a state against itself, so it never detects a mem_type
change and never rejects the async flip.

On DCN 3.0.1, this shows up as intermittent corruption when a single DCC
plane is scanned out with immediate flips under gamescope and its buffer
moves between the VRAM carveout and GTT.

[How]
Use drm_atomic_get_old_plane_state() and drm_atomic_get_new_plane_state()
to compare the actual old and new states. These return NULL rather than
an error pointer for a plane that is not part of the commit, so the
IS_ERR() check becomes a NULL check that skips those planes, such as an
unmodified cursor still in the CRTC's plane_mask.

Fixes: 4caacd1671b7 ("drm/amd/display: Do not elevate mem_type change to full update")
Reviewed-by: Harry Wentland <harry.wentland@amd.com>
Reviewed-by: Melissa Wen <mwen@igalia.com>
Signed-off-by: Matthew Schwartz <matthew.schwartz@linux.dev>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
(cherry picked from commit 13158e5dbd896281f3e9982b5437cffa5fd621b2)

drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c

index 1ed697a3a4532d596954d3985637ce88f23ebfdc..eb5696b5daeb7999617851848234d4edf07a77c1 100644 (file)
@@ -12938,13 +12938,11 @@ static bool amdgpu_dm_crtc_mem_type_changed(struct drm_device *dev,
        struct drm_plane_state *new_plane_state, *old_plane_state;
 
        drm_for_each_plane_mask(plane, dev, crtc_state->plane_mask) {
-               new_plane_state = drm_atomic_get_plane_state(state, plane);
-               old_plane_state = drm_atomic_get_plane_state(state, plane);
+               new_plane_state = drm_atomic_get_new_plane_state(state, plane);
+               old_plane_state = drm_atomic_get_old_plane_state(state, plane);
 
-               if (IS_ERR(new_plane_state) || IS_ERR(old_plane_state)) {
-                       drm_err(dev, "Failed to get plane state for plane %s\n", plane->name);
-                       return false;
-               }
+               if (!old_plane_state || !new_plane_state)
+                       continue;
 
                if (old_plane_state->fb && new_plane_state->fb &&
                    get_mem_type(old_plane_state->fb) != get_mem_type(new_plane_state->fb))