Hi,
On DCE8-class ASICs (e.g. Bonaire), the resource pool contains digital DIG
stream encoders plus one analog DAC encoder. When assigning a stream
encoder for a second DisplayPort MST stream, if the preferred digital
encoder is already acquired,
dce100_find_first_free_match_stream_enc_for_link() falls back to the first
free pool entry. That entry may be the analog encoder, whose funcs table
lacks DP hooks such as dp_set_stream_attribute. The subsequent atomic
commit then dereferences NULL function pointers in link_set_dpms_on() and
crashes.

Skip encoders without dp_set_stream_attribute when the stream uses a DP
signal (including MST). Use dc_is_dp_signal(stream->signal) for the MST
fallback path instead of checking only the link connector signal.

Tested on:
- GPU: AMD Radeon R7 260X (Bonaire / DCE8)
- Board: Supermicro C9X299-PG300
- Setup: DP MST daisy chain, either hotplug second monitor or have it
connected on boot
- Kernel: 7.1.3 (issue observed since 6.19)
- Result: kernel oops without patch; dual monitors stable with patch

Thanks,
Andriy Korud
From d77178fe6f2cbf54f6be8c1e3c49108849e53eba Mon Sep 17 00:00:00 2001
From: Andriy Korud <[email protected]>
Date: Thu, 9 Jul 2026 19:27:34 +0200
Subject: [PATCH drm-amd] drm/amd/display: dce100: skip non-DP stream encoders
 for DP MST On DCE8-class ASICs (e.g. Bonaire), the resource pool contains
 digital DIG stream encoders plus one analog DAC encoder. When assigning an
 encoder for a second DisplayPort MST stream, if the preferred digital encoder
 is already acquired, dce100_find_first_free_match_stream_enc_for_link() falls
 back to the first free pool entry. That entry may be the analog encoder,
 whose funcs table lacks DP hooks (dp_set_stream_attribute, etc.). The
 subsequent atomic commit then dereferences NULL function pointers in
 link_set_dpms_on() and crashes. Skip encoders without dp_set_stream_attribute
 when the stream uses a DP signal (including MST). Use
 dc_is_dp_signal(stream->signal) for the MST fallback path instead of checking
 only the link connector signal. Reproduced on Radeon R7 260X (Bonaire) with
 DP MST hotplug of a second monitor on Linux 6.19+.

Signed-off-by: Andriy Korud <[email protected]>
---
 .../drm/amd/display/dc/resource/dce100/dce100_resource.c | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c
index b92d4f378d60..beaf2e654672 100644
--- a/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c
+++ b/drivers/gpu/drm/amd/display/dc/resource/dce100/dce100_resource.c
@@ -29,6 +29,7 @@
 #include "stream_encoder.h"
 
 #include "resource.h"
+#include "signal_types.h"
 #include "clk_mgr.h"
 #include "include/irq_service_interface.h"
 #include "dio/virtual/virtual_stream_encoder.h"
@@ -992,6 +993,12 @@ struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link(
 	for (i = 0; i < pool->stream_enc_count; i++) {
 		if (!res_ctx->is_stream_enc_acquired[i] &&
 				pool->stream_enc[i]) {
+			/* DP/MST needs a digital encoder; skip analog/no-DP encoders */
+			if (dc_is_dp_signal(stream->signal) &&
+			    (!pool->stream_enc[i]->funcs ||
+			     !pool->stream_enc[i]->funcs->dp_set_stream_attribute))
+				continue;
+
 			/* Store first available for MST second display
 			 * in daisy chain use case
 			 */
@@ -1014,7 +1021,7 @@ struct stream_encoder *dce100_find_first_free_match_stream_enc_for_link(
 	 * required for non DP connectors.
 	 */
 
-	if (j >= 0 && link->connector_signal == SIGNAL_TYPE_DISPLAY_PORT)
+	if (j >= 0 && dc_is_dp_signal(stream->signal))
 		return pool->stream_enc[j];
 
 	return NULL;
-- 
2.55.0

Reply via email to