Commit 410ad92d authored by Wayne Lin's avatar Wayne Lin Committed by Alex Deucher
Browse files

drm/amd/display: Add option to defer works of hpd_rx_irq



[Why & How]
Due to some code flow constraints, we need to defer dc_lock needed works
from dc_link_handle_hpd_rx_irq(). Thus, do following changes:

* Change allow_hpd_rx_irq() from static to public
* Change handle_automated_test() from static to public
* Extract link lost handling flow out from dc_link_handle_hpd_rx_irq()
  and put those into a new function dc_link_dp_handle_link_loss()
* Add one option parameter to decide whether defer works within
  dc_link_handle_hpd_rx_irq()

Acked-by: default avatarMikita Lipski <mikita.lipski@amd.com>
Signed-off-by: default avatarWayne Lin <Wayne.Lin@amd.com>
Reviewed-by: default avatarNicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Tested-by: default avatarDaniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: default avatarAlex Deucher <alexander.deucher@amd.com>
parent 928adbf6
Loading
Loading
Loading
Loading
+60 −32
Original line number Diff line number Diff line
@@ -3431,7 +3431,7 @@ void decide_link_settings(struct dc_stream_state *stream,
}

/*************************Short Pulse IRQ***************************/
static bool allow_hpd_rx_irq(const struct dc_link *link)
bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link)
{
	/*
	 * Don't handle RX IRQ unless one of following is met:
@@ -3940,7 +3940,7 @@ static void dp_test_get_audio_test_data(struct dc_link *link, bool disable_video
	}
}

static void handle_automated_test(struct dc_link *link)
void dc_link_dp_handle_automated_test(struct dc_link *link)
{
	union test_request test_request;
	union test_response test_response;
@@ -3989,17 +3989,50 @@ static void handle_automated_test(struct dc_link *link)
			sizeof(test_response));
}

bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss)
void dc_link_dp_handle_link_loss(struct dc_link *link)
{
	int i;
	struct pipe_ctx *pipe_ctx;

	for (i = 0; i < MAX_PIPES; i++) {
		pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
		if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
			break;
	}

	if (pipe_ctx == NULL || pipe_ctx->stream == NULL)
		return;

	for (i = 0; i < MAX_PIPES; i++) {
		pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
		if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
				pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) {
			core_link_disable_stream(pipe_ctx);
		}
	}

	for (i = 0; i < MAX_PIPES; i++) {
		pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
		if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
				pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe) {
			core_link_enable_stream(link->dc->current_state, pipe_ctx);
		}
	}
}

static bool handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss,
							bool defer_handling, bool *has_left_work)
{
	union hpd_irq_data hpd_irq_dpcd_data = { { { {0} } } };
	union device_service_irq device_service_clear = { { 0 } };
	enum dc_status result;
	bool status = false;
	struct pipe_ctx *pipe_ctx;
	int i;

	if (out_link_loss)
		*out_link_loss = false;

	if (has_left_work)
		*has_left_work = false;
	/* For use cases related to down stream connection status change,
	 * PSR and device auto test, refer to function handle_sst_hpd_irq
	 * in DAL2.1*/
@@ -4031,11 +4064,14 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
			&device_service_clear.raw,
			sizeof(device_service_clear.raw));
		device_service_clear.raw = 0;
		handle_automated_test(link);
		if (defer_handling && has_left_work)
			*has_left_work = true;
		else
			dc_link_dp_handle_automated_test(link);
		return false;
	}

	if (!allow_hpd_rx_irq(link)) {
	if (!dc_link_dp_allow_hpd_rx_irq(link)) {
		DC_LOG_HW_HPD_IRQ("%s: skipping HPD handling on %d\n",
			__func__, link->link_index);
		return false;
@@ -4049,12 +4085,18 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
	 * so do not handle as a normal sink status change interrupt.
	 */

	if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY)
	if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.UP_REQ_MSG_RDY) {
		if (defer_handling && has_left_work)
			*has_left_work = true;
		return true;
	}

	/* check if we have MST msg and return since we poll for it */
	if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY)
	if (hpd_irq_dpcd_data.bytes.device_service_irq.bits.DOWN_REP_MSG_RDY) {
		if (defer_handling && has_left_work)
			*has_left_work = true;
		return false;
	}

	/* For now we only handle 'Downstream port status' case.
	 * If we got sink count changed it means
@@ -4071,29 +4113,10 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
					sizeof(hpd_irq_dpcd_data),
					"Status: ");

		for (i = 0; i < MAX_PIPES; i++) {
			pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
			if (pipe_ctx && pipe_ctx->stream && pipe_ctx->stream->link == link)
				break;
		}

		if (pipe_ctx == NULL || pipe_ctx->stream == NULL)
			return false;


		for (i = 0; i < MAX_PIPES; i++) {
			pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
			if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
					pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe)
				core_link_disable_stream(pipe_ctx);
		}

		for (i = 0; i < MAX_PIPES; i++) {
			pipe_ctx = &link->dc->current_state->res_ctx.pipe_ctx[i];
			if (pipe_ctx && pipe_ctx->stream && !pipe_ctx->stream->dpms_off &&
					pipe_ctx->stream->link == link && !pipe_ctx->prev_odm_pipe)
				core_link_enable_stream(link->dc->current_state, pipe_ctx);
		}
		if (defer_handling && has_left_work)
			*has_left_work = true;
		else
			dc_link_dp_handle_link_loss(link);

		status = false;
		if (out_link_loss)
@@ -4119,6 +4142,11 @@ bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd
	return status;
}

bool dc_link_handle_hpd_rx_irq(struct dc_link *link, union hpd_irq_data *out_hpd_irq_dpcd_data, bool *out_link_loss)
{
	return handle_hpd_rx_irq(link, out_hpd_irq_dpcd_data, out_link_loss, false, NULL);
}

/*query dpcd for version and mst cap addresses*/
bool is_mst_supported(struct dc_link *link)
{
+3 −0
Original line number Diff line number Diff line
@@ -315,6 +315,9 @@ bool dc_link_wait_for_t12(struct dc_link *link);
enum dc_status read_hpd_rx_irq_data(
	struct dc_link *link,
	union hpd_irq_data *irq_data);
void dc_link_dp_handle_automated_test(struct dc_link *link);
void dc_link_dp_handle_link_loss(struct dc_link *link);
bool dc_link_dp_allow_hpd_rx_irq(const struct dc_link *link);

struct dc_sink_init_data;