aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Kazlauskas <[email protected]>2023-12-14 16:46:35 -0500
committerAlex Deucher <[email protected]>2024-01-03 10:47:49 -0500
commitb8a204fb1a97b39a7fcaefbf2c6c4d01aa4f3c57 (patch)
tree1a4375dac2aacbe1eb926ec5b1ac3e3ebd7d7ba7
parent9ade4870b87b09e1f132ba92c1ab13a6769d1b0f (diff)
drm/amd/display: Verify disallow bits were cleared for idle
[Why] A hang was observed where a read-modify-write access occurred due to the register for idle state being shared between DMCUB and driver. dmcub read - idle allow / no commit driver read - idle allow / no commit driver write - idle disallow / no commit dmcub write - idle allow / commit Resulting in DMCUB re-entering IPS after a disable and keeping the allow high. [How] Long term we need to split commit/allow into two registers or use shared DRAM state, but short term we can reduce the repro rate by ensuring that the disallow went through by bounding the expected worst case scenario. Tested-by: Daniel Wheeler <[email protected]> Reviewed-by: Hansen Dsouza <[email protected]> Reviewed-by: Ovidiu Bunea <[email protected]> Acked-by: Rodrigo Siqueira <[email protected]> Signed-off-by: Nicholas Kazlauskas <[email protected]> Signed-off-by: Alex Deucher <[email protected]>
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c12
1 files changed, 10 insertions, 2 deletions
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 dadeaa9c92dd..a65c485b0b49 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -1233,8 +1233,16 @@ static void dc_dmub_srv_exit_low_power_state(const struct dc *dc)
if (!(allow_state & DMUB_IPS2_ALLOW_MASK)) {
// Wait for evaluation time
- udelay(dc->debug.ips2_eval_delay_us);
- commit_state = dc->hwss.get_idle_state(dc);
+ for (;;) {
+ udelay(dc->debug.ips2_eval_delay_us);
+ commit_state = dc->hwss.get_idle_state(dc);
+ if (commit_state & DMUB_IPS2_ALLOW_MASK)
+ break;
+
+ /* allow was still set, retry eval delay */
+ dc->hwss.set_idle_state(dc, false);
+ }
+
if (!(commit_state & DMUB_IPS2_COMMIT_MASK)) {
// Tell PMFW to exit low power state
dc->clk_mgr->funcs->exit_low_power_state(dc->clk_mgr);