OSDN Git Service

drm/amd/display: add workaround for riommu invalidation request hang
authorEric Yang <Eric.Yang2@amd.com>
Fri, 9 Jul 2021 16:57:50 +0000 (12:57 -0400)
committerAlex Deucher <alexander.deucher@amd.com>
Fri, 23 Jul 2021 14:07:58 +0000 (10:07 -0400)
[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>
drivers/gpu/drm/amd/display/dc/dcn20/dcn20_hwseq.c
drivers/gpu/drm/amd/display/dc/dcn31/dcn31_hubbub.c
drivers/gpu/drm/amd/display/dc/inc/hw/dchubbub.h

index 5c28536..ef185b9 100644 (file)
@@ -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
index 2043528..ef233cb 100644 (file)
@@ -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,
index 713f555..259283d 100644 (file)
@@ -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