Since commit 843049bac7c0 ("drm/amd/display: Split DPMS ON into
parts"), link_set_dpms_on_enable_link() returns
DC_DPMS_FAILED_HANDSHAKE when enable_link() fails and the stream
enable has to be aborted: any failure other than link training, or a
link training failure on DP MST. The link has already been disabled at
that point. The step loop in link_set_dpms_on() treats
DC_DPMS_FAILED_HANDSHAKE like DC_DPMS_SUCCESS and goes on to
link_set_dpms_on_post_enable_link().

Before the split, this path returned right after disable_link(),
because MST displays can't proceed without link training. Now, for
failed MST handshakes MST slots are still allocated.  When the link
trains again later, the new payload starts after the leaked slots so
ACT never completes, and the display stays black until
reboot. Replugging or power-cycling the monitor does not recover it.

Seen on Navi 33 (DCN 3.2.1) with a DP 2.1 MST monitor (Odyssey Neo G9)
at UHBR10 x4 with DSC. Link training sometimes fails on DPMS
wake. With this change, the failed attempt leaves no payload behind,
and the next modeset after the sink reconnects bring the monito back
up.

Return early on DC_DPMS_FAILED_HANDSHAKE, as for
DC_DPMS_SKIPPED_HANDSHAKE. This restores the pre-split behaviour. Link
training failures on non-MST signals still return DC_DPMS_SUCCESS and
continue as before.

Closes: https://gitlab.freedesktop.org/drm/amd/-/work_items/6047
Fixes: 843049bac7c0 ("drm/amd/display: Split DPMS ON into parts")
Cc: [email protected] # 7.3
Signed-off-by: Abdulla Bubshait <[email protected]>
---
 drivers/gpu/drm/amd/display/dc/link/link_dpms.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c 
b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
index 75e232ebffe8..b355e29b178d 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -2813,11 +2813,11 @@ enum dc_status link_set_dpms_on(
 
                switch (step_result) {
                case DC_DPMS_SUCCESS:
-               case DC_DPMS_FAILED_HANDSHAKE:
                        // Enum is ordered from "best" to "worst" results
                        result = max(result, step_result);
                        break;
 
+               case DC_DPMS_FAILED_HANDSHAKE:
                case DC_DPMS_SKIPPED_HANDSHAKE:
                        return step_result;
 
-- 
2.56.0

Reply via email to