Browse Source

disp: msm: dp: Enforce HDCP 2.3 timing requirements

The HDCP 2.3 specification added new timing
requirements for message read duration. Ensure
that these requirements are enforced in the DP
display layer.

Delay for a specification-allowed amount of time
before reading messages to ensure that sinks have
enough time to process messages and make their
replies available to read.

Change-Id: I40b210823a7cbaca6efc12abc4c8e8b98a10e071
Signed-off-by: Fuad Hossain <[email protected]>
Signed-off-by: Tatenda Chipeperekwa <[email protected]>
Tatenda Chipeperekwa 5 years ago
parent
commit
f7de094233
3 changed files with 87 additions and 44 deletions
  1. 22 12
      msm/dp/dp_hdcp2p2.c
  2. 48 20
      msm/sde_hdcp_2x.c
  3. 17 12
      msm/sde_hdcp_2x.h

+ 22 - 12
msm/dp/dp_hdcp2p2.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2016-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2016-2020, The Linux Foundation. All rights reserved.
  */
 
 #include <linux/delay.h>
@@ -44,7 +44,8 @@ struct dp_hdcp2p2_ctrl {
 	struct hdcp2_buffer response;
 	struct hdcp2_buffer request;
 	uint32_t total_message_length;
-	uint32_t timeout;
+	uint32_t transaction_delay;
+	uint32_t transaction_timeout;
 	struct sde_hdcp_2x_msg_part msg_part[HDCP_MAX_MESSAGE_PARTS];
 	u8 sink_rx_status;
 	u8 rx_status;
@@ -108,7 +109,6 @@ static int dp_hdcp2p2_copy_buf(struct dp_hdcp2p2_ctrl *ctrl,
 
 	mutex_lock(&ctrl->msg_lock);
 
-	ctrl->timeout = data->timeout;
 	num_messages = data->message_data->num_messages;
 	ctrl->total_message_length = 0; /* Total length of all messages */
 
@@ -132,6 +132,9 @@ static int dp_hdcp2p2_copy_buf(struct dp_hdcp2p2_ctrl *ctrl,
 	ctrl->request.data = data->buf;
 	ctrl->request.length = ctrl->total_message_length;
 
+	ctrl->transaction_delay = data->transaction_delay;
+	ctrl->transaction_timeout = data->transaction_timeout;
+
 	mutex_unlock(&ctrl->msg_lock);
 
 	return 0;
@@ -170,7 +173,6 @@ static void dp_hdcp2p2_set_interrupts(struct dp_hdcp2p2_ctrl *ctrl, bool enable)
 static int dp_hdcp2p2_wakeup(struct hdcp_transport_wakeup_data *data)
 {
 	struct dp_hdcp2p2_ctrl *ctrl;
-	u32 const default_timeout_us = 500;
 
 	if (!data) {
 		DP_ERR("invalid input\n");
@@ -183,11 +185,6 @@ static int dp_hdcp2p2_wakeup(struct hdcp_transport_wakeup_data *data)
 		return -EINVAL;
 	}
 
-	if (data->timeout)
-		ctrl->timeout = (data->timeout) * 2;
-	else
-		ctrl->timeout = default_timeout_us;
-
 	if (dp_hdcp2p2_copy_buf(ctrl, data))
 		goto exit;
 
@@ -364,6 +361,8 @@ static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl)
 	int rc = 0, max_size = 16, read_size = 0, bytes_read = 0;
 	int size = ctrl->request.length, offset = ctrl->msg_part->offset;
 	u8 *buf = ctrl->request.data;
+	s64 diff_ms;
+	ktime_t start_read, finish_read;
 
 	if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE ||
 		atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL) {
@@ -380,6 +379,7 @@ static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl)
 
 	DP_DEBUG("offset(0x%x), size(%d)\n", offset, size);
 
+	start_read = ktime_get();
 	do {
 		read_size = min(size, max_size);
 
@@ -396,7 +396,14 @@ static int dp_hdcp2p2_aux_read_message(struct dp_hdcp2p2_ctrl *ctrl)
 		offset += read_size;
 		size -= read_size;
 	} while (size > 0);
+	finish_read = ktime_get();
+	diff_ms = ktime_ms_delta(finish_read, start_read);
 
+	if (ctrl->transaction_timeout && diff_ms > ctrl->transaction_timeout) {
+		DP_ERR("HDCP read timeout exceeded (%dms > %dms)\n", diff_ms,
+				ctrl->transaction_timeout);
+		rc = -ETIMEDOUT;
+	}
 exit:
 	return rc;
 }
@@ -485,7 +492,7 @@ static void dp_hdcp2p2_send_msg(struct dp_hdcp2p2_ctrl *ctrl)
 
 	rc = dp_hdcp2p2_aux_write_message(ctrl, ctrl->response.data,
 			ctrl->response.length, ctrl->msg_part->offset,
-			ctrl->timeout);
+			ctrl->transaction_delay);
 	if (rc) {
 		DP_ERR("Error sending msg to sink %d\n", rc);
 		mutex_unlock(&ctrl->msg_lock);
@@ -493,7 +500,7 @@ static void dp_hdcp2p2_send_msg(struct dp_hdcp2p2_ctrl *ctrl)
 	}
 
 	cdata.cmd = HDCP_2X_CMD_MSG_SEND_SUCCESS;
