Skip to contentSkip to conversation

FAILED: patch "[PATCH] drm/amd/display: Exit idle optimizations before programming" failed to apply to 7.1-stable tree

PATCH In review [email protected] 3 participants 7 messages Aug 5 – Aug 7

Subsystems (4)
lore
Share & tools
lore

[email protected]

author maintainer
#0 lore raw

The patch below does not apply to the 7.1-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.

To reproduce the conflict and resubmit, you may use the following commands:

git fetch https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git/ linux-7.1.y
git checkout FETCH_HEAD
git cherry-pick -x 8419331e64d92a8de5fc4feef0e305f201fb8b33
# <resolve conflicts, build, test, etc.>
git commit -s
git send-email --to '<[email protected]>' --in-reply-to '2026080547-scoff-that-5ce1@gregkh' --subject-prefix 'PATCH 7.1.y' 'HEAD^..'

Possible dependencies:

thanks,

greg k-h

------------------ original commit in Linus's tree ------------------

From 8419331e64d92a8de5fc4feef0e305f201fb8b33 Mon Sep 17 00:00:00 2001
From: Leo Li <[email protected]>
Date: Tue, 28 Jul 2026 13:02:47 -0400
Subject: [PATCH] drm/amd/display: Exit idle optimizations before programming

[Why]

We need to exit PSR/IPS before programming. Before calling DC for programming in amdgpu_dm_commit_planes(), there's a vblank_control_workqueue flush. This waits for IPS and PSR exit. (See drm_vblank_on/off() > amdgpu_dm_crtc_set_vblank() --queue_work()-> amdgpu_dm_crtc_vblank_control_worker())

Prior to the tagged "Fixes:" change, drm_vblank_get() was called before the workqueue flush. This ordering ensures that PSR exit occurred before programming. After the "Fixes:" change, drm_vblank_get() is called after the workqueue flush, leading to programming while idle optimizations are still active. This can lead to incorrect flip_pending detection used by vblank event delivery.

[How]

Split the vblank_get() component of dm_arm_vblank_event() into dm_arm_vblank_event_pre_programming(), which is called before programming. Call it before the vblank_control_workqueue flush.

Includes a drive-by cleanup of prepare_flip_isr(): the only caller is dm_arm_vblank_event() and it's simple enough to roll-in.

v2: Fix checkpatch formatting warning on
drm_arm_vblank_event_pre_programming() arg alignment.

Fixes 48ab86360af1 ("drm/amd/display: check GRPH_FLIP status before sending event")
Assisted-by Codex:gpt-5.6-sol
Assisted-by Claude:opus-5
(cherry picked from commit 05984e29520a28c27f5a2388742c957a6a87ee7a)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +46 -32
index eaf19ec843e8..1820547b1dde 100644
@@ -9903,25 +9903,6 @@ static void remove_stream(struct amdgpu_device *adev,
 	acrtc->enabled = false;
 }
 
-static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
-{
-
-	assert_spin_locked(&acrtc->base.dev->event_lock);
-	WARN_ON(acrtc->event);
-
-	acrtc->event = acrtc->base.state->event;
-
-	/* Set the flip status */
-	acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
-
-	/* Mark this event as consumed */
-	acrtc->base.state->event = NULL;
-
-	drm_dbg_state(acrtc->base.dev,
-		      "crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
-		      acrtc->crtc_id);
-}
-
 static void update_freesync_state_on_stream(
 	struct amdgpu_display_manager *dm,
 	struct dm_crtc_state *new_crtc_state,
@@ -10274,17 +10255,47 @@ static void dm_arm_vblank_event(struct amdgpu_crtc *acrtc,
 		return;
 
 	if (pflip_update) {
-		drm_crtc_vblank_get(&acrtc->base);
 		WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE);
-		/* Arm flip completion handling and event delivery after programming. */
-		prepare_flip_isr(acrtc);
+		WARN_ON(acrtc->event);
+
+		acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
+		acrtc->event = acrtc->base.state->event;
+		acrtc->base.state->event = NULL;
+
+		drm_dbg_state(acrtc->base.dev,
+			      "crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
+			      acrtc->crtc_id);
 	} else if (cursor_update) {
-		drm_crtc_vblank_get(&acrtc->base);
 		acrtc->event = acrtc->base.state->event;
 		acrtc->base.state->event = NULL;
 	}
 }
 
