ソースを参照

driver : hdcp_qseecom: Retry HDCP key verify when Qseecomd down

HDCP has a dependency on Qseecomd for HDCP key
verification and other SCM calls. Qseecomd takes
a lot of time to be available during boot because
of which HDCP init fails.
Adding retry mechanism only when there is hdcp key
verification failure due to Qseecomd not starting
in time. For other error codes, like HDCP key not
programmed, there will be no retry.
If Qseecomd doesn’t come up within maximum retries,
code will stop retrying and hdcp key verification
will fail. For each retry, there is a sleep of 100ms.
The number of retries can be changed from the dtsi file.
By default, we are allowing 40 retries but it can be
changed. 40 retries are based on the qseecomd KPI which
can be anywhere between 2.9 sec to 3.6 sec.

Change-Id: I3661b349ec44604147d6e6700307fa416904bbfa
Signed-off-by: Shubham Dhiman <[email protected]>
Shubham Dhiman 1 年間 前
コミット
bae6b391eb
4 ファイル変更115 行追加22 行削除
  1. 34 14
      hdcp/hdcp_main.c
  2. 6 0
      hdcp/hdcp_main.h
  3. 55 8
      hdcp/hdcp_qseecom.c
  4. 20 0
      hdcp/hdcp_qseecom.h

+ 34 - 14
hdcp/hdcp_main.c

@@ -105,7 +105,7 @@ bool hdcp2_feature_supported(void *data)
 
 	return ret;
 }
-EXPORT_SYMBOL(hdcp2_feature_supported);
+EXPORT_SYMBOL_GPL(hdcp2_feature_supported);
 
 int hdcp2_force_encryption(void *ctx, uint32_t enable)
 {
@@ -117,7 +117,7 @@ int hdcp2_force_encryption(void *ctx, uint32_t enable)
 
 	return ret;
 }
-EXPORT_SYMBOL(hdcp2_force_encryption);
+EXPORT_SYMBOL_GPL(hdcp2_force_encryption);
 
 int hdcp2_app_comm(void *ctx, enum hdcp2_app_cmd cmd,
 				   struct hdcp2_app_data *app_data)
@@ -168,7 +168,7 @@ error:
 	mutex_unlock(&hdcp2_mutex_g);
 	return ret;
 }
-EXPORT_SYMBOL(hdcp2_app_comm);
+EXPORT_SYMBOL_GPL(hdcp2_app_comm);
 
 int hdcp2_open_stream(void *ctx, uint8_t vc_payload_id, uint8_t stream_number,
 		  uint32_t *stream_id)
@@ -182,7 +182,7 @@ int hdcp2_open_stream(void *ctx, uint8_t vc_payload_id, uint8_t stream_number,
 
 	return ret;
 }
-EXPORT_SYMBOL(hdcp2_open_stream);
+EXPORT_SYMBOL_GPL(hdcp2_open_stream);
 
 int hdcp2_close_stream(void *ctx, uint32_t stream_id)
 {
@@ -194,7 +194,7 @@ int hdcp2_close_stream(void *ctx, uint32_t stream_id)
 
 	return ret;
 }
-EXPORT_SYMBOL(hdcp2_close_stream);
+EXPORT_SYMBOL_GPL(hdcp2_close_stream);
 
 void *hdcp2_init(u32 device_type)
 {
@@ -206,13 +206,23 @@ void *hdcp2_init(u32 device_type)
 
 	return data;
 }
-EXPORT_SYMBOL(hdcp2_init);
+EXPORT_SYMBOL_GPL(hdcp2_init);
+
+void hdcp2_set_hdcp_key_verify_retries(void *ctx, u32 max_hdcp_key_verify_retries)
+{
+	struct hdcp2_qsee_handle *handle = ctx;
+
+	handle->max_hdcp_key_verify_retries = max_hdcp_key_verify_retries;
+
+	pr_debug("hdcp2 max_hdcp_key_verify_retries %d\n", handle->max_hdcp_key_verify_retries);
+}
+EXPORT_SYMBOL_GPL(hdcp2_set_hdcp_key_verify_retries);
 
 void hdcp2_deinit(void *ctx)
 {
 	ta_interface.trusted_app_hdcp2_deinit(ctx);
 }
-EXPORT_SYMBOL(hdcp2_deinit);
+EXPORT_SYMBOL_GPL(hdcp2_deinit);
 
 void *hdcp1_init(void)
 {
@@ -224,13 +234,23 @@ void *hdcp1_init(void)
 
 	return data;
 }
