Skip to content

Commit

Permalink
drm/amd/display: decouple dmcub execution to reduce lock granularity
Browse files Browse the repository at this point in the history
[Why]
On some systems dmub commands run at high IRQ, so long running
commands will block other interrupts.

[How]
Decouple wait_for_idle from dmcub queue/execute/wait.

Reviewed-by: Josip Pavic <[email protected]>
Acked-by: Hersen Wu <[email protected]>
Signed-off-by: JinZe.Xu <[email protected]>
Tested-by: Daniel Wheeler <[email protected]>
Signed-off-by: Alex Deucher <[email protected]>
  • Loading branch information
unsccaptain1 authored and alexdeucher committed Nov 7, 2023
1 parent 13c84bb commit 028bac5
Show file tree
Hide file tree
Showing 2 changed files with 82 additions and 0 deletions.
74 changes: 74 additions & 0 deletions drivers/gpu/drm/amd/display/dc/dc_dmub_srv.c
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,80 @@ void dc_dmub_srv_send_inbox0_cmd(struct dc_dmub_srv *dc_dmub_srv,
}
}

bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
union dmub_rb_cmd *cmd_list)
{
struct dc_context *dc_ctx = dc_dmub_srv->ctx;
struct dmub_srv *dmub;
enum dmub_status status;
int i;

if (!dc_dmub_srv || !dc_dmub_srv->dmub)
return false;

dmub = dc_dmub_srv->dmub;

for (i = 0 ; i < count; i++) {
// Queue command
status = dmub_srv_cmd_queue(dmub, &cmd_list[i]);

if (status == DMUB_STATUS_QUEUE_FULL) {
/* Execute and wait for queue to become empty again. */
dmub_srv_cmd_execute(dmub);
dmub_srv_wait_for_idle(dmub, 100000);

/* Requeue the command. */
status = dmub_srv_cmd_queue(dmub, &cmd_list[i]);
}

if (status != DMUB_STATUS_OK) {
DC_ERROR("Error queueing DMUB command: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
return false;
}
}

status = dmub_srv_cmd_execute(dmub);
if (status != DMUB_STATUS_OK) {
DC_ERROR("Error starting DMUB execution: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
return false;
}

return true;
}

bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
enum dm_dmub_wait_type wait_type,
union dmub_rb_cmd *cmd_list)
{
struct dmub_srv *dmub;
enum dmub_status status;

if (!dc_dmub_srv || !dc_dmub_srv->dmub)
return false;

dmub = dc_dmub_srv->dmub;

// Wait for DMUB to process command
if (wait_type != DM_DMUB_WAIT_TYPE_NO_WAIT) {
status = dmub_srv_wait_for_idle(dmub, 100000);

if (status != DMUB_STATUS_OK) {
DC_LOG_DEBUG("No reply for DMUB command: status=%d\n", status);
dc_dmub_srv_log_diagnostic_data(dc_dmub_srv);
return false;
}

// Copy data back from ring buffer into command
if (wait_type == DM_DMUB_WAIT_TYPE_WAIT_WITH_REPLY)
dmub_rb_get_return_data(&dmub->inbox1_rb, cmd_list);
}

return true;
}

bool dc_dmub_srv_cmd_run(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type)
{
return dc_dmub_srv_cmd_run_list(dc_dmub_srv, 1, cmd, wait_type);
Expand Down
8 changes: 8 additions & 0 deletions drivers/gpu/drm/amd/display/dc/dc_dmub_srv.h
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,14 @@ void dc_dmub_srv_wait_idle(struct dc_dmub_srv *dc_dmub_srv);

bool dc_dmub_srv_optimized_init_done(struct dc_dmub_srv *dc_dmub_srv);

bool dc_dmub_srv_cmd_list_queue_execute(struct dc_dmub_srv *dc_dmub_srv,
unsigned int count,
union dmub_rb_cmd *cmd_list);

bool dc_dmub_srv_wait_for_idle(struct dc_dmub_srv *dc_dmub_srv,
enum dm_dmub_wait_type wait_type,
union dmub_rb_cmd *cmd_list);

bool dc_dmub_srv_cmd_run(struct dc_dmub_srv *dc_dmub_srv, union dmub_rb_cmd *cmd, enum dm_dmub_wait_type wait_type);

bool dc_dmub_srv_cmd_run_list(struct dc_dmub_srv *dc_dmub_srv, unsigned int count, union dmub_rb_cmd *cmd_list, enum dm_dmub_wait_type wait_type);
Expand Down

0 comments on commit 028bac5

Please sign in to comment.