+/**
+ * dm_arm_vblank_event_pre_programming - Prepare for programming
+ * @acrtc: The amdgpu CRTC to prepare
+ * @acrtc_state: The new CRTC state
+ * @pflip_update: Whether a page flip is being programmed
+ * @cursor_update: Whether a cursor update is being programmed
+ *
+ * Grab a reference on the vblank counter if a page flip or cursor update is to
+ * be programmed. Do this before programming so the HW is not in any
+ * idle-optimized state (such as PSR).
+ */
+static void dm_arm_vblank_event_pre_programming(struct amdgpu_crtc *acrtc,
+						struct dm_crtc_state *acrtc_state,
+						bool pflip_update,
+						bool cursor_update)
+{
+	assert_spin_locked(&acrtc->base.dev->event_lock);
+
+	if (!acrtc->base.state->event || acrtc_state->active_planes == 0)
+		return;
+
+	if (pflip_update || cursor_update)
+		drm_crtc_vblank_get(&acrtc->base);
+}
+
 static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
 				    struct drm_device *dev,
 				    struct amdgpu_display_manager *dm,
@@ -10550,16 +10561,19 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_commit *state,
 		}
 	}
 
-	/*
-	 * DCE depends on a combination of GRPH_FLIP, VLINE0, and VUPDATE for
-	 * event delivery. Only GRPH_FLIP handler can send pflip events, and it
-	 * only fires if HW latched to the flip. Maintain legacy behavior by
-	 * arming event before programming.
-	 */
-	if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) {
-		scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) {
+	scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) {
+		dm_arm_vblank_event_pre_programming(acrtc_attach, acrtc_state,
+						    pflip_present,
+						    cursor_update);
+		/*
+		 * DCE depends on a combination of GRPH_FLIP, VLINE0, and
+		 * VUPDATE for event delivery. Only GRPH_FLIP handler can send
+		 * pflip events, and it only fires if HW latched to the flip.
+		 * Maintain legacy behavior by arming event before programming.
+		 */
+		if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) {
 			dm_arm_vblank_event(acrtc_attach, acrtc_state,
-					pflip_present, cursor_update);
+					    pflip_present, cursor_update);
 		}
 	}
 
#1 lore raw

PATCH 1/1 drm/amd/display: Exit idle optimizations before programming

From: Leo Li <[email protected]>

[Why]

We need to exit PSR/IPS before programming. Before calling DC for programming in amdgpu_dm_commit_planes(), there's a vblank_control_workqueue flush. This waits for IPS and PSR exit. (See drm_vblank_on/off() > amdgpu_dm_crtc_set_vblank() --queue_work()-> amdgpu_dm_crtc_vblank_control_worker())

Prior to the tagged "Fixes:" change, drm_vblank_get() was called before the workqueue flush. This ordering ensures that PSR exit occurred before programming. After the "Fixes:" change, drm_vblank_get() is called after the workqueue flush, leading to programming while idle optimizations are still active. This can lead to incorrect flip_pending detection used by vblank event delivery.

[How]

Split the vblank_get() component of dm_arm_vblank_event() into dm_arm_vblank_event_pre_programming(), which is called before programming. Call it before the vblank_control_workqueue flush.

Includes a drive-by cleanup of prepare_flip_isr(): the only caller is dm_arm_vblank_event() and it's simple enough to roll-in.

v2: Fix checkpatch formatting warning on
drm_arm_vblank_event_pre_programming() arg alignment.

