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>
This commit is contained in:
Nicholas Kazlauskas 2024-02-26 14:29:05 -05:00 committed by Alex Deucher
parent 398a16e1f0
commit 93ddf00f87
2 changed files with 13 additions and 2 deletions

View File

@ -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;

View File

@ -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;
};