소스 검색

disp: msm: hdcp: abort queued tasks while processing PM suspend

During suspend, there might be a chance that lib auth work is queued
but not yet started. So during pm cycle it might start execution
before host_init which can lead to noc error while accessing dp_aux
registers. To prevent that set abort flag to abort lib auth work and
set interrupts before host_deinit.

Change-Id: Ie2c3ac9b0846644d3c2b37f410c341659b030c16
Signed-off-by: Rajat Gupta <[email protected]>
Signed-off-by: Tatenda Chipeperekwa <[email protected]>
Rajat Gupta 5 년 전
부모
커밋
0e1496c718
4개의 변경된 파일47개의 추가작업 그리고 2개의 파일을 삭제
  1. 18 0
      msm/dp/dp_display.c
  2. 12 0
      msm/dp/dp_hdcp2p2.c
  3. 2 1
      msm/sde_hdcp.h
  4. 15 1
      msm/sde_hdcp_1x.c

+ 18 - 0
msm/dp/dp_display.c

@@ -513,6 +513,22 @@ static void dp_display_hdcp_process_state(struct dp_display_private *dp)
 	}
 }
 
+static void dp_display_abort_hdcp(struct dp_display_private *dp,
+		bool abort)
+{
+	u8 i = HDCP_VERSION_2P2;
+	struct dp_hdcp_dev *dev = NULL;
+
+	while (i) {
+		dev = &dp->hdcp.dev[i];
+		i >>= 1;
+		if (!(dp->hdcp.source_cap & dev->ver))
+			continue;
+
+		dev->ops->abort(dev->fd, abort);
+	}
+}
+
 static void dp_display_hdcp_cb_work(struct work_struct *work)
 {
 	struct dp_display_private *dp;
@@ -894,6 +910,7 @@ static void dp_display_host_init(struct dp_display_private *dp)
 	dp->hpd->host_init(dp->hpd, &dp->catalog->hpd);
 	dp->ctrl->init(dp->ctrl, flip, reset);
 	enable_irq(dp->irq);
+	dp_display_abort_hdcp(dp, false);
 
 	dp_display_state_add(DP_STATE_INITIALIZED);
 
@@ -971,6 +988,7 @@ static void dp_display_host_deinit(struct dp_display_private *dp)
 		return;
 	}
 
+	dp_display_abort_hdcp(dp, true);
 	dp->ctrl->deinit(dp->ctrl);
 	dp->hpd->host_deinit(dp->hpd, &dp->catalog->hpd);
 	dp->power->deinit(dp->power);

+ 12 - 0
msm/dp/dp_hdcp2p2.c

@@ -31,6 +31,7 @@ struct dp_hdcp2p2_ctrl {
 	DECLARE_KFIFO(cmd_q, enum hdcp_transport_wakeup_cmd, 8);
 	wait_queue_head_t wait_q;
 	atomic_t auth_state;
+	atomic_t abort;
 	enum dp_hdcp2p2_sink_status sink_status; /* Is sink connected */
 	struct dp_hdcp2p2_interrupts *intr;
 	struct sde_hdcp_init_data init_data;
@@ -151,6 +152,9 @@ static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable)
 	void __iomem *base = ctrl->init_data.dp_ahb->base;
 	struct dp_hdcp2p2_interrupts *intr = ctrl->intr;
 
+	if (atomic_read(&ctrl->abort))
+		return;
+
 	while (intr && intr->reg) {
 		struct dp_hdcp2p2_int_set *int_set = intr->int_set;
 		u32 interrupts = 0;
@@ -882,6 +886,13 @@ static int dp_hdcp2p2_main(void *data)
 	return 0;
 }
 
+static void dp_hdcp2p2_abort(void *input, bool abort)
+{
+	struct dp_hdcp2p2_ctrl *ctrl = input;
+
+	atomic_set(&ctrl->abort, abort);
+}
+
 void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
 {
 	int rc;
@@ -896,6 +907,7 @@ void *sde_dp_hdcp2p2_init(struct sde_hdcp_init_data *init_data)
 		.set_mode = dp_hdcp2p2_register,
 		.on = dp_hdcp2p2_on,
 		.off = dp_hdcp2p2_off,
+		.abort = dp_hdcp2p2_abort,
 		.cp_irq = dp_hdcp2p2_cp_irq,
 		.register_streams = dp_hdcp2p2_register_streams,
 		.deregister_streams = dp_hdcp2p2_deregister_streams,

+ 2 - 1
msm/sde_hdcp.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2012, 2014-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2012, 2014-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __SDE_HDCP_H__
@@ -81,6 +81,7 @@ struct sde_hdcp_ops {
 	bool (*feature_supported)(void *input);
 	void (*force_encryption)(void *input, bool enable);
 	bool (*sink_support)(void *input);
+	void (*abort)(void *input, bool abort);
 	int (*set_mode)(void *input, bool mst_enabled);
 	int (*on)(void *input);
 	void (*off)(void *hdcp_ctrl);

+ 15 - 1
msm/sde_hdcp_1x.c

@@ -207,6 +207,7 @@ struct sde_hdcp_1x {
 	bool reauth;
 	bool ksv_ready;
 	bool force_encryption;
+	atomic_t abort;
 	enum sde_hdcp_state hdcp_state;
 	struct HDCP_V2V1_MSG_TOPOLOGY current_tp;
 	struct delayed_work hdcp_auth_work;
@@ -1040,7 +1041,7 @@ static void sde_hdcp_1x_update_auth_status(struct sde_hdcp_1x *hdcp)
 
 static void sde_hdcp_1x_auth_work(struct work_struct *work)
 {
-	int rc;
+	int rc = 0;
 	struct delayed_work *dw = to_delayed_work(work);
 	struct sde_hdcp_1x *hdcp = container_of(dw,
 		struct sde_hdcp_1x, hdcp_auth_work);
@@ -1056,6 +1057,9 @@ static void sde_hdcp_1x_auth_work(struct work_struct *work)
 		return;
 	}
 
+	if (atomic_read(&hdcp->abort))
+		goto end;
+
 	hdcp->sink_r0_ready = false;
 	hdcp->reauth = false;
 	hdcp->ksv_ready = false;
@@ -1484,6 +1488,15 @@ irq_not_handled:
 	return -EINVAL;
 }
 
+static void sde_hdcp_1x_abort(void *data, bool abort)
+{
+	struct sde_hdcp_1x *hdcp = data;
+
+	atomic_set(&hdcp->abort, abort);
+	cancel_delayed_work_sync(&hdcp->hdcp_auth_work);
+	flush_workqueue(hdcp->workq);
+}
+
 void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data)
 {
 	struct sde_hdcp_1x *hdcp = NULL;
@@ -1496,6 +1509,7 @@ void *sde_hdcp_1x_init(struct sde_hdcp_init_data *init_data)
 		.feature_supported = sde_hdcp_1x_feature_supported,
 		.force_encryption = sde_hdcp_1x_force_encryption,
 		.sink_support = sde_hdcp_1x_sink_support,
+		.abort = sde_hdcp_1x_abort,
 		.off = sde_hdcp_1x_off
 	};