Fixes 48ab86360af1 ("drm/amd/display: check GRPH_FLIP status before sending event")
Assisted-by Codex:gpt-5.6-sol
Assisted-by Claude:opus-5
(cherry picked from commit 05984e29520a28c27f5a2388742c957a6a87ee7a)
(cherry picked from commit 8419331e64d92a8de5fc4feef0e305f201fb8b33)
---
 .../gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c | 78 +++++++++++--------
 1 file changed, 46 insertions(+), 32 deletions(-)
drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm.c +46 -32
index 11affddbb2650..40d82a3eeec05 100644
@@ -9656,25 +9656,6 @@ static void remove_stream(struct amdgpu_device *adev,
 	acrtc->enabled = false;
 }
 
-static void prepare_flip_isr(struct amdgpu_crtc *acrtc)
-{
-
-	assert_spin_locked(&acrtc->base.dev->event_lock);
-	WARN_ON(acrtc->event);
-
-	acrtc->event = acrtc->base.state->event;
-
-	/* Set the flip status */
-	acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
-
-	/* Mark this event as consumed */
-	acrtc->base.state->event = NULL;
-
-	drm_dbg_state(acrtc->base.dev,
-		      "crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
-		      acrtc->crtc_id);
-}
-
 static void update_freesync_state_on_stream(
 	struct amdgpu_display_manager *dm,
 	struct dm_crtc_state *new_crtc_state,
@@ -10023,17 +10004,47 @@ static void dm_arm_vblank_event(struct amdgpu_crtc *acrtc,
 		return;
 
 	if (pflip_update) {
-		drm_crtc_vblank_get(&acrtc->base);
 		WARN_ON(acrtc->pflip_status != AMDGPU_FLIP_NONE);
-		/* Arm flip completion handling and event delivery after programming. */
-		prepare_flip_isr(acrtc);
+		WARN_ON(acrtc->event);
+
+		acrtc->pflip_status = AMDGPU_FLIP_SUBMITTED;
+		acrtc->event = acrtc->base.state->event;
+		acrtc->base.state->event = NULL;
+
+		drm_dbg_state(acrtc->base.dev,
+			      "crtc:%d, pflip_stat:AMDGPU_FLIP_SUBMITTED\n",
+			      acrtc->crtc_id);
 	} else if (cursor_update) {
-		drm_crtc_vblank_get(&acrtc->base);
 		acrtc->event = acrtc->base.state->event;
 		acrtc->base.state->event = NULL;
 	}
 }
 
+/**
+ * dm_arm_vblank_event_pre_programming - Prepare for programming
+ * @acrtc: The amdgpu CRTC to prepare
+ * @acrtc_state: The new CRTC state
+ * @pflip_update: Whether a page flip is being programmed
+ * @cursor_update: Whether a cursor update is being programmed
+ *
+ * Grab a reference on the vblank counter if a page flip or cursor update is to
+ * be programmed. Do this before programming so the HW is not in any
+ * idle-optimized state (such as PSR).
+ */
+static void dm_arm_vblank_event_pre_programming(struct amdgpu_crtc *acrtc,
+						struct dm_crtc_state *acrtc_state,
+						bool pflip_update,
+						bool cursor_update)
+{
+	assert_spin_locked(&acrtc->base.dev->event_lock);
+
+	if (!acrtc->base.state->event || acrtc_state->active_planes == 0)
+		return;
+
+	if (pflip_update || cursor_update)
+		drm_crtc_vblank_get(&acrtc->base);
+}
+
 static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
 				    struct drm_device *dev,
 				    struct amdgpu_display_manager *dm,
@@ -10301,16 +10312,19 @@ static void amdgpu_dm_commit_planes(struct drm_atomic_state *state,
 		}
 	}
 
