summaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm
diff options
context:
space:
mode:
authorSimon Polack <spolack+git@mailbox.org>2026-09-17 12:42:34 +0200
committerAlex Deucher <alexander.deucher@amd.com>2026-10-01 17:18:05 -0400
commitb76a5b7bee22556914f7cde210f695ef162d81bf (patch)
treeb4207346e6416fc0ab6e55ff2b6c29205bfc988a /drivers/gpu/drm
parentde1eab13efef83fd2b76f4688de5bf672644596f (diff)
downloadlinux-stable-b76a5b7bee22556914f7cde210f695ef162d81bf.tar.gz
linux-stable-b76a5b7bee22556914f7cde210f695ef162d81bf.zip
drm/amd/display: Fix stale replay_events after mod_power stream removal
[Why] mod_power_remove_stream() shifts the remaining power_entity slots down but does not move replay_events, and mod_power_add_stream() does not initialize it. replay_events therefore stay bound to the map slot instead of the stream. When several streams are disabled in one atomic commit, amdgpu_dm_mod_power_update_streams() removes them one after another. The eDP stream can then be looked up in a slot whose stale replay_events already have replay_event_hw_programming set, so amdgpu_dm_replay_set_event() returns early ("already in desired state") without calling mod_power_set_replay_event(). Replay is not disabled before the eDP panel is powered off. After DPMS on, the sink reports neither replay state nor frame lock (DPCD 0x378 = 0x00, no error bits), so the HPD IRQ recovery does not trigger and the panel stays black until a full modeset. Seen with an eDP panel using FreeSync Replay plus two DP-MST displays: DPMS off/on of all outputs leaves eDP black, while DPMS of eDP alone works. Doing an eDP-only DPMS first makes the next all-output DPMS fail reliably. [How] Shift replay_events together with the PSR cached fields in mod_power_remove_stream() and initialize it to replay_event_vsync in mod_power_add_stream(), matching the psr_event_vsync initial value used for PSR (both vsync events are driven together by amdgpu_dm_crtc_set_static_screen_optimze()). Tested on 7.3.0-rc3 (238650ef6c7c): the reproducer above now recovers reliably, and Replay still engages when the screen is idle. The issue was debugged with help from an AI assistant (Claude), which analysed ftrace/kprobe traces and the driver source, pointed to the missing replay_events handling and suggested this change. I collected the traces and built and tested the fix on the affected hardware. Fixes: 4cef2ac4c795 ("drm/amd/display: Introduce power module on Linux") Assisted-by: Claude:claude-opus-5 Signed-off-by: Simon Polack <spolack+git@mailbox.org> Reviewed-by: Ray Wu <ray.wu@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com> (cherry picked from commit 3d47e38e271195435e125527b224d11cfdb777b1) Cc: stable@vger.kernel.org
Diffstat (limited to 'drivers/gpu/drm')
-rw-r--r--drivers/gpu/drm/amd/display/modules/power/power.c2
1 files changed, 2 insertions, 0 deletions
diff --git a/drivers/gpu/drm/amd/display/modules/power/power.c b/drivers/gpu/drm/amd/display/modules/power/power.c
index 2f9690e65..d900be8cb 100644
--- a/drivers/gpu/drm/amd/display/modules/power/power.c
+++ b/drivers/gpu/drm/amd/display/modules/power/power.c
@@ -328,6 +328,7 @@ bool mod_power_add_stream(struct mod_power *mod_power,
core_power->map[core_power->num_entities].psr_enabled = 0;
core_power->map[core_power->num_entities].psr_events = psr_event_vsync;
core_power->map[core_power->num_entities].psr_power_opt = 0;
+ core_power->map[core_power->num_entities].replay_events = replay_event_vsync;
core_power->num_entities++;
return true;
}
@@ -387,6 +388,7 @@ bool mod_power_remove_stream(struct mod_power *mod_power,
core_power->map[i].psr_enabled = core_power->map[i + 1].psr_enabled;
core_power->map[i].psr_events = core_power->map[i + 1].psr_events;
core_power->map[i].psr_power_opt = core_power->map[i + 1].psr_power_opt;
+ core_power->map[i].replay_events = core_power->map[i + 1].replay_events;
memcpy(core_power->map[i].psr_context, core_power->map[i + 1].psr_context, sizeof(struct mod_power_psr_context));
memset(core_power->map[i + 1].psr_context, 0, sizeof(struct mod_power_psr_context));