[PATCH 1/3] drm/amd/display: fix NULL stream deref on MST DPMS-off
From: Arthur Liberman
Date: Tue Sep 22 2026 - 12:07:50 EST
>From dff1f3ce5f313dc88503c1da01c959638b7d42e4 Mon Sep 17 00:00:00 2001
Message-ID: <dff1f3ce5f313dc88503c1da01c959638b7d42e4.1790083445.git.arthur_liberman@xxxxxxxxxxx>
In-Reply-To: <cover.1790083445.git.arthur_liberman@xxxxxxxxxxx>
References: <cover.1790083445.git.arthur_liberman@xxxxxxxxxxx>
From: Arthur Liberman <arthur_liberman@xxxxxxxxxxx>
Date: Mon, 21 Sep 2026 01:41:20 +0300
Subject: [PATCH 1/3] drm/amd/display: fix NULL stream deref on MST DPMS-off
dc_stream_get_status() and dc_stream_get_status_const() load
stream->ctx with no NULL check. HPD detect of an MST daisy-chain
reaches them from link_set_all_streams_dpms_off_for_link() through
dc_commit_updates_for_stream(). On 6.13 that oopsed when the first
full update released current_state and the next loop iteration passed
the cleared pipe stream:
BUG: unable to handle page fault for address: 0000000000006460
RIP: dc_stream_get_status
Call Trace:
update_planes_and_stream_v1
dc_commit_updates_for_stream
link_set_all_streams_dpms_off_for_link
link_detect
handle_hpd_irq_helper
Commit 1561782686cc ("drm/amd/display: fix link_set_dpms_off
multi-display MST corner case") caches those pointers before the
loop, so the loop no longer re-reads the cleared pipe_ctx. The
helpers still oops if a caller passes NULL.
Return NULL when stream is NULL, and skip a NULL cached entry in
the DPMS-off loop.
Fixes: 09f609c34fc8 ("drm/amd/display: Fix driver load crash in amdgpu_dm")
Cc: stable@xxxxxxxxxxxxxxx
Assisted-by: Cursor:xai-grok-4.6
Signed-off-by: Arthur Liberman <arthur_liberman@xxxxxxxxxxx>
---
drivers/gpu/drm/amd/display/dc/core/dc_stream.c | 14 ++++++++++++--
drivers/gpu/drm/amd/display/dc/link/link_dpms.c | 7 +++++++
2 files changed, 19 insertions(+), 2 deletions(-)
diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
index 8d3aacc7b96c..e5134c103bdb 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_stream.c
@@ -267,14 +267,24 @@ struct dc_stream_state *dc_copy_stream(const struct dc_stream_state *stream)
struct dc_stream_status *dc_stream_get_status(
struct dc_stream_state *stream)
{
- struct dc *dc = stream->ctx->dc;
+ struct dc *dc;
+
+ if (!stream)
+ return NULL;
+
+ dc = stream->ctx->dc;
return dc_state_get_stream_status(dc->current_state, stream);
}
const struct dc_stream_status *dc_stream_get_status_const(
const struct dc_stream_state *stream)
{
- struct dc *dc = stream->ctx->dc;
+ struct dc *dc;
+
+ if (!stream)
+ return NULL;
+
+ dc = stream->ctx->dc;
return dc_state_get_stream_status(dc->current_state, stream);
}
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 48b086d15ab0..17cb831ce8c4 100644
--- a/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
+++ b/drivers/gpu/drm/amd/display/dc/link/link_dpms.c
@@ -177,6 +177,13 @@ void link_set_all_streams_dpms_off_for_link(struct dc_link *link)
streams[i] = pipes[i]->stream;
for (i = 0; i < count; i++) {
+ /* A full update can release current_state and NULL remaining
+ * pipe streams. MST daisy-chains have multiple streams on one
+ * link, so skip any that disappeared mid-loop.
+ */
+ if (!streams[i])
+ continue;
+
stream_update.stream = streams[i];
dc_commit_updates_for_stream(link->ctx->dc, NULL, 0,
streams[i], &stream_update,
--
2.55.0