[PATCH] drm/amd/display: avoid NULL hubp deref when filling mpcc_id on DCE

Honglei Huang <[email protected]> Wed, 5 Aug 2026 09:23:50 +0800
Newsgroups gmane.comp.freedesktop.amd-gfx,gmane.comp.video.dri.devel
Message-ID <[email protected]>
HUBP only exists on DCN. On ASICs that use DCE, such as Vega20, the display
pipe never owns a HUBP, so pipe_ctx->plane_res.hubp stays NULL.

The block sequence rework now fills mpcc_id inside the generic helpers in
dc_hw_sequencer.c by reading pipe_ctx->plane_res.hubp->inst. On a DCE ASIC
that read follows the NULL pointer and faults at offset 0x88, where the
inst field sits in struct hubp, and the box dies on the first modeset:

  BUG: kernel NULL pointer dereference, address: 0000000000000088
  #PF: supervisor read access in kernel mode
  Oops: 0000 [#1] SMP NOPTI
  CPU: 14 UID: 0 PID: 531 Comm: plymouthd Not tainted 7.1.0 #70
  RIP: 0010:hwss_set_output_transfer_func+0x69/0xc0 [amdgpu]
  Call Trace:
   dce110_program_front_end_for_pipe+0x4d7/0x5c0 [amdgpu]
   dce110_apply_ctx_for_surface+0xf1/0x270 [amdgpu]
   commit_planes_for_stream+0xba1/0x1c80 [amdgpu]
   update_planes_and_stream_v2+0x297/0x6f0 [amdgpu]
   dc_update_state_prepare+0x6f/0x1c0 [amdgpu]
   dc_update_state+0x41/0x60 [amdgpu]
   dc_update_planes_and_stream+0x43/0x70 [amdgpu]
   amdgpu_dm_atomic_commit_tail+0x1a6f/0x4120 [amdgpu]
   commit_tail+0xc5/0x1a0
   drm_atomic_helper_commit+0x137/0x160
   drm_atomic_commit+0xaf/0xf0
   drm_client_modeset_commit_atomic+0x1ec/0x230
   drm_client_modeset_commit_locked+0x5b/0x170
   drm_client_modeset_commit+0x27/0x50
   __drm_fb_helper_restore_fbdev_mode_unlocked+0xe8/0x110
   drm_fbdev_client_restore+0x12/0x20
   drm_client_dev_restore+0xbb/0x100

DCE never uses mpcc_id, so 0 is a fine value when there is no HUBP. Add a
small helper that returns the HUBP instance, or 0 when it is missing, and
use it for every mpcc_id assignment. DCN is unchanged since HUBP is always
there.

Fixes: f879f53407f0 ("drm/amd/display: Refactor DPP_SET_OUTPUT_TRANSFER_FUNC to drop pipe_ctx")
Fixes: 9403e15b2ab1 ("drm/amd/display: Refactor DPP_PROGRAM_GAMUT_REMAP to drop pipe_ctx param")
Cc: Tomasz Siemek <[email protected]>
Cc: Wayne Lin <[email protected]>
Cc: Alvin Lee <[email protected]>
Signed-off-by: Honglei Huang <[email protected]>
---
 .../drm/amd/display/dc/core/dc_hw_sequencer.c | 26 +++++++++++++------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
index 11411fa946..7676aa4485 100644
--- a/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
+++ b/drivers/gpu/drm/amd/display/dc/core/dc_hw_sequencer.c
@@ -729,6 +729,16 @@ void get_fams2_visual_confirm_color(
 	}
 }
 