-	/*
-	 * DCE depends on a combination of GRPH_FLIP, VLINE0, and VUPDATE for
-	 * event delivery. Only GRPH_FLIP handler can send pflip events, and it
-	 * only fires if HW latched to the flip. Maintain legacy behavior by
-	 * arming event before programming.
-	 */
-	if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) {
-		scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) {
+	scoped_guard(spinlock_irqsave, &pcrtc->dev->event_lock) {
+		dm_arm_vblank_event_pre_programming(acrtc_attach, acrtc_state,
+						    pflip_present,
+						    cursor_update);
+		/*
+		 * DCE depends on a combination of GRPH_FLIP, VLINE0, and
+		 * VUPDATE for event delivery. Only GRPH_FLIP handler can send
+		 * pflip events, and it only fires if HW latched to the flip.
+		 * Maintain legacy behavior by arming event before programming.
+		 */
+		if (amdgpu_ip_version(dm->adev, DCE_HWIP, 0) == 0) {
 			dm_arm_vblank_event(acrtc_attach, acrtc_state,
-					pflip_present, cursor_update);
+					    pflip_present, cursor_update);
 		}
 	}
 
Signature · 1 line
2.54.0
maintainer
#2 lore raw

Re: [PATCH 7.1.y] drm/amd/display: Exit idle optimizations before programming

This doesn't apply cleanly to 7.1?

Signature · 2 lines
Thanks,
Sasha
maintainer
#3 lore raw

Re: [PATCH 7.1.y] drm/amd/display: Exit idle optimizations before programming

Quoted 2 lines · Sasha Levin

This doesn't apply cleanly to 7.1?

Hi Sasha,

Looks like the tagged "Fixes:" hasn't landed in 7.1 yet. This patch depends on it.
See the 7.1 backport of it here: https://lore.kernel.org/stable/[email protected]/

Thanks,
Leo

author maintainer
#4 lore raw

Re: [PATCH 7.1.y] drm/amd/display: Exit idle optimizations before programming

Quoted 10 lines · Leo Li
Quoted 2 lines · Sasha Levin

This doesn't apply cleanly to 7.1?

Hi Sasha,

Looks like the tagged "Fixes:" hasn't landed in 7.1 yet. This patch depends on it.
See the 7.1 backport of it here: https://lore.kernel.org/stable/[email protected]/

So what are we supposed to do here?

maintainer
#5 lore raw

Re: [PATCH 7.1.y] drm/amd/display: Exit idle optimizations before programming

Quoted 7 lines · Greg KH
Quoted 6 lines · Leo Li
Quoted 2 lines · Sasha Levin

This doesn't apply cleanly to 7.1?

Quoted 6 lines
Quoted 4 lines

Hi Sasha,

Looks like the tagged "Fixes:" hasn't landed in 7.1 yet. This patch depends on it.
See the 7.1 backport of it here: https://lore.kernel.org/stable/[email protected]/

So what are we supposed to do here?

Hi Greg,

The two remaining fixes for 7.1 and 6.18 are this patch, and

[PATCH 7.1.y] drm/amd/display: check GRPH_FLIP status before sending event

    https://lore.kernel.org/stable/[email protected]/

[PATCH 6.18.y] drm/amd/display: check GRPH_FLIP status before sending event

    https://lore.kernel.org/stable/[email protected]/

Looks like Sasha queued them just now:
https://lore.kernel.org/stable/[email protected]/

Thanks, and sorry for the confusion!
Leo

maintainer
#6 lore raw

Re: [PATCH 7.1.y] drm/amd/display: Exit idle optimizations before programming

In reply to [email protected]
Quoted 5 lines · On Wed, Aug 05, 2026 at 12:33:14PM -0400, [email protected] wrote:

Prior to the tagged "Fixes:" change, drm_vblank_get() was called before the workqueue flush. This ordering ensures that PSR exit occurred before programming. After the "Fixes:" change, drm_vblank_get() is called after the workqueue flush, leading to programming while idle optimizations are still active.

Queued for 7.1 and 6.18, with the "check GRPH_FLIP status before sending event" prerequisite applied ahead of it on both trees, thanks.

Signature · 2 lines
Thanks,
Sasha