Blob Blame History Raw
From 00d38d66309d7e007c8a2747cccfcaae9fc7bb4f Mon Sep 17 00:00:00 2001
From: Eric Yang <Eric.Yang2@amd.com>
Date: Fri, 9 Jul 2021 12:57:50 -0400
Subject: drm/amd/display: add workaround for riommu invalidation request hang
Git-commit: a4d5df1787cc143b513b9f472ead1ff5eaa550e1
Patch-mainline: v5.15-rc1
References: jsc#PED-1166 jsc#PED-1168 jsc#PED-1170 jsc#PED-1218 jsc#PED-1220 jsc#PED-1222 jsc#PED-1223 jsc#PED-1225

[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: Jun Lei <jun.lei@amd.com>
Acked-by: Rodrigo Siqueira <Rodrigo.Siqueira@amd.com>
Signed-off-by: Eric Yang <Eric.Yang2@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
Acked-by: Patrik Jakobsson <pjakobsson@suse.de>
---
 .../drm/amd/display/dc/dcn20/dcn20_hwseq.c    |  6 ++++++
 .../drm/amd/display/dc/dcn31/dcn31_hubbub.c   | 20 +++++++++++++++++++
 .../gpu/drm/amd/display/dc/inc/hw/dchubbub.h  |  3 +++
 3 files changed, 29 insertions(+)

diff --git a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
index 5c2853654cca..ef185b93b31d 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
@@ -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
diff --git a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
index 2043528d3490..ef233cb49b31 100644
--- a/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
+++ b/drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
@@ -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,
diff --git a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
index 713f5558f5e1..259283d8bde8 100644
--- a/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
+++ b/drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h
@@ -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
-- 
2.38.1