-	cdata.timeout = ctrl->timeout;
+	cdata.timeout = ctrl->transaction_delay;
 	mutex_unlock(&ctrl->msg_lock);
 
 exit:
@@ -519,7 +526,7 @@ static int dp_hdcp2p2_get_msg_from_sink(struct dp_hdcp2p2_ctrl *ctrl)
 	}
 
 	cdata.total_message_length = ctrl->total_message_length;
-	cdata.timeout = ctrl->timeout;
+	cdata.timeout = ctrl->transaction_delay;
 exit:
 	if (rc == -ETIMEDOUT)
 		cdata.cmd = HDCP_2X_CMD_MSG_RECV_TIMEOUT;
@@ -544,6 +551,9 @@ static void dp_hdcp2p2_recv_msg(struct dp_hdcp2p2_ctrl *ctrl)
 		return;
 	}
 
+	if (ctrl->transaction_delay)
+		msleep(ctrl->transaction_delay);
+
 	dp_hdcp2p2_get_msg_from_sink(ctrl);
 }
 

+ 48 - 20
msm/sde_hdcp_2x.c

@@ -1,6 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
  */
 
 #define pr_fmt(fmt)	"[sde-hdcp-2x] %s: " fmt, __func__
@@ -42,6 +42,9 @@
 #define REAUTH_REQ BIT(3)
 #define LINK_INTEGRITY_FAILURE BIT(4)
 