-EXPORT_SYMBOL(hdcp1_init);
+EXPORT_SYMBOL_GPL(hdcp1_init);
+
+void hdcp1_set_hdcp_key_verify_retries(void *ctx, u32 max_hdcp_key_verify_retries)
+{
+	struct hdcp1_qsee_handle *handle = ctx;
+
+	handle->max_hdcp_key_verify_retries = max_hdcp_key_verify_retries;
+
+	pr_debug("hdcp1 max_hdcp_key_verify_retries %d\n", handle->max_hdcp_key_verify_retries);
+}
+EXPORT_SYMBOL_GPL(hdcp1_set_hdcp_key_verify_retries);
 
 void hdcp1_deinit(void *data)
 {
 	kfree(data);
 }
-EXPORT_SYMBOL(hdcp1_deinit);
+EXPORT_SYMBOL_GPL(hdcp1_deinit);
 
 bool hdcp1_feature_supported(void *data)
 {
@@ -242,7 +262,7 @@ bool hdcp1_feature_supported(void *data)
 
 	return supported;
 }
-EXPORT_SYMBOL(hdcp1_feature_supported);
+EXPORT_SYMBOL_GPL(hdcp1_feature_supported);
 
 int hdcp1_set_enc(void *data, bool enable)
 {
@@ -254,7 +274,7 @@ int hdcp1_set_enc(void *data, bool enable)
 
 	return ret;
 }
-EXPORT_SYMBOL(hdcp1_set_enc);
+EXPORT_SYMBOL_GPL(hdcp1_set_enc);
 
 int hdcp1_ops_notify(void *data, void *topo, bool is_authenticated)
 {
@@ -264,7 +284,7 @@ int hdcp1_ops_notify(void *data, void *topo, bool is_authenticated)
 
 	return ret;
 }
-EXPORT_SYMBOL(hdcp1_ops_notify);
+EXPORT_SYMBOL_GPL(hdcp1_ops_notify);
 
 int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb)
 {
@@ -276,7 +296,7 @@ int hdcp1_start(void *data, u32 *aksv_msb, u32 *aksv_lsb)
 
 	return ret;
 }
-EXPORT_SYMBOL(hdcp1_start);
+EXPORT_SYMBOL_GPL(hdcp1_start);
 
 void hdcp1_stop(void *data)
 {
@@ -284,7 +304,7 @@ void hdcp1_stop(void *data)
 	ta_interface.trusted_app_hdcp1_stop(data);
 	mutex_unlock(&hdcp1_mutex_g);
 }
-EXPORT_SYMBOL(hdcp1_stop);
+EXPORT_SYMBOL_GPL(hdcp1_stop);
 
 static int __init hdcp_module_init(void)
 {

+ 6 - 0
hdcp/hdcp_main.h

@@ -56,6 +56,12 @@
 /* Wait 200ms after authentication */
 #define SLEEP_FORCE_ENCRYPTION_MS 200
 
+/* Error code when Qseecomd is not up at boot time */
+#define QSEECOMD_ERROR -4103
+
+/* Wait for 100ms on every retry to check if Qseecomd is up */
+#define SLEEP_QSEECOMD_WAIT_MS 100
+
 #define SLEEP_SET_HW_KEY_MS 300
 
 /* flags set by tz in response message */

+ 55 - 8
hdcp/hdcp_qseecom.c

@@ -323,6 +323,12 @@ static int hdcp1_verify_key(struct hdcp1_qsee_handle *hdcp1_handle)
 	}
 
 	rc = key_verify_rsp->ret;
+
+	if (rc == QSEECOMD_ERROR)
+		qseecomd_down = true;
+	else
+		qseecomd_down = false;
+
 	if (rc) {
 		pr_err("key_verify failed, rsp=%d\n", key_verify_rsp->ret);
 		return -EINVAL;
@@ -385,6 +391,11 @@ static int hdcp2_verify_key(struct hdcp2_qsee_handle *handle)
 	rc = hdcp2_app_process_cmd(verify_key);
 	pr_debug("verify_key = %d\n", rc);
 
+	if (rsp_buf->status == QSEECOMD_ERROR)
+		qseecomd_down = true;
+	else
+		qseecomd_down = false;
+
 error:
 	return rc;
 }
@@ -468,6 +479,7 @@ bool hdcp1_feature_supported_qseecom(void *data)
 	bool supported = false;
 	struct hdcp1_qsee_handle *handle = data;
 	int rc = 0;
+	int retry = 0;
 
 	if (!handle) {
 		pr_err("invalid handle\n");
@@ -480,11 +492,31 @@ bool hdcp1_feature_supported_qseecom(void *data)
 	}
 
 	rc = hdcp1_app_load(handle);
