From: Ovidiu Bunea <[email protected]> [why & how] Allowing the DCHVM<->rIOMMU SDP port to disconnect during IPS1 cycling can cause extra credits to be released to rIOMMU. In turn, this will let the rIOMMU issue more outstanding table walk requests at once, overflowing the downstream request FIFO. This results in dropped/orphaned requests with no method of recovery. This typically manifests as an invalidation hang error in the main IOMMU.
As a workaround, dis-allow the SDP port from disconnecting from IPS1 exit up until after powerstatus=1. This ensures that rIOMMU does not have the chance to request credits multiple times during the powerstatus 0->1 transition. Since x86 driver cannot access rIOMMU register space, send a command to DMU to do it. Reviewed-by: Nicholas Kazlauskas <[email protected]> Signed-off-by: Ovidiu Bunea <[email protected]> Signed-off-by: James Lin <[email protected]> --- drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c | 18 ++++++++++++++++++ drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h | 12 ++++++++++++ .../amd/display/dc/hubbub/dcn35/dcn35_hubbub.c | 7 +++++++ 3 files changed, 37 insertions(+) diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c index 01864fe816a3..4723e0974647 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c @@ -2527,3 +2527,21 @@ bool dc_dmub_srv_panel_polarity_get_polarity(struct dc_dmub_srv *dc_dmub_srv, ui return ret; } + +void dc_dmub_srv_hubbub_set_riommu_pctrl(const struct dc_context *ctx, uint32_t value) +{ + union dmub_rb_cmd cmd; + + if (!(ctx->dce_version == DCN_VERSION_4_2 || ctx->dce_version == DCN_VERSION_4_2B)) + return; + + memset(&cmd, 0, sizeof(cmd)); + + cmd.dc_bls_dchvm_init.header.type = DMUB_CMD__DC_BLS; + cmd.dc_bls_dchvm_init.header.sub_type = DMUB_CMD__DC_BLS_DCHVM_INIT; + cmd.dc_bls_dchvm_init.header.payload_bytes = sizeof(struct dmub_cmd_dc_bls_dchvm_init_data); + + cmd.dc_bls_dchvm_init.data.riommu_pctrl_val = value; + + dc_wake_and_execute_dmub_cmd(ctx, &cmd, DM_DMUB_WAIT_TYPE_WAIT); +} diff --git a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h index ec5387aedf46..ab026847e38b 100644 --- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h +++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h @@ -451,4 +451,16 @@ void dc_dmub_srv_panel_polarity_reset(struct dc_dmub_srv *dc_dmub_srv, uint8_t p */ bool dc_dmub_srv_panel_polarity_get_polarity(struct dc_dmub_srv *dc_dmub_srv, uint8_t panel_inst, int32_t *polarity); +/** + * dc_dmub_srv_hubbub_set_riommu_pctrl() - Program the RIOMMU PCTRL register via DMCUB. + * + * The RIOMMU PCTRL register (SMN address 0x16B0A100) controls the SDP port + * disconnection hysteresis between rIOMMU & DCHVM. It is not accessible from + * x86, so the write is offloaded to DMCUB. + * + * @ctx: dc context + * @value: value to program into the register (e.g. 0x20) + */ +void dc_dmub_srv_hubbub_set_riommu_pctrl(const struct dc_context *ctx, uint32_t value); + #endif /* _DMUB_DC_SRV_H_ */ diff --git a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c index 5e5a7a74346d..53744b000f5d 100644 --- a/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c +++ b/drivers/gpu/drm/amd/display/dc/hubbub/dcn35/dcn35_hubbub.c @@ -31,6 +31,7 @@ #include "dcn35_hubbub.h" #include "dm_services.h" #include "reg_helper.h" +#include "dc_dmub_srv.h" #define CTX \ @@ -580,7 +581,13 @@ void dcn35_dchvm_init(struct hubbub *hubbub) //Reflect the power status of DCHUBBUB REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_POWERSTATUS, 1); + udelay(5); + } + + // generically re-allow the DCHVM<->rIOMMU SDP port to disconnect after powerstatus=1 + dc_dmub_srv_hubbub_set_riommu_pctrl(hubbub->ctx, 0x20); + if (riommu_active) { //Start rIOMMU prefetching REG_UPDATE(DCHVM_RIOMMU_CTRL0, HOSTVM_PREFETCH_REQ, 1); -- 2.43.0