+/* Temporary define to override wrong TZ value */
+#define AKE_SEND_CERT_MSG_DELAY 100
+
 struct sde_hdcp_2x_ctrl {
 	DECLARE_KFIFO(cmd_q, enum sde_hdcp_2x_wakeup_cmd, 8);
 	wait_queue_head_t wait_q;
@@ -100,49 +103,49 @@ static const struct sde_hdcp_2x_msg_data
 				hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = {
 	[AKE_INIT] = { 2,
 		{ {"rtx", 0x69000, 8}, {"TxCaps", 0x69008, 3} },
-		0 },
+		0, 0 },
 	[AKE_SEND_CERT] = { 3,
 		{ {"cert-rx", 0x6900B, 522}, {"rrx", 0x69215, 8},
 			{"RxCaps", 0x6921D, 3} },
-		0 },
+		0, 110 },
 	[AKE_NO_STORED_KM] = { 1,
 		{ {"Ekpub_km", 0x69220, 128} },
-		0 },
+		0, 0 },
 	[AKE_STORED_KM] = { 2,
 		{ {"Ekh_km", 0x692A0, 16}, {"m", 0x692B0, 16} },
-		0 },
+		0, 0 },
 	[AKE_SEND_H_PRIME] = { 1,
 		{ {"H'", 0x692C0, 32} },
-		(1 << 1) },
+		(1 << 1), 7 },
 	[AKE_SEND_PAIRING_INFO] =  { 1,
 		{ {"Ekh_km", 0x692E0, 16} },
-		(1 << 2) },
+		(1 << 2), 5 },
 	[LC_INIT] = { 1,
 		{ {"rn", 0x692F0, 8} },
-		0 },
+		0, 0 },
 	[LC_SEND_L_PRIME] = { 1,
 		{ {"L'", 0x692F8, 32} },
-		0 },
+		0, 0 },
 	[SKE_SEND_EKS] = { 2,
 		{ {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} },
-		0 },
+		0, 0 },
 	[SKE_SEND_TYPE_ID] = { 1,
 		{ {"type", 0x69494, 1} },
-		0 },
+		0, 0 },
 	[REP_SEND_RECV_ID_LIST] = { 4,
 		{ {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3},
 			{"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} },
-		(1 << 0) },
+		(1 << 0), 0 },
 	[REP_SEND_ACK] = { 1,
 		{ {"V", 0x693E0, 16} },
-		0 },
+		0, 0 },
 	[REP_STREAM_MANAGE] = { 3,
 		{ {"seq_num_M", 0x693F0, 3}, {"k", 0x693F3, 2},
 			{"streamID_Type", 0x693F5, 126} },
-		0 },
+		0, 0 },
 	[REP_STREAM_READY] = { 1,
 		{ {"M'", 0x69473, 32} },
-		0 },
+		0, 7 },
 };
 
 static int sde_hdcp_2x_get_next_message(struct sde_hdcp_2x_ctrl *hdcp,
@@ -247,6 +250,29 @@ static void sde_hdcp_2x_wait_for_response(struct sde_hdcp_2x_ctrl *hdcp)
 	hdcp->wait_timeout_ms = 0;
 }
 
+static void sde_hdcp_2x_adjust_transaction_params(
+		struct sde_hdcp_2x_ctrl *hdcp,
+		struct hdcp_transport_wakeup_data *data)
+{
+	switch (hdcp->last_msg) {
+	case AKE_SEND_CERT:
+		data->transaction_delay = AKE_SEND_CERT_MSG_DELAY;
+		break;
+	case REP_STREAM_READY:
+		break;
+	default:
+		data->transaction_delay = 0;
+		break;
+	}
+
+	data->transaction_timeout =
+			hdcp_msg_lookup[hdcp->last_msg].transaction_timeout;
+
+	pr_debug("%s: transaction delay: %ums, transaction timeout: %ums\n",
+			sde_hdcp_2x_message_name(hdcp->last_msg),
+			data->transaction_delay, data->transaction_timeout);
+}
+
 static void sde_hdcp_2x_wakeup_client(struct sde_hdcp_2x_ctrl *hdcp,
 				struct hdcp_transport_wakeup_data *data)
 {
@@ -271,6 +297,8 @@ static void sde_hdcp_2x_wakeup_client(struct sde_hdcp_2x_ctrl *hdcp,
 		data->message_data = &hdcp_msg_lookup[hdcp->last_msg];
 	}
 
+	sde_hdcp_2x_adjust_transaction_params(hdcp, data);
+
 	rc = hdcp->client_ops->wakeup(data);
 	if (rc)
 		pr_err("error sending %s to client\n",
@@ -285,7 +313,7 @@ static inline void sde_hdcp_2x_send_message(struct sde_hdcp_2x_ctrl *hdcp)
 					HDCP_TRANSPORT_CMD_SEND_MESSAGE };
 
 	cdata.context = hdcp->client_data;
-	cdata.timeout = hdcp->app_data.timeout;
+	cdata.transaction_delay = hdcp->app_data.timeout;
 	cdata.buf_len = hdcp->app_data.response.length;
 
 	/* ignore the first byte as it contains the message id */
@@ -436,7 +464,7 @@ static void sde_hdcp_2x_initialize_command(struct sde_hdcp_2x_ctrl *hdcp,
 		struct hdcp_transport_wakeup_data *cdata)
 {
 		cdata->cmd = cmd;
-		cdata->timeout = hdcp->timeout_left;
+		cdata->transaction_delay = hdcp->timeout_left;
 		cdata->buf = hdcp->app_data.request.data + 1;
 }
 
@@ -492,7 +520,7 @@ static void sde_hdcp_2x_msg_sent(struct sde_hdcp_2x_ctrl *hdcp)
 		break;
 	default:
 		cdata.cmd = HDCP_TRANSPORT_CMD_RECV_MESSAGE;
-		cdata.timeout = hdcp->timeout_left;
+		cdata.transaction_delay = hdcp->app_data.timeout;
 		cdata.buf = hdcp->app_data.request.data + 1;
 	}
 
