Commit a4d5df17 authored by Eric Yang's avatar Eric Yang Committed by Alex Deucher
Browse files

drm/amd/display: add workaround for riommu invalidation request hang



[Why]
When an riommu invalidation request come at the same time as a pipe is
disabled there can be a case where DCN cannot ACK the request if only
one VMID is setup in the inuse list.

[How]
Setup a second unused VMID will work around the issue.

Reviewed-by: default avatarJun Lei <jun.lei@amd.com>
Acked-by: default avatarRodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: default avatarEric Yang <Eric.Yang2@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent ba16b22d
Loading
Loading
Loading
Loading
+6 −0
Original line number Diff line number Diff line
@@ -570,6 +570,12 @@ void dcn20_plane_atomic_disable(struct dc *dc, struct pipe_ctx *pipe_ctx)
	struct hubp *hubp = pipe_ctx->plane_res.hubp;
	struct dpp *dpp = pipe_ctx->plane_res.dpp;

	if (hws->wa.early_riommu_invalidation) {
		struct hubbub *hubbub = dc->res_pool->hubbub;

		hubbub->funcs->apply_invalidation_req_wa(hubbub, &hubbub->vmid_cache);
	}

	dc->hwss.wait_for_mpcc_disconnect(dc, dc->res_pool, pipe_ctx);

	/* In flip immediate with pipe splitting case GSL is used for
+20 −0
Original line number Diff line number Diff line
@@ -880,6 +880,8 @@ static int hubbub31_init_dchub_sys_ctx(struct hubbub *hubbub,

	dcn21_dchvm_init(hubbub);

	hubbub->vmid_cache = *pa_config;

	return NUM_VMID;
}

@@ -920,6 +922,23 @@ static void hubbub31_get_dchub_ref_freq(struct hubbub *hubbub,
	}
}

static void hubbub31_apply_invalidation_req_wa(struct hubbub *hubbub,
		struct dcn_hubbub_phys_addr_config *pa_config)
{
	struct dcn20_hubbub *hubbub1 = TO_DCN20_HUBBUB(hubbub);
	struct dcn_vmid_page_table_config phys_config;

	if (pa_config->gart_config.page_table_start_addr != pa_config->gart_config.page_table_end_addr) {
		phys_config.page_table_start_addr = pa_config->gart_config.page_table_start_addr >> 12;
		phys_config.page_table_end_addr = pa_config->gart_config.page_table_end_addr >> 12;
		phys_config.page_table_base_addr = pa_config->gart_config.page_table_base_addr;
		phys_config.depth = 0;
		phys_config.block_size = 0;
		// Program an arbitrary unused VMID
		dcn20_vmid_setup(&hubbub1->vmid[15], &phys_config);
	}
}

static const struct hubbub_funcs hubbub31_funcs = {
	.update_dchub = hubbub2_update_dchub,
	.init_dchub_sys_ctx = hubbub31_init_dchub_sys_ctx,
@@ -936,6 +955,7 @@ static const struct hubbub_funcs hubbub31_funcs = {
	.program_compbuf_size = dcn31_program_compbuf_size,
	.init_crb = dcn31_init_crb,
	.hubbub_read_state = hubbub2_read_state,
	.apply_invalidation_req_wa = hubbub31_apply_invalidation_req_wa
};

void hubbub31_construct(struct dcn20_hubbub *hubbub31,
+3 −0
Original line number Diff line number Diff line
@@ -166,12 +166,15 @@ struct hubbub_funcs {
	void (*program_det_size)(struct hubbub *hubbub, int hubp_inst, unsigned det_buffer_size_in_kbyte);
	void (*program_compbuf_size)(struct hubbub *hubbub, unsigned compbuf_size_kb, bool safe_to_increase);
	void (*init_crb)(struct hubbub *hubbub);
	void (*apply_invalidation_req_wa)(struct hubbub *hubbub,
			struct dcn_hubbub_phys_addr_config *pa_config);
};

struct hubbub {
	const struct hubbub_funcs *funcs;
	struct dc_context *ctx;
	bool riommu_active;
	struct dcn_hubbub_phys_addr_config vmid_cache;
};

#endif