On Wednesday 01 August 2018 04:00 PM, Shankar, Uma wrote:
-----Original Message----- From: C, Ramalingam Sent: Saturday, July 14, 2018 8:45 AM To: intel-gfx@lists.freedesktop.org; dri-devel@lists.freedesktop.org; daniel@ffwll.ch; seanpaul@chromium.org; Winkler, Tomas tomas.winkler@intel.com; Usyskin, Alexander alexander.usyskin@intel.com; Shankar, Uma uma.shankar@intel.com Cc: Sharma, Shashank shashank.sharma@intel.com; C, Ramalingam ramalingam.c@intel.com Subject: [PATCH v6 13/35] drm/i915: Implement HDCP2.2 repeater authentication
Implements the HDCP2.2 repeaters authentication steps such as verifying the downstream topology and sending stream management information.
v2: Rebased. v3: No Changes. v4: -EINVAL is returned for topology error and rollover scenario. Endianness conversion func from drm_hdcp.h is used [Uma] v5: Rebased as part of patches reordering. Defined the mei service functions [Daniel] v6: Redefined the mei service functions as per comp redesign.
Signed-off-by: Ramalingam C ramalingam.c@intel.com
drivers/gpu/drm/i915/intel_hdcp.c | 171 ++++++++++++++++++++++++++++++++++++++ include/drm/drm_hdcp.h | 15 ++++ 2 files changed, 186 insertions(+)
diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index ee1e06bac175..a08d80c710d7 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -1144,6 +1144,56 @@ static int hdcp2_prepare_skey(struct intel_connector *connector, return ret; }
+static int +hdcp2_verify_rep_topology_prepare_ack(
struct intel_connector *connector,
struct hdcp2_rep_send_receiverid_list *rep_topology,
struct hdcp2_rep_send_ack *rep_send_ack) {
- struct mei_hdcp_data *data = &connector->hdcp.mei_data;
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct i915_component_master *comp = dev_priv->comp_master;
- int ret;
- if (!comp)
return -EINVAL;
- if (!comp->hdcp_ops || !comp->mei_cldev || data->port ==
INVALID_PORT)
return -EINVAL;
- ret = comp->hdcp_ops->repeater_check_flow_prepare_ack(comp-
mei_cldev,
data,
rep_topology,
rep_send_ack);
Same as mentioned in earlier patch in the series.
comp->hdcp_ops and comp->mei_cldev are initialized at component binding of the mei_hdcp module. So until the component binding happens at mei_hdcp, members of the comp->hdcp_ops wont be utilized.
Otherwise overall the change looks ok to me.
- if (ret < 0)
comp->hdcp_ops->close_hdcp_session(comp->mei_cldev, data);
- return ret;
+}
+static int +hdcp2_verify_mprime(struct intel_connector *connector,
struct hdcp2_rep_stream_ready *stream_ready) {
- struct mei_hdcp_data *data = &connector->hdcp.mei_data;
- struct drm_i915_private *dev_priv = to_i915(connector->base.dev);
- struct i915_component_master *comp = dev_priv->comp_master;
- int ret;
- if (!comp)
return -EINVAL;
- if (!comp->hdcp_ops || !comp->mei_cldev || data->port ==
INVALID_PORT)
return -EINVAL;
- ret = comp->hdcp_ops->verify_mprime(comp->mei_cldev, data,
stream_ready);
- if (ret < 0)
comp->hdcp_ops->close_hdcp_session(comp->mei_cldev, data);
- return ret;
+}
static int hdcp2_authenticate_port(struct intel_connector *connector) { struct mei_hdcp_data *data = &connector->hdcp.mei_data; @@ -1319,6 +1369,121 @@ static int hdcp2_session_key_exchange(struct intel_connector *connector) return 0; }
+static +int hdcp2_propagate_stream_management_info(struct intel_connector +*connector) {
- struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
- union {
struct hdcp2_rep_stream_manage stream_manage;
struct hdcp2_rep_stream_ready stream_ready;
- } msgs;
- const struct intel_hdcp_shim *shim = hdcp->shim;
- int ret;
- /* Prepare RepeaterAuth_Stream_Manage msg */
- msgs.stream_manage.msg_id = HDCP_2_2_REP_STREAM_MANAGE;
- reverse_endianness(msgs.stream_manage.seq_num_m,
HDCP_2_2_SEQ_NUM_LEN,
(u8 *)&hdcp->seq_num_m);
- /* K no of streams is fixed as 1. Stored as big-endian. */
- msgs.stream_manage.k = __swab16(1);
- /* For HDMI this is forced to be 0x0. For DP SST also this is 0x0. */
- msgs.stream_manage.streams[0].stream_id = 0;
- msgs.stream_manage.streams[0].stream_type = hdcp->content_type;
- /* Send it to Repeater */
- ret = shim->write_2_2_msg(intel_dig_port, &msgs.stream_manage,
sizeof(msgs.stream_manage));
- if (ret < 0)
return ret;
- ret = shim->read_2_2_msg(intel_dig_port,
HDCP_2_2_REP_STREAM_READY,
&msgs.stream_ready,
sizeof(msgs.stream_ready));
How the timeout of 100ms is ensured here.
shim->read_2_2_msg() waits for the required timeout for each HDCP2.2 msgs.
--Ram.
- if (ret < 0)
return ret;
- hdcp->mei_data.seq_num_m = hdcp->seq_num_m;
- hdcp->mei_data.streams[0].stream_type = hdcp->content_type;
- ret = hdcp2_verify_mprime(connector, &msgs.stream_ready);
- if (ret < 0)
return ret;
- hdcp->seq_num_m++;
- if (hdcp->seq_num_m > HDCP_2_2_SEQ_NUM_MAX) {
DRM_DEBUG_KMS("seq_num_m roll over.\n");
return -1;
- }
- return 0;
+}
+static +int hdcp2_authenticate_repeater_topology(struct intel_connector +*connector) {
- struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector);
- struct intel_hdcp *hdcp = &connector->hdcp;
- union {
struct hdcp2_rep_send_receiverid_list recvid_list;
struct hdcp2_rep_send_ack rep_ack;
- } msgs;
- const struct intel_hdcp_shim *shim = hdcp->shim;
- uint8_t *rx_info;
- uint32_t seq_num_v;
- int ret;
- ret = shim->read_2_2_msg(intel_dig_port,
HDCP_2_2_REP_SEND_RECVID_LIST,
&msgs.recvid_list, sizeof(msgs.recvid_list));
- if (ret < 0)
return ret;
- rx_info = msgs.recvid_list.rx_info;
- if (HDCP_2_2_MAX_CASCADE_EXCEEDED(rx_info[1]) ||
HDCP_2_2_MAX_DEVS_EXCEEDED(rx_info[1])) {
DRM_DEBUG_KMS("Topology Max Size Exceeded\n");
return -EINVAL;
- }
- /* Converting and Storing the seq_num_v to local variable as DWORD */
- reverse_endianness((u8 *)&seq_num_v, HDCP_2_2_SEQ_NUM_LEN,
msgs.recvid_list.seq_num_v);
- if (seq_num_v < hdcp->seq_num_v) {
/* Roll over of the seq_num_v from repeater. Reauthenticate. */
DRM_DEBUG_KMS("Seq_num_v roll over.\n");
return -EINVAL;
- }
- ret = hdcp2_verify_rep_topology_prepare_ack(connector,
&msgs.recvid_list,
&msgs.rep_ack);
- if (ret < 0)
return ret;
- hdcp->seq_num_v = seq_num_v;
- ret = shim->write_2_2_msg(intel_dig_port, &msgs.rep_ack,
sizeof(msgs.rep_ack));
- if (ret < 0)
return ret;
- return 0;
+}
+static int hdcp2_authenticate_repeater(struct intel_connector +*connector) {
- int ret;
- ret = hdcp2_authenticate_repeater_topology(connector);
- if (ret < 0)
return ret;
- return hdcp2_propagate_stream_management_info(connector);
+}
static int hdcp2_authenticate_sink(struct intel_connector *connector) { struct intel_digital_port *intel_dig_port = conn_to_dig_port(connector); @@ -1360,6 +1525,12 @@ static int hdcp2_authenticate_sink(struct intel_connector *connector) sizeof(stream_type_msg)); if (ret < 0) return ret;
- } else if (hdcp->is_repeater) {
ret = hdcp2_authenticate_repeater(connector);
if (ret < 0) {
DRM_DEBUG_KMS("Repeater Auth Failed. Err: %d\n",
ret);
return ret;
}
}
hdcp->mei_data.streams[0].stream_type = hdcp->content_type; diff --git
a/include/drm/drm_hdcp.h b/include/drm/drm_hdcp.h index 2b4cfb0b7324..c01cdb1d848d 100644 --- a/include/drm/drm_hdcp.h +++ b/include/drm/drm_hdcp.h @@ -252,4 +252,19 @@ struct hdcp2_dp_errata_stream_type { #define HDCP_2_2_HDMI_RXSTATUS_READY(x) ((x) & BIT(2)) #define HDCP_2_2_HDMI_RXSTATUS_REAUTH_REQ(x) ((x) & BIT(3))
+/*
- Library functions for endianness are aligned for 16/32/64 bits.
- But hdcp sequence numbers are 24bits. So for their Byte swapping,
- a conversion function is developed.
- */
+static inline void reverse_endianness(u8 *dest, size_t sz, u8 *src) {
- u32 index;
- if (!sz || sz > sizeof(u32))
return;
- for (index = 0; index < sz; index++)
dest[sz - index - 1] = src[index];
+}
#endif
2.7.4