summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Kazlauskas <nicholas.kazlauskas@amd.com>2024-02-26 22:29:05 +0300
committerAlex Deucher <alexander.deucher@amd.com>2024-03-22 22:49:29 +0300
commit93ddf00f874c26e078ba01010bc126f521d49e7f (patch)
tree128c8121052936638f71621b1371476157fe02c4
parent398a16e1f03b6b583b94c7ab080aa38432fb0502 (diff)
downloadlinux-93ddf00f874c26e078ba01010bc126f521d49e7f.tar.xz
drm/amd/display: Detect and disallow idle reallow during reentrancy
[Why] Cursor updates can be preempted by queued flips in some DMs. The synchronization model causes this to occur within the same thread at an intermediate level when we insert logs into the OS queue. Since this occurs on the same thread and we're still holding the lock (recursively) the cache is coherent. The exit sequence will run twice since we technically haven't finished the exit the first time, so we need a way to detect and avoid the reallow in the middle of this call to prevent the hang on the cursor update that was preempted. [How] Keep a counter that tracks the depth of the exit calls. Do not reallow until the counter is zero. Reviewed-by: Duncan Ma <duncan.ma@amd.com> Acked-by: Wayne Lin <wayne.lin@amd.com> Signed-off-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com> Tested-by: Daniel Wheeler <daniel.wheeler@amd.com> Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c14
-rw-r--r--drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h1
2 files changed, 13 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 f796ed061879..4878e9e50440 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
@@ -1437,6 +1437,8 @@ void dc_dmub_srv_apply_idle_power_optimizations(const struct dc *dc, bool allow_
*/
if (!allow_idle) {
+ dc_dmub_srv->idle_exit_counter += 1;
+
dc_dmub_srv_exit_low_power_state(dc);
/*
* Idle is considered fully exited only after the sequence above
@@ -1448,6 +1450,12 @@ void dc_dmub_srv_apply_idle_power_optimizations(const struct dc *dc, bool allow_
* dm_execute_dmub_cmd submission instead of the "wake" helpers.
*/
dc_dmub_srv->idle_allowed = false;
+
+ dc_dmub_srv->idle_exit_counter -= 1;
+ if (dc_dmub_srv->idle_exit_counter < 0) {
+ ASSERT(0);
+ dc_dmub_srv->idle_exit_counter = 0;
+ }
} else {
/* Consider idle as notified prior to the actual submission to
* prevent multiple entries. */
@@ -1489,7 +1497,8 @@ bool dc_wake_and_execute_dmub_cmd_list(const struct dc_context *ctx, unsigned in
else
result = dm_execute_dmub_cmd(ctx, cmd, wait_type);
- if (result && reallow_idle && !ctx->dc->debug.disable_dmub_reallow_idle)
+ if (result && reallow_idle && dc_dmub_srv->idle_exit_counter == 0 &&
+ !ctx->dc->debug.disable_dmub_reallow_idle)
dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, true);
return result;
@@ -1538,7 +1547,8 @@ bool dc_wake_and_execute_gpint(const struct dc_context *ctx, enum dmub_gpint_com
result = dc_dmub_execute_gpint(ctx, command_code, param, response, wait_type);
- if (result && reallow_idle && !ctx->dc->debug.disable_dmub_reallow_idle)
+ if (result && reallow_idle && dc_dmub_srv->idle_exit_counter == 0 &&
+ !ctx->dc->debug.disable_dmub_reallow_idle)
dc_dmub_srv_apply_idle_power_optimizations(ctx->dc, true);
return result;
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 60c93e9e3533..c0a512a12531 100644
--- a/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
+++ b/drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
@@ -51,6 +51,7 @@ struct dc_dmub_srv {
struct dc_context *ctx;
void *dm;
+ int32_t idle_exit_counter;
bool idle_allowed;
bool needs_idle_wake;
};