Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9b445309 authored by Christopher Braga's avatar Christopher Braga
Browse files

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: default avatarChristopher Braga <cbraga@codeaurora.org>
parent 7893b22b
Loading
Loading
Loading
Loading
+27 −8
Original line number Diff line number Diff line
@@ -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 (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 @@ static int dp_display_pre_disable(struct dp_display *dp_display, void *panel)

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;