+
+	/* Other than in SUCCESS case, if there is a FAILURE when
+	 * handle is NULL, the hdcp1_app_load will return zero.
+	 * Checking the hdcp_state will ensure that the conditional
+	 * is ONLY true when hdcp1_app_load had no Failures.
+	 */
 	if (!rc && (handle->hdcp_state & HDCP_STATE_APP_LOADED)) {
-		if (!hdcp1_verify_key(handle)) {
-			pr_debug("HDCP 1.x supported\n");
-			handle->feature_supported = true;
-			supported = true;
+		do {
+			if (!hdcp1_verify_key(handle)) {
+				pr_debug("HDCP 1.x supported\n");
+				pr_debug("hdcp1_verify_key succeeded on %d retry.\n", retry);
+				handle->feature_supported = true;
+				supported = true;
+				break;
+			} else if (qseecomd_down) {
+				pr_debug("Qseecomd is not up. Going to sleep.\n");
+				msleep(SLEEP_QSEECOMD_WAIT_MS);
+				retry++;
+			} else
+				break;
+		} while (handle->max_hdcp_key_verify_retries >= retry);
+
+		if (qseecomd_down) {
+			pr_err("hdcp1_verify_key failed after %d retries as Qseecomd is not up.\n",
+				handle->max_hdcp_key_verify_retries);
 		}
 		hdcp1_app_unload(handle);
 	}
@@ -1252,6 +1284,7 @@ error:
 bool hdcp2_feature_supported_qseecom(void *ctx)
 {
 	int rc = 0;
+	int retry = 0;
 	bool supported = false;
 	struct hdcp2_qsee_handle *handle = (struct hdcp2_qsee_handle *)ctx;
 
@@ -1268,10 +1301,24 @@ bool hdcp2_feature_supported_qseecom(void *ctx)
 
 	rc = hdcp2_app_load(handle);
 	if (!rc) {
-		if (!hdcp2_verify_key(handle)) {
-			pr_debug("HDCP 2.2 supported\n");
-			handle->feature_supported = true;
-			supported = true;
+		do {
+			if (!hdcp2_verify_key(handle)) {
+				pr_debug("HDCP 2.2 supported.\n");
+				pr_debug("hdcp2_verify_key succeeded on %d retry.\n", retry);
+				handle->feature_supported = true;
+				supported = true;
+				break;
+			} else if (qseecomd_down) {
+				pr_debug("Qseecomd is not up. Going to sleep.\n");
+				msleep(SLEEP_QSEECOMD_WAIT_MS);
+				retry++;
+			} else
+				break;
+		} while (handle->max_hdcp_key_verify_retries >= retry);
+
+		if (qseecomd_down) {
+			pr_err("hdcp2_verify_key failed after %d retries as Qseecomd is not up.\n",
+				handle->max_hdcp_key_verify_retries);
 		}
 		hdcp2_app_unload(handle);
 	}

+ 20 - 0
hdcp/hdcp_qseecom.h

@@ -13,6 +13,11 @@
 
 #include "hdcp_main.h"
 
+/*
+ * @max_hdcp_key_verify_retries - Max number of retries by default set to 0 which
+ *                                is equivalent to 0MS. Actual value will be the one
+ *                                from the dtsi file.
+ */
 struct hdcp1_qsee_handle {
 	struct qseecom_handle *qseecom_handle;
 	struct qseecom_handle *hdcpops_handle;
@@ -20,8 +25,22 @@ struct hdcp1_qsee_handle {
 	uint32_t device_type;
 	enum hdcp_state hdcp_state;
 	char *app_name;
+	uint32_t max_hdcp_key_verify_retries;
 };
 
+/*
+ * If Qseecomd starts late and hdcp key
+ * verification has already started, qseecomd_down
+ * flag will be set to true. It will be set to false
+ * once the Qseecomd is up. Initial assumption is
+ * that the Qseecomd will start in time.
+ */
+static bool qseecomd_down;
+/*
+ * @max_hdcp_key_verify_retries - Max number of retries by default set to 0 which
+ *                                is equivalent to 0MS. Actual value will be the one
+ *                                from the dtsi file.
+ */
 struct hdcp2_qsee_handle {
 	struct hdcp2_app_data app_data;
 	uint32_t tz_ctxhandle;
@@ -37,6 +56,7 @@ struct hdcp2_qsee_handle {
 	unsigned char *res_buf;
 	int (*app_init)(struct hdcp2_qsee_handle *handle);
 	int (*tx_init)(struct hdcp2_qsee_handle *handle);
+	uint32_t max_hdcp_key_verify_retries;
 };
 
 struct hdcp1_key_set_req {