Implements the HDCP2.2 repeaters authentication steps such as verifying the downstream topology and sending stream management information. Signed-off-by: Ramalingam C <ramalingam.c@xxxxxxxxx> --- drivers/gpu/drm/i915/intel_hdcp.c | 133 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index 64276f180e45..0cd637dd3f6b 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -1153,6 +1153,133 @@ static int hdcp2_session_key_exchange(struct intel_hdcp *hdcp) return 0; } +/* + * Lib endianness functions are aligned for 16/32/64 bits. Since here sequence + * num is 24bits developed a small conversion function. + */ +static inline void reverse_endianness(u8 *dest, size_t dst_sz, u8 *src) +{ + u32 index; + + if (dest != NULL && dst_sz != 0) { + for (index = 0; index < dst_sz && index < sizeof(u32); + index++) { + dest[dst_sz - index - 1] = src[index]; + } + } +} + +static int hdcp2_propagate_stream_management_info(struct intel_hdcp *hdcp) +{ + struct intel_digital_port *intel_dig_port = + conn_to_dig_port(hdcp->connector); + union { + struct hdcp2_rep_stream_manage stream_manage; + struct hdcp2_rep_stream_ready stream_ready; + } msgs; + const struct intel_hdcp2_shim *shim = hdcp->hdcp2_shim; + int ret; + + /* Prepare RepeaterAuth_Stream_Manage msg */ + msgs.stream_manage.msg_id = REP_STREAM_MANAGE; + reverse_endianness(msgs.stream_manage.seq_num_m, HDCP_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_msg(intel_dig_port, &msgs.stream_manage, + sizeof(msgs.stream_manage)); + if (ret < 0) + return ret; + + ret = shim->read_msg(intel_dig_port, REP_STREAM_READY, + &msgs.stream_ready, sizeof(msgs.stream_ready)); + if (ret < 0) + return ret; + + hdcp->mei_hdcp_data->seq_num_m = hdcp->seq_num_m; + hdcp->mei_hdcp_data->streams[0].stream_type = hdcp->content_type; + + ret = hdcp2_verify_mprime(hdcp, &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_hdcp *hdcp) +{ + struct intel_digital_port *intel_dig_port = + conn_to_dig_port(hdcp->connector); + union { + struct hdcp2_rep_send_receiverid_list recvid_list; + struct hdcp2_rep_send_ack rep_ack; + } msgs; + const struct intel_hdcp2_shim *shim = hdcp->hdcp2_shim; + union hdcp2_rx_info *rx_info; + uint32_t seq_num_v; + int ret; + + ret = shim->read_msg(intel_dig_port, REP_SEND_RECVID_LIST, + &msgs.recvid_list, sizeof(msgs.recvid_list)); + if (ret < 0) + return ret; + + rx_info = &msgs.recvid_list.rx_info; + + if (rx_info->fields.max_cascade_exceeded || + rx_info->fields.max_devs_exceeded) { + DRM_DEBUG_KMS("Topology Max Size Exceeded\n"); + return -1; + } + + /* Converting and Storing the seq_num_v to local variable as DWORD */ + reverse_endianness((u8 *)&seq_num_v, HDCP_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 -1; + } + + ret = hdcp2_verify_rep_topology_prepare_ack(hdcp, &msgs.recvid_list, + &msgs.rep_ack); + if (ret < 0) + return ret; + + hdcp->seq_num_v = seq_num_v; + ret = shim->write_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_hdcp *hdcp) +{ + int ret; + + ret = hdcp2_authenticate_repeater_topology(hdcp); + if (ret < 0) + return ret; + + return hdcp2_propagate_stream_management_info(hdcp); +} + static int hdcp2_authenticate_sink(struct intel_hdcp *hdcp) { struct intel_digital_port *intel_dig_port = @@ -1194,6 +1321,12 @@ static int hdcp2_authenticate_sink(struct intel_hdcp *hdcp) sizeof(stream_type_msg)); if (ret < 0) return ret; + } else if (hdcp->is_repeater) { + ret = hdcp2_authenticate_repeater(hdcp); + if (ret < 0) { + DRM_DEBUG_KMS("Repeater Auth Failed. Err: %d\n", ret); + return ret; + } } hdcp->mei_hdcp_data->streams[0].stream_type = hdcp->content_type; -- 2.7.4 _______________________________________________ Intel-gfx mailing list Intel-gfx@xxxxxxxxxxxxxxxxxxxxx https://lists.freedesktop.org/mailman/listinfo/intel-gfx