OSDN Git Service

drm/amd/display: Add option to defer works of hpd_rx_irq
authorWayne Lin <Wayne.Lin@amd.com>
Fri, 13 Aug 2021 07:54:47 +0000 (15:54 +0800)
committerAlex Deucher <alexander.deucher@amd.com>
Tue, 14 Sep 2021 19:57:09 +0000 (15:57 -0400)
[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: Mikita Lipski <mikita.lipski@amd.com>
Signed-off-by: Wayne Lin <Wayne.Lin@amd.com>
Reviewed-by: Nicholas Kazlauskas <nicholas.kazlauskas@amd.com>
Tested-by: Daniel Wheeler <daniel.wheeler@amd.com>
Signed-off-by: Alex Deucher <alexander.deucher@amd.com>
drivers/gpu/drm/amd/display/dc/core/dc_link_dp.c
drivers/gpu/drm/amd/display/dc/dc_link.h

index 3b68d77..ea0a415 100644 (file)
@@ -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)
 {
index 4fdb24b..bb515d6 100644 (file)
@@ -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;