From 9b4453096ab191a8809155bd04fa5abd2b0a34e8 Mon Sep 17 00:00:00 2001 From: Christopher Braga Date: Mon, 22 Apr 2019 16:39:22 -0400 Subject: [PATCH] disp: msm: dp: Prevent disconnect from stopping HDCP If a DP stream is disconnected when HDCP is not fully authenticated, authentication may not continue for remaining streams. This occurs due to the worker thread rescheduling itself on auth fail while disconnect cancels any pending work. Update disconnect logic to wait for HDCP authentication to complete before stream de-registration, and reschedule the HDCP worker if HDCP did not fully authenticate prior to disconnect. Change-Id: I0f8934e4f34e4f5a8015587e852131795a3dad21 Signed-off-by: Christopher Braga --- msm/dp/dp_display.c | 35 +++++++++++++++++++++++++++-------- 1 file changed, 27 insertions(+), 8 deletions(-) diff --git a/msm/dp/dp_display.c b/msm/dp/dp_display.c index 5b9b3921bfc5..0d83844a6aba 100644 --- a/msm/dp/dp_display.c +++ b/msm/dp/dp_display.c @@ -99,6 +99,7 @@ struct dp_display_private { struct mutex session_lock; bool suspended; bool hdcp_delayed_off; + bool hdcp_abort; u32 active_stream_cnt; struct dp_mst mst; @@ -306,7 +307,8 @@ static void dp_display_hdcp_cb_work(struct work_struct *work) dp = container_of(dw, struct dp_display_private, hdcp_cb_work); - if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted)) + if (!dp->power_on || !dp->is_connected || atomic_read(&dp->aborted) || + dp->hdcp_abort) return; if (dp->suspended) { @@ -1660,13 +1662,16 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) goto end; } + dp->hdcp_abort = true; + cancel_delayed_work_sync(&dp->hdcp_cb_work); if (dp_display_is_hdcp_enabled(dp) && status->hdcp_state != HDCP_STATE_INACTIVE) { + bool off = true; if (dp->suspended) { pr_debug("Can't perform HDCP cleanup while suspended. Defer\n"); dp->hdcp_delayed_off = true; - goto stream; + goto clean; } flush_delayed_work(&dp->hdcp_cb_work); @@ -1677,18 +1682,19 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel) if (i != dp_panel->stream_id && dp->active_panels[i]) { pr_debug("Streams are still active. Skip disabling HDCP\n"); - goto stream; + off = false; } } } - if (dp->hdcp.ops->off) - dp->hdcp.ops->off(dp->hdcp.data); - - dp_display_update_hdcp_status(dp, true); + if (off) { + if (dp->hdcp.ops->off) + dp->hdcp.ops->off(dp->hdcp.data); + dp_display_update_hdcp_status(dp, true); + } } -stream: +clean: if (dp_panel->audio_supported) dp_panel->audio->off(dp_panel->audio); @@ -1701,8 +1707,10 @@ end: static int dp_display_disable(struct dp_display *dp_display, void *panel) { + int i; struct dp_display_private *dp = NULL; struct dp_panel *dp_panel = NULL; + struct dp_link_hdcp_status *status; if (!dp_display || !panel) { pr_err("invalid input\n"); @@ -1711,6 +1719,7 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel) dp = container_of(dp_display, struct dp_display_private, dp_display); dp_panel = panel; + status = &dp->link->hdcp_status; mutex_lock(&dp->session_lock); @@ -1721,6 +1730,16 @@ static int dp_display_disable(struct dp_display *dp_display, void *panel) dp_display_stream_disable(dp, dp_panel); dp_display_update_dsc_resources(dp, dp_panel, false); + + dp->hdcp_abort = false; + for (i = DP_STREAM_0; i < DP_STREAM_MAX; i++) { + if (dp->active_panels[i]) { + if (status->hdcp_state != HDCP_STATE_AUTHENTICATED) + queue_delayed_work(dp->wq, &dp->hdcp_cb_work, + HZ/4); + break; + } + } end: mutex_unlock(&dp->session_lock); return 0;