@@ -593,7 +621,7 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)
 
 	if (msg[0] == AKE_SEND_H_PRIME && hdcp->no_stored_km) {
 		cdata.cmd = HDCP_TRANSPORT_CMD_RECV_MESSAGE;
-		cdata.timeout = hdcp->app_data.timeout;
+		cdata.transaction_delay = hdcp->app_data.timeout;
 		cdata.buf = hdcp->app_data.request.data + 1;
 		goto exit;
 	}
@@ -653,7 +681,7 @@ static void sde_hdcp_2x_msg_recvd(struct sde_hdcp_2x_ctrl *hdcp)
 		cdata.cmd = HDCP_TRANSPORT_CMD_SEND_MESSAGE;
 		cdata.buf = hdcp->app_data.response.data + 1;
 		cdata.buf_len = hdcp->app_data.response.length;
-		cdata.timeout = hdcp->app_data.timeout;
+		cdata.transaction_delay = hdcp->app_data.timeout;
 	}
 exit:
 	sde_hdcp_2x_wakeup_client(hdcp, &cdata);

+ 17 - 12
msm/sde_hdcp_2x.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2015-2019, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2015-2020, The Linux Foundation. All rights reserved.
  */
 
 #ifndef __SDE_HDCP_2X_H__
@@ -114,32 +114,37 @@ struct sde_hdcp_2x_msg_part {
 
 /**
  * struct sde_hdcp_2x_msg_data - HDCP 2.2 message containing one or more parts
- * @num_messages:   total number of parts in a full message
- * @messages:       array containing num_messages parts
- * @rx_status:      value of rx_status register
+ * @num_messages:          total number of parts in a full message
+ * @messages:              array containing num_messages parts
+ * @rx_status:             value of rx_status register
+ * @transaction_timeout:   maximum duration to read/write message from/to sink
  */
 struct sde_hdcp_2x_msg_data {
 	uint32_t num_messages;
 	struct sde_hdcp_2x_msg_part messages[HDCP_MAX_MESSAGE_PARTS];
 	uint8_t rx_status;
+	uint32_t transaction_timeout;
 };
 
 /**
  * struct hdcp_transport_wakeup_data - data sent to display transport layer
- * @cmd:            command type
- * @context:        void pointer to the display transport layer
- * @send_msg_buf:   buffer containing message to be sent to sink
- * @send_msg_len:   length of the message to be sent to sink
- * @timeout:        timeout value for timed transactions
- * @abort_mask:     mask used to determine whether HDCP link is valid
- * @message_data:   a pointer to the message description
+ * @cmd:                  command type
+ * @context:              void pointer to the display transport layer
+ * @send_msg_buf:         buffer containing message to be sent to sink
+ * @send_msg_len:         length of the message to be sent to sink
+ * @timeout:              timeout value for timed transactions
+ * @abort_mask:           mask used to determine whether HDCP link is valid
+ * @message_data:         a pointer to the message description
+ * @transaction_delay:    amount of time to delay before performing transaction
+ * @transaction_timeout:  maximum duration to read/write message from/to sink
  */
 struct hdcp_transport_wakeup_data {
 	enum hdcp_transport_wakeup_cmd cmd;
 	void *context;
 	unsigned char *buf;
 	u32 buf_len;
-	u32 timeout;
+	u32 transaction_delay;
+	u32 transaction_timeout;
 	u8 abort_mask;
 	const struct sde_hdcp_2x_msg_data *message_data;
 };