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 <fhossain@codeaurora.org>
Signed-off-by: Tatenda Chipeperekwa <tatendac@codeaurora.org>
This commit is contained in:
Tatenda Chipeperekwa
2019-11-05 12:25:18 -05:00
parent 3e26909b0a
commit f7de094233
3 changed files with 87 additions and 44 deletions

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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> #include <linux/delay.h>
@@ -44,7 +44,8 @@ struct dp_hdcp2p2_ctrl {
struct hdcp2_buffer response; struct hdcp2_buffer response;
struct hdcp2_buffer request; struct hdcp2_buffer request;
uint32_t total_message_length; 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]; struct sde_hdcp_2x_msg_part msg_part[HDCP_MAX_MESSAGE_PARTS];
u8 sink_rx_status; u8 sink_rx_status;
u8 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); mutex_lock(&ctrl->msg_lock);
ctrl->timeout = data->timeout;
num_messages = data->message_data->num_messages; num_messages = data->message_data->num_messages;
ctrl->total_message_length = 0; /* Total length of all 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.data = data->buf;
ctrl->request.length = ctrl->total_message_length; ctrl->request.length = ctrl->total_message_length;
ctrl->transaction_delay = data->transaction_delay;
ctrl->transaction_timeout = data->transaction_timeout;
mutex_unlock(&ctrl->msg_lock); mutex_unlock(&ctrl->msg_lock);
return 0; 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) static int dp_hdcp2p2_wakeup(struct hdcp_transport_wakeup_data *data)
{ {
struct dp_hdcp2p2_ctrl *ctrl; struct dp_hdcp2p2_ctrl *ctrl;
u32 const default_timeout_us = 500;
if (!data) { if (!data) {
DP_ERR("invalid input\n"); DP_ERR("invalid input\n");
@@ -183,11 +185,6 @@ static int dp_hdcp2p2_wakeup(struct hdcp_transport_wakeup_data *data)
return -EINVAL; return -EINVAL;
} }
if (data->timeout)
ctrl->timeout = (data->timeout) * 2;
else
ctrl->timeout = default_timeout_us;
if (dp_hdcp2p2_copy_buf(ctrl, data)) if (dp_hdcp2p2_copy_buf(ctrl, data))
goto exit; 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 rc = 0, max_size = 16, read_size = 0, bytes_read = 0;
int size = ctrl->request.length, offset = ctrl->msg_part->offset; int size = ctrl->request.length, offset = ctrl->msg_part->offset;
u8 *buf = ctrl->request.data; u8 *buf = ctrl->request.data;
s64 diff_ms;
ktime_t start_read, finish_read;
if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE || if (atomic_read(&ctrl->auth_state) == HDCP_STATE_INACTIVE ||
atomic_read(&ctrl->auth_state) == HDCP_STATE_AUTH_FAIL) { 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); DP_DEBUG("offset(0x%x), size(%d)\n", offset, size);
start_read = ktime_get();
do { do {
read_size = min(size, max_size); 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; offset += read_size;
size -= read_size; size -= read_size;
} while (size > 0); } 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: exit:
return rc; 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, rc = dp_hdcp2p2_aux_write_message(ctrl, ctrl->response.data,
ctrl->response.length, ctrl->msg_part->offset, ctrl->response.length, ctrl->msg_part->offset,
ctrl->timeout); ctrl->transaction_delay);
if (rc) { if (rc) {
DP_ERR("Error sending msg to sink %d\n", rc); DP_ERR("Error sending msg to sink %d\n", rc);
mutex_unlock(&ctrl->msg_lock); 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.cmd = HDCP_2X_CMD_MSG_SEND_SUCCESS;
cdata.timeout = ctrl->timeout; cdata.timeout = ctrl->transaction_delay;
mutex_unlock(&ctrl->msg_lock); mutex_unlock(&ctrl->msg_lock);
exit: 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.total_message_length = ctrl->total_message_length;
cdata.timeout = ctrl->timeout; cdata.timeout = ctrl->transaction_delay;
exit: exit:
if (rc == -ETIMEDOUT) if (rc == -ETIMEDOUT)
cdata.cmd = HDCP_2X_CMD_MSG_RECV_TIMEOUT; cdata.cmd = HDCP_2X_CMD_MSG_RECV_TIMEOUT;
@@ -544,6 +551,9 @@ static void dp_hdcp2p2_recv_msg(struct dp_hdcp2p2_ctrl *ctrl)
return; return;
} }
if (ctrl->transaction_delay)
msleep(ctrl->transaction_delay);
dp_hdcp2p2_get_msg_from_sink(ctrl); dp_hdcp2p2_get_msg_from_sink(ctrl);
} }

View File

@@ -1,6 +1,6 @@
// SPDX-License-Identifier: GPL-2.0-only // 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__ #define pr_fmt(fmt) "[sde-hdcp-2x] %s: " fmt, __func__
@@ -42,6 +42,9 @@
#define REAUTH_REQ BIT(3) #define REAUTH_REQ BIT(3)
#define LINK_INTEGRITY_FAILURE BIT(4) #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 { struct sde_hdcp_2x_ctrl {
DECLARE_KFIFO(cmd_q, enum sde_hdcp_2x_wakeup_cmd, 8); DECLARE_KFIFO(cmd_q, enum sde_hdcp_2x_wakeup_cmd, 8);
wait_queue_head_t wait_q; wait_queue_head_t wait_q;
@@ -100,49 +103,49 @@ static const struct sde_hdcp_2x_msg_data
hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = { hdcp_msg_lookup[HDCP2P2_MAX_MESSAGES] = {
[AKE_INIT] = { 2, [AKE_INIT] = { 2,
{ {"rtx", 0x69000, 8}, {"TxCaps", 0x69008, 3} }, { {"rtx", 0x69000, 8}, {"TxCaps", 0x69008, 3} },
0 }, 0, 0 },
[AKE_SEND_CERT] = { 3, [AKE_SEND_CERT] = { 3,
{ {"cert-rx", 0x6900B, 522}, {"rrx", 0x69215, 8}, { {"cert-rx", 0x6900B, 522}, {"rrx", 0x69215, 8},
{"RxCaps", 0x6921D, 3} }, {"RxCaps", 0x6921D, 3} },
0 }, 0, 110 },
[AKE_NO_STORED_KM] = { 1, [AKE_NO_STORED_KM] = { 1,
{ {"Ekpub_km", 0x69220, 128} }, { {"Ekpub_km", 0x69220, 128} },
0 }, 0, 0 },
[AKE_STORED_KM] = { 2, [AKE_STORED_KM] = { 2,
{ {"Ekh_km", 0x692A0, 16}, {"m", 0x692B0, 16} }, { {"Ekh_km", 0x692A0, 16}, {"m", 0x692B0, 16} },
0 }, 0, 0 },
[AKE_SEND_H_PRIME] = { 1, [AKE_SEND_H_PRIME] = { 1,
{ {"H'", 0x692C0, 32} }, { {"H'", 0x692C0, 32} },
(1 << 1) }, (1 << 1), 7 },
[AKE_SEND_PAIRING_INFO] = { 1, [AKE_SEND_PAIRING_INFO] = { 1,
{ {"Ekh_km", 0x692E0, 16} }, { {"Ekh_km", 0x692E0, 16} },
(1 << 2) }, (1 << 2), 5 },
[LC_INIT] = { 1, [LC_INIT] = { 1,
{ {"rn", 0x692F0, 8} }, { {"rn", 0x692F0, 8} },
0 }, 0, 0 },
[LC_SEND_L_PRIME] = { 1, [LC_SEND_L_PRIME] = { 1,
{ {"L'", 0x692F8, 32} }, { {"L'", 0x692F8, 32} },
0 }, 0, 0 },
[SKE_SEND_EKS] = { 2, [SKE_SEND_EKS] = { 2,
{ {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} }, { {"Edkey_ks", 0x69318, 16}, {"riv", 0x69328, 8} },
0 }, 0, 0 },
[SKE_SEND_TYPE_ID] = { 1, [SKE_SEND_TYPE_ID] = { 1,
{ {"type", 0x69494, 1} }, { {"type", 0x69494, 1} },
0 }, 0, 0 },
[REP_SEND_RECV_ID_LIST] = { 4, [REP_SEND_RECV_ID_LIST] = { 4,
{ {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3}, { {"RxInfo", 0x69330, 2}, {"seq_num_V", 0x69332, 3},
{"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} }, {"V'", 0x69335, 16}, {"ridlist", 0x69345, 155} },
(1 << 0) }, (1 << 0), 0 },
[REP_SEND_ACK] = { 1, [REP_SEND_ACK] = { 1,
{ {"V", 0x693E0, 16} }, { {"V", 0x693E0, 16} },
0 }, 0, 0 },
[REP_STREAM_MANAGE] = { 3, [REP_STREAM_MANAGE] = { 3,
{ {"seq_num_M", 0x693F0, 3}, {"k", 0x693F3, 2}, { {"seq_num_M", 0x693F0, 3}, {"k", 0x693F3, 2},
{"streamID_Type", 0x693F5, 126} }, {"streamID_Type", 0x693F5, 126} },
0 }, 0, 0 },
[REP_STREAM_READY] = { 1, [REP_STREAM_READY] = { 1,
{ {"M'", 0x69473, 32} }, { {"M'", 0x69473, 32} },
0 }, 0, 7 },
}; };
static int sde_hdcp_2x_get_next_message(struct sde_hdcp_2x_ctrl *hdcp, 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; 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, static void sde_hdcp_2x_wakeup_client(struct sde_hdcp_2x_ctrl *hdcp,
struct hdcp_transport_wakeup_data *data) 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]; data->message_data = &hdcp_msg_lookup[hdcp->last_msg];
} }
sde_hdcp_2x_adjust_transaction_params(hdcp, data);
rc = hdcp->client_ops->wakeup(data); rc = hdcp->client_ops->wakeup(data);
if (rc) if (rc)
pr_err("error sending %s to client\n", 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 }; HDCP_TRANSPORT_CMD_SEND_MESSAGE };
cdata.context = hdcp->client_data; 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; cdata.buf_len = hdcp->app_data.response.length;
/* ignore the first byte as it contains the message id */ /* 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) struct hdcp_transport_wakeup_data *cdata)
{ {
cdata->cmd = cmd; cdata->cmd = cmd;
cdata->timeout = hdcp->timeout_left; cdata->transaction_delay = hdcp->timeout_left;
cdata->buf = hdcp->app_data.request.data + 1; 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; break;
default: default:
cdata.cmd = HDCP_TRANSPORT_CMD_RECV_MESSAGE; 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; 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) { if (msg[0] == AKE_SEND_H_PRIME && hdcp->no_stored_km) {
cdata.cmd = HDCP_TRANSPORT_CMD_RECV_MESSAGE; 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; cdata.buf = hdcp->app_data.request.data + 1;
goto exit; 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.cmd = HDCP_TRANSPORT_CMD_SEND_MESSAGE;
cdata.buf = hdcp->app_data.response.data + 1; cdata.buf = hdcp->app_data.response.data + 1;
cdata.buf_len = hdcp->app_data.response.length; cdata.buf_len = hdcp->app_data.response.length;
cdata.timeout = hdcp->app_data.timeout; cdata.transaction_delay = hdcp->app_data.timeout;
} }
exit: exit:
sde_hdcp_2x_wakeup_client(hdcp, &cdata); sde_hdcp_2x_wakeup_client(hdcp, &cdata);

View File

@@ -1,6 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* 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__ #ifndef __SDE_HDCP_2X_H__
@@ -117,11 +117,13 @@ struct sde_hdcp_2x_msg_part {
* @num_messages: total number of parts in a full message * @num_messages: total number of parts in a full message
* @messages: array containing num_messages parts * @messages: array containing num_messages parts
* @rx_status: value of rx_status register * @rx_status: value of rx_status register
* @transaction_timeout: maximum duration to read/write message from/to sink
*/ */
struct sde_hdcp_2x_msg_data { struct sde_hdcp_2x_msg_data {
uint32_t num_messages; uint32_t num_messages;
struct sde_hdcp_2x_msg_part messages[HDCP_MAX_MESSAGE_PARTS]; struct sde_hdcp_2x_msg_part messages[HDCP_MAX_MESSAGE_PARTS];
uint8_t rx_status; uint8_t rx_status;
uint32_t transaction_timeout;
}; };
/** /**
@@ -133,13 +135,16 @@ struct sde_hdcp_2x_msg_data {
* @timeout: timeout value for timed transactions * @timeout: timeout value for timed transactions
* @abort_mask: mask used to determine whether HDCP link is valid * @abort_mask: mask used to determine whether HDCP link is valid
* @message_data: a pointer to the message description * @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 { struct hdcp_transport_wakeup_data {
enum hdcp_transport_wakeup_cmd cmd; enum hdcp_transport_wakeup_cmd cmd;
void *context; void *context;
unsigned char *buf; unsigned char *buf;
u32 buf_len; u32 buf_len;
u32 timeout; u32 transaction_delay;
u32 transaction_timeout;
u8 abort_mask; u8 abort_mask;
const struct sde_hdcp_2x_msg_data *message_data; const struct sde_hdcp_2x_msg_data *message_data;
}; };