Commit 64d283cb authored by Jimmy Kizito's avatar Jimmy Kizito Committed by Alex Deucher
Browse files

drm/amd/display: Fix dynamic link encoder access.



[Why]
Assuming DIG link encoders are statically mapped to links can cause
system instability due to null pointer accesses.

[How]
- Add checks for non-null link encoder pointers before trying to access
them.
- When a hardware platform uses dynamic DIG assignment (i.e. resource
function 'link_encs_assign' defined) and a link supports flexible
mapping to DIGs, use the link_enc_cfg API to access the DIG assigned to
a link or stream.

Reviewed-by: default avatarMeenakshikumar Somasundaram <meenakshikumar.somasundaram@amd.com>
Acked-by: default avatarMikita Lipski <mikita.lipski@amd.com>
Signed-off-by: default avatarJimmy Kizito <Jimmy.Kizito@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 035f5496
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -87,7 +87,7 @@ int dcn31_get_active_display_cnt_wa(
		const struct dc_link *link = dc->links[i];

		/* abusing the fact that the dig and phy are coupled to see if the phy is enabled */
		if (link->link_enc->funcs->is_dig_enabled &&
		if (link->link_enc && link->link_enc->funcs->is_dig_enabled &&
				link->link_enc->funcs->is_dig_enabled(link->link_enc))
			display_count++;
	}
+34 −8
Original line number Diff line number Diff line
@@ -3457,6 +3457,10 @@ static enum dc_status deallocate_mst_payload(struct pipe_ctx *pipe_ctx)
static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
{
	struct cp_psp *cp_psp = &pipe_ctx->stream->ctx->cp_psp;
#if defined(CONFIG_DRM_AMD_DC_DCN)
	struct link_encoder *link_enc = NULL;
#endif

	if (cp_psp && cp_psp->funcs.update_stream_config) {
		struct cp_psp_stream_config config = {0};
		enum dp_panel_mode panel_mode =
@@ -3468,8 +3472,21 @@ static void update_psp_stream_config(struct pipe_ctx *pipe_ctx, bool dpms_off)
		config.dig_be = pipe_ctx->stream->link->link_enc_hw_inst;
#if defined(CONFIG_DRM_AMD_DC_DCN)
		config.stream_enc_idx = pipe_ctx->stream_res.stream_enc->id - ENGINE_ID_DIGA;
		config.link_enc_idx = pipe_ctx->stream->link->link_enc->transmitter - TRANSMITTER_UNIPHY_A;
		config.phy_idx = pipe_ctx->stream->link->link_enc->transmitter - TRANSMITTER_UNIPHY_A;
		if (pipe_ctx->stream->link->ep_type == DISPLAY_ENDPOINT_PHY) {
			link_enc = pipe_ctx->stream->link->link_enc;
			config.phy_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
		} else if (pipe_ctx->stream->link->dc->res_pool->funcs->link_encs_assign) {
			/* Use link encoder assignment from current DC state - which may differ from the DC state to be
			 * committed - when updating PSP config.
			 */
			link_enc = link_enc_cfg_get_link_enc_used_by_stream(
					pipe_ctx->stream->link->dc->current_state,
					pipe_ctx->stream);
			config.phy_idx = 0; /* Clear phy_idx for non-physical display endpoints. */
		}
		ASSERT(link_enc);
		if (link_enc)
			config.link_enc_idx = link_enc->transmitter - TRANSMITTER_UNIPHY_A;
		if (is_dp_128b_132b_signal(pipe_ctx)) {
			config.stream_enc_idx = pipe_ctx->stream_res.hpo_dp_stream_enc->id - ENGINE_ID_HPO_DP_0;
			config.link_enc_idx = pipe_ctx->stream->link->hpo_dp_link_enc->inst;
@@ -3576,6 +3593,7 @@ void core_link_enable_stream(
	struct dc_stream_state *stream = pipe_ctx->stream;
	struct dc_link *link = stream->sink->link;
	enum dc_status status;
	struct link_encoder *link_enc;
#if defined(CONFIG_DRM_AMD_DC_DCN)
	enum otg_out_mux_dest otg_out_dest = OUT_MUX_DIO;
#endif
@@ -3585,14 +3603,21 @@ void core_link_enable_stream(
			dc_is_virtual_signal(pipe_ctx->stream->signal))
		return;

	if (dc->res_pool->funcs->link_encs_assign && stream->link->ep_type != DISPLAY_ENDPOINT_PHY)
		link_enc = stream->link_enc;
	else
		link_enc = stream->link->link_enc;
	ASSERT(link_enc);

#if defined(CONFIG_DRM_AMD_DC_DCN)
	if (!dc_is_virtual_signal(pipe_ctx->stream->signal)
			&& !is_dp_128b_132b_signal(pipe_ctx)) {
#else
	if (!dc_is_virtual_signal(pipe_ctx->stream->signal)) {
#endif
		stream->link->link_enc->funcs->setup(
			stream->link->link_enc,
		if (link_enc)
			link_enc->funcs->setup(
				link_enc,
				pipe_ctx->stream->signal);
		pipe_ctx->stream_res.stream_enc->funcs->setup_stereo_sync(
			pipe_ctx->stream_res.stream_enc,
@@ -3748,8 +3773,9 @@ void core_link_enable_stream(
#else
		if (!dc_is_virtual_signal(pipe_ctx->stream->signal))
#endif
			stream->link->link_enc->funcs->setup(
				stream->link->link_enc,
			if (link_enc)
				link_enc->funcs->setup(
					link_enc,
					pipe_ctx->stream->signal);

		dc->hwss.enable_stream(pipe_ctx);
+32 −4
Original line number Diff line number Diff line
@@ -2624,13 +2624,27 @@ static enum dc_link_rate get_lttpr_max_link_rate(struct dc_link *link)

bool dc_link_dp_get_max_link_enc_cap(const struct dc_link *link, struct dc_link_settings *max_link_enc_cap)
{
	struct link_encoder *link_enc = NULL;

	if (!max_link_enc_cap) {
		DC_LOG_ERROR("%s: Could not return max link encoder caps", __func__);
		return false;
	}

	if (link->link_enc->funcs->get_max_link_cap) {
		link->link_enc->funcs->get_max_link_cap(link->link_enc, max_link_enc_cap);
	/* Links supporting dynamically assigned link encoder will be assigned next
	 * available encoder if one not already assigned.
	 */
	if (link->is_dig_mapping_flexible &&
			link->dc->res_pool->funcs->link_encs_assign) {
		link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link);
		if (link_enc == NULL)
			link_enc = link_enc_cfg_get_next_avail_link_enc(link->dc, link->dc->current_state);
	} else
		link_enc = link->link_enc;
	ASSERT(link_enc);

	if (link_enc && link_enc->funcs->get_max_link_cap) {
		link_enc->funcs->get_max_link_cap(link_enc, max_link_enc_cap);
		return true;
	}

@@ -2646,9 +2660,23 @@ static struct dc_link_settings get_max_link_cap(struct dc_link *link)
#if defined(CONFIG_DRM_AMD_DC_DCN)
	enum dc_link_rate lttpr_max_link_rate;
#endif
	struct link_encoder *link_enc = NULL;

	/* Links supporting dynamically assigned link encoder will be assigned next
	 * available encoder if one not already assigned.
	 */
	if (link->is_dig_mapping_flexible &&
			link->dc->res_pool->funcs->link_encs_assign) {
		link_enc = link_enc_cfg_get_link_enc_used_by_link(link->dc->current_state, link);
		if (link_enc == NULL)
			link_enc = link_enc_cfg_get_next_avail_link_enc(link->dc, link->dc->current_state);
	} else
		link_enc = link->link_enc;
	ASSERT(link_enc);

	/* get max link encoder capability */
	link->link_enc->funcs->get_max_link_cap(link->link_enc, &max_link_cap);
	if (link_enc)
		link_enc->funcs->get_max_link_cap(link_enc, &max_link_cap);
#if defined(CONFIG_DRM_AMD_DC_DCN)
	if (max_link_cap.link_rate >= LINK_RATE_UHBR10 &&
			!link->hpo_dp_link_enc)
@@ -2867,7 +2895,7 @@ bool dp_verify_link_cap(
	 * PHY will sometimes be in bad state on hotplugging display from certain USB-C dongle,
	 * so add extra cycle of enabling and disabling the PHY before first link training.
	 */
	if (link->link_enc->features.flags.bits.DP_IS_USB_C &&
	if (link->link_enc && link->link_enc->features.flags.bits.DP_IS_USB_C &&
			link->dc->debug.usbc_combo_phy_reset_wa) {
		dp_enable_link_phy(link, link->connector_signal, dp_cs_id, cur);
		dp_disable_link_phy(link, link->connector_signal);
+15 −10
Original line number Diff line number Diff line
@@ -139,7 +139,7 @@ static struct dc_stream_state *get_stream_using_link_enc(
	for (i = 0; i < state->stream_count; i++) {
		struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i];

		if (assignment.valid && (assignment.eng_id == eng_id)) {
		if ((assignment.valid == true) && (assignment.eng_id == eng_id)) {
			stream_idx = i;
			break;
		}
@@ -254,7 +254,7 @@ struct dc_link *link_enc_cfg_get_link_using_link_enc(
	for (i = 0; i < state->stream_count; i++) {
		struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i];

		if (assignment.valid && (assignment.eng_id == eng_id)) {
		if ((assignment.valid == true) && (assignment.eng_id == eng_id)) {
			stream_idx = i;
			break;
		}
@@ -274,7 +274,6 @@ struct link_encoder *link_enc_cfg_get_link_enc_used_by_link(
{
	struct link_encoder *link_enc = NULL;
	struct display_endpoint_id ep_id;
	int stream_idx = -1;
	int i;

	ep_id = (struct display_endpoint_id) {
@@ -283,20 +282,15 @@ struct link_encoder *link_enc_cfg_get_link_enc_used_by_link(

	for (i = 0; i < state->stream_count; i++) {
		struct link_enc_assignment assignment = state->res_ctx.link_enc_assignments[i];

		if (assignment.valid &&
		if (assignment.valid == true &&
				assignment.ep_id.link_id.id == ep_id.link_id.id &&
				assignment.ep_id.link_id.enum_id == ep_id.link_id.enum_id &&
				assignment.ep_id.link_id.type == ep_id.link_id.type &&
				assignment.ep_id.ep_type == ep_id.ep_type) {
			stream_idx = i;
			break;
			link_enc = link->dc->res_pool->link_encoders[assignment.eng_id - ENGINE_ID_DIGA];
		}
	}

	if (stream_idx != -1)
		link_enc = state->streams[stream_idx]->link_enc;

	return link_enc;
}

@@ -313,3 +307,14 @@ struct link_encoder *link_enc_cfg_get_next_avail_link_enc(

	return link_enc;
}

struct link_encoder *link_enc_cfg_get_link_enc_used_by_stream(
		struct dc_state *state,
		const struct dc_stream_state *stream)
{
	struct link_encoder *link_enc;

	link_enc = link_enc_cfg_get_link_enc_used_by_link(state, stream->link);

	return link_enc;
}
+4 −3
Original line number Diff line number Diff line
@@ -452,6 +452,7 @@ void dp_retrain_link_dp_test(struct dc_link *link,
			if ((&pipes[i])->stream_res.audio && !link->dc->debug.az_endpoint_mute_only)
				(&pipes[i])->stream_res.audio->funcs->az_disable((&pipes[i])->stream_res.audio);

			if (link->link_enc)
				link->link_enc->funcs->disable_output(
						link->link_enc,
						SIGNAL_TYPE_DISPLAY_PORT);
Loading