From a4d5df1787cc143b513b9f472ead1ff5eaa550e1 Mon Sep 17 00:00:00 2001 From: Eric Yang Date: Fri, 9 Jul 2021 12:57:50 -0400 Subject: [PATCH] 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: Jun Lei Acked-by: Rodrigo Siqueira Signed-off-by: Eric Yang Signed-off-by: Alex Deucher --- .../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 5c2853654ccad..ef185b93b31d6 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 2043528d3490a..ef233cb49b317 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 713f5558f5e17..259283d8bde8f 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.30.2