Commit 028bac58 authored by JinZe.Xu's avatar JinZe.Xu Committed by Alex Deucher
Browse files

drm/amd/display: decouple dmcub execution to reduce lock granularity



[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: default avatarJosip Pavic <josip.pavic@amd.com>
Acked-by: default avatarHersen Wu <hersenxs.wu@amd.com>
Signed-off-by: default avatarJinZe.Xu <jinze.xu@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 13c84bbe
Loading
Loading
Loading
Loading
+74 −0
Original line number Diff line number Diff line
@@ -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);
+8 −0
Original line number Diff line number Diff line
@@ -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);