+/*
+ * Return the MPCC instance for a pipe. On DCN it matches the HUBP instance.
+ * DCE has no HUBP and ignores mpcc_id, so return 0 there instead of chasing a
+ * NULL pointer.
+ */
+static int hwss_pipe_mpcc_id(const struct pipe_ctx *pipe_ctx)
+{
+	return pipe_ctx->plane_res.hubp ? pipe_ctx->plane_res.hubp->inst : 0;
+}
+
 void hwss_build_fast_sequence(struct dc *dc,
 		struct dc_dmub_cmd *dc_dmub_cmd,
 		unsigned int dmub_cmd_count,
@@ -1073,7 +1083,7 @@ void hwss_build_fast_sequence(struct dc *dc,
 					params->dpp = current_mpc_pipe->plane_res.dpp;
 					params->mpc = dc->res_pool->mpc;
 					params->xfm = current_mpc_pipe->plane_res.xfm;
-					params->mpcc_id = current_mpc_pipe->plane_res.hubp->inst;
+					params->mpcc_id = hwss_pipe_mpcc_id(current_mpc_pipe);
 					params->plane = current_mpc_pipe->plane_state;
 					params->stream = current_mpc_pipe->stream;
 					params->is_top_pipe = current_mpc_pipe->top_pipe == NULL;
@@ -1118,7 +1128,7 @@ void hwss_build_fast_sequence(struct dc *dc,
 				otf_params->dpp = current_mpc_pipe->plane_res.dpp;
 				otf_params->xfm = current_mpc_pipe->plane_res.xfm;
 				otf_params->mpc = dc->res_pool->mpc;
-				otf_params->mpcc_id = current_mpc_pipe->plane_res.hubp->inst;
+				otf_params->mpcc_id = hwss_pipe_mpcc_id(current_mpc_pipe);
 				otf_params->is_top_pipe = resource_is_pipe_type(current_mpc_pipe, OPP_HEAD);
 				otf_params->stream = current_mpc_pipe->stream;
 				block_sequence[*num_steps].func = DPP_SET_OUTPUT_TRANSFER_FUNC;
@@ -1128,13 +1138,13 @@ void hwss_build_fast_sequence(struct dc *dc,
 				dc->hwss.update_visual_confirm_color) {
 				block_sequence[*num_steps].params.update_visual_confirm_params.dc = dc;
 				block_sequence[*num_steps].params.update_visual_confirm_params.pipe_ctx = current_mpc_pipe;
-				block_sequence[*num_steps].params.update_visual_confirm_params.mpcc_id = current_mpc_pipe->plane_res.hubp->inst;
+				block_sequence[*num_steps].params.update_visual_confirm_params.mpcc_id = hwss_pipe_mpcc_id(current_mpc_pipe);
 				block_sequence[*num_steps].func = MPC_UPDATE_VISUAL_CONFIRM;
 				(*num_steps)++;
 			}
 			if (current_mpc_pipe->stream->update_flags.bits.out_csc) {
 				block_sequence[*num_steps].params.power_on_mpc_mem_pwr_params.mpc = dc->res_pool->mpc;
-				block_sequence[*num_steps].params.power_on_mpc_mem_pwr_params.mpcc_id = current_mpc_pipe->plane_res.hubp->inst;
+				block_sequence[*num_steps].params.power_on_mpc_mem_pwr_params.mpcc_id = hwss_pipe_mpcc_id(current_mpc_pipe);
 				block_sequence[*num_steps].params.power_on_mpc_mem_pwr_params.power_on = true;
 				block_sequence[*num_steps].func = MPC_POWER_ON_MPC_MEM_PWR;
 				(*num_steps)++;
@@ -1837,7 +1847,7 @@ void hwss_add_dpp_program_gamut_remap(struct block_sequence_state *seq_state,
 		params->xfm = pipe_ctx->plane_res.xfm;
 		params->dpp = pipe_ctx->plane_res.dpp;
 		params->mpc = pipe_ctx->stream->ctx->dc->res_pool->mpc;
-		params->mpcc_id = pipe_ctx->plane_res.hubp->inst;
+		params->mpcc_id = hwss_pipe_mpcc_id(pipe_ctx);
 		params->plane = pipe_ctx->plane_state;
 		params->stream = pipe_ctx->stream;
 		params->is_top_pipe = pipe_ctx->top_pipe == NULL;
@@ -1883,7 +1893,7 @@ void hwss_add_dpp_set_output_transfer_func(struct block_sequence_state *seq_stat
 			.xfm = pipe_ctx->plane_res.xfm,
 			.dpp = pipe_ctx->plane_res.dpp,
 			.mpc = dc->res_pool->mpc,
-			.mpcc_id = pipe_ctx->plane_res.hubp->inst,
+			.mpcc_id = hwss_pipe_mpcc_id(pipe_ctx),
 			.is_top_pipe = resource_is_pipe_type(pipe_ctx, OPP_HEAD),
 			.stream = pipe_ctx->stream,
 		};
@@ -1900,7 +1910,7 @@ void hwss_set_output_transfer_func(struct dc *dc, struct pipe_ctx *pipe_ctx)
 				.xfm = pipe_ctx->plane_res.xfm,
 				.dpp = pipe_ctx->plane_res.dpp,
 				.mpc = dc->res_pool->mpc,
-				.mpcc_id = pipe_ctx->plane_res.hubp->inst,
+				.mpcc_id = hwss_pipe_mpcc_id(pipe_ctx),
 				.is_top_pipe = resource_is_pipe_type(pipe_ctx, OPP_HEAD),
 				.stream = pipe_ctx->stream,
 			}
@@ -3840,7 +3850,7 @@ void hwss_program_gamut_remap(struct pipe_ctx *pipe_ctx)
 			.xfm = pipe_ctx->plane_res.xfm,
 			.dpp = pipe_ctx->plane_res.dpp,
 			.mpc = dc->res_pool->mpc,
-			.mpcc_id = pipe_ctx->plane_res.hubp->inst,
+			.mpcc_id = hwss_pipe_mpcc_id(pipe_ctx),
 			.stream = pipe_ctx->stream,
 			.plane = pipe_ctx->plane_state,
 			.is_top_pipe = pipe_ctx->top_pipe == NULL,
-- 
2.34.1