[Intel-gfx] [PATCH v7 15/17] drm/mst: Add support for QUERY_STREAM_ENCRYPTION_STATUS MST sideband message
Anshuman Gupta
anshuman.gupta at intel.com
Thu Jul 2 14:37:36 UTC 2020
On 2020-06-30 at 12:48:34 -0400, Sean Paul wrote:
> On Tue, Jun 30, 2020 at 10:21 AM Anshuman Gupta
> <anshuman.gupta at intel.com> wrote:
> >
> > On 2020-06-23 at 21:29:05 +0530, Sean Paul wrote:
> > Hi Sean,
> > I am new to DP MST stuff, I am looking to DP MST spec DP v1.2a.
> > I have looked the entire series, i will take up this opportunity to review
> > the series from HDCP over DP MST POV.
> > I think theoretically this series should work or Gen12 as well, as DP MST streams
> > are getting encrypted by QUERY_STREAM_ENCRYPTION_STATUS reply tranaction msg
> > (generating Stream State Signature L’).
> > I will test this on Gen12 H/W with DP MST support and will provide my inputs.
> >
> > Meanwhile while going through DP MST v1.2a specs(Page 262) came to know about
> > a DP irq vector LINK_SERVICE_IRQ_VECTOR_ESI0 (02005h),
> > Bit 2 : STREAM_STATUS_CHANGED.
> > When this bit set to ‘1’ indicates the source must re-check the Stream Status
> > with the QUERY_STREAM_ENCRYPTION_STATUS message.
> > Currently i feel this irq support is missing, do we require to support
> > above IRQ vector for DP MST stream encryption.
> >
>
> Hi Anshuman,
> Thank you for your comments.
>
> QUERY_STREAM_ENCRYPTION_STATUS is not necessary for HDCP 1.x, I added
> this as a safety check to ensure that the streams were being
> encrypted. As such, the existing integrity checks in place for DP are
> sufficient to satisfy spec. When HDCP 2.2 support is added for MST,
> handling QSES will need to be addressed to meet spec. Note also that
> we're not validating the QSES signature for the same reason.
Thanks sean for the explanation,
overall patch looks good to me but i have couple of doubt see below.
>
> Sean
>
>
> > Thanks,
> > Anshuman Gupta.
> >
> > > From: Sean Paul <seanpaul at chromium.org>
> > >
> > > Used to query whether an MST stream is encrypted or not.
> > >
> > > Signed-off-by: Sean Paul <seanpaul at chromium.org>
> > >
> > > Link: https://patchwork.freedesktop.org/patch/msgid/20200218220242.107265-14-sean@poorly.run #v4
> > > Link: https://patchwork.freedesktop.org/patch/msgid/20200305201236.152307-15-sean@poorly.run #v5
> > > Link: https://patchwork.freedesktop.org/patch/msgid/20200429195502.39919-15-sean@poorly.run #v6
> > >
> > > Changes in v4:
> > > -Added to the set
> > > Changes in v5:
> > > -None
> > > Changes in v6:
> > > -Use FIELD_PREP to generate request buffer bitfields (Lyude)
> > > -Add mst selftest and dump/decode_sideband_req for QSES (Lyude)
> > > Changes in v7:
> > > -None
> > > ---
> > > drivers/gpu/drm/drm_dp_mst_topology.c | 142 ++++++++++++++++++
> > > .../drm/selftests/test-drm_dp_mst_helper.c | 17 +++
> > > include/drm/drm_dp_helper.h | 3 +
> > > include/drm/drm_dp_mst_helper.h | 44 ++++++
> > > 4 files changed, 206 insertions(+)
> > >
> > > diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
> > > index b2f5a84b4cfb..fc68478eaeb4 100644
> > > --- a/drivers/gpu/drm/drm_dp_mst_topology.c
> > > +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
> > > @@ -20,11 +20,13 @@
> > > * OF THIS SOFTWARE.
> > > */
> > >
> > > +#include <linux/bitfield.h>
> > > #include <linux/delay.h>
> > > #include <linux/errno.h>
> > > #include <linux/i2c.h>
> > > #include <linux/init.h>
> > > #include <linux/kernel.h>
> > > +#include <linux/random.h>
> > > #include <linux/sched.h>
> > > #include <linux/seq_file.h>
> > > #include <linux/iopoll.h>
> > > @@ -419,6 +421,22 @@ drm_dp_encode_sideband_req(const struct drm_dp_sideband_msg_req_body *req,
> > > memcpy(&buf[idx], req->u.i2c_write.bytes, req->u.i2c_write.num_bytes);
> > > idx += req->u.i2c_write.num_bytes;
> > > break;
> > > + case DP_QUERY_STREAM_ENC_STATUS: {
> > > + const struct drm_dp_query_stream_enc_status *msg;
> > > +
> > > + msg = &req->u.enc_status;
> > > + buf[idx] = msg->stream_id;
> > > + idx++;
> > > + memcpy(&buf[idx], msg->client_id, sizeof(msg->client_id));
> > > + idx += sizeof(msg->client_id);
> > > + buf[idx] = 0;
> > > + buf[idx] |= FIELD_PREP(GENMASK(1, 0), msg->stream_event);
> > > + buf[idx] |= msg->valid_stream_event ? BIT(2) : 0;
> > > + buf[idx] |= FIELD_PREP(GENMASK(4, 3), msg->stream_behavior);
> > > + buf[idx] |= msg->valid_stream_behavior ? BIT(5) : 0;
> > > + idx++;
> > > + }
> > > + break;
> > > }
> > > raw->cur_len = idx;
> > > }
> > > @@ -547,6 +565,20 @@ drm_dp_decode_sideband_req(const struct drm_dp_sideband_msg_tx *raw,
> > > return -ENOMEM;
> > > }
> > > break;
> > > + case DP_QUERY_STREAM_ENC_STATUS:
> > > + req->u.enc_status.stream_id = buf[idx++];
> > > + for (i = 0; i < sizeof(req->u.enc_status.client_id); i++)
> > > + req->u.enc_status.client_id[i] = buf[idx++];
> > > +
> > > + req->u.enc_status.stream_event = FIELD_GET(GENMASK(1, 0),
> > > + buf[idx]);
> > > + req->u.enc_status.valid_stream_event = FIELD_GET(BIT(2),
> > > + buf[idx]);
> > > + req->u.enc_status.stream_behavior = FIELD_GET(GENMASK(4, 3),
> > > + buf[idx]);
> > > + req->u.enc_status.valid_stream_behavior = FIELD_GET(BIT(5),
> > > + buf[idx]);
> > > + break;
> > > }
> > >
> > > return 0;
> > > @@ -625,6 +657,16 @@ drm_dp_dump_sideband_msg_req_body(const struct drm_dp_sideband_msg_req_body *req
> > > req->u.i2c_write.num_bytes, req->u.i2c_write.num_bytes,
> > > req->u.i2c_write.bytes);
> > > break;
> > > + case DP_QUERY_STREAM_ENC_STATUS:
> > > + P("stream_id=%u client_id=%*ph stream_event=%x "
> > > + "valid_event=%d stream_behavior=%x valid_behavior=%d",
> > > + req->u.enc_status.stream_id,
> > > + (int)ARRAY_SIZE(req->u.enc_status.client_id),
> > > + req->u.enc_status.client_id, req->u.enc_status.stream_event,
> > > + req->u.enc_status.valid_stream_event,
> > > + req->u.enc_status.stream_behavior,
> > > + req->u.enc_status.valid_stream_behavior);
> > > + break;
> > > default:
> > > P("???\n");
> > > break;
> > > @@ -925,6 +967,34 @@ static bool drm_dp_sideband_parse_power_updown_phy_ack(struct drm_dp_sideband_ms
> > > return true;
> > > }
> > >
> > > +static bool
> > > +drm_dp_sideband_parse_query_stream_enc_status(
> > > + struct drm_dp_sideband_msg_rx *raw,
> > > + struct drm_dp_sideband_msg_reply_body *repmsg)
> > > +{
> > > + struct drm_dp_query_stream_enc_status_ack_reply *reply;
> > > +
> > > + reply = &repmsg->u.enc_status;
> > > +
> > > + reply->stream_id = raw->msg[3];
It seems msg[0] is not part of reply data,
could you help me with pointers, where msg is formatted.
> > > +
> > > + reply->reply_signed = raw->msg[2] & BIT(0);
> > > +
> > > + reply->hdcp_1x_device_present = raw->msg[2] & BIT(3);
> > > + reply->hdcp_2x_device_present = raw->msg[2] & BIT(4);
> > > +
> > > + reply->query_capable_device_present = raw->msg[2] & BIT(5);
> > > + reply->legacy_device_present = raw->msg[2] & BIT(6);
> > > + reply->unauthorizable_device_present = raw->msg[2] & BIT(7);
> > > +
> > > + reply->auth_completed = !!(raw->msg[1] & BIT(3));
> > > + reply->encryption_enabled = !!(raw->msg[1] & BIT(4));
> > > + reply->repeater_present = !!(raw->msg[1] & BIT(5));
> > > + reply->state = (raw->msg[1] & GENMASK(7, 6)) >> 6;
> > > +
> > > + return true;
> > > +}
> > > +
> > > static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw,
> > > struct drm_dp_sideband_msg_reply_body *msg)
> > > {
> > > @@ -959,6 +1029,8 @@ static bool drm_dp_sideband_parse_reply(struct drm_dp_sideband_msg_rx *raw,
> > > return drm_dp_sideband_parse_power_updown_phy_ack(raw, msg);
> > > case DP_CLEAR_PAYLOAD_ID_TABLE:
> > > return true; /* since there's nothing to parse */
> > > + case DP_QUERY_STREAM_ENC_STATUS:
> > > + return drm_dp_sideband_parse_query_stream_enc_status(raw, msg);
> > > default:
> > > DRM_ERROR("Got unknown reply 0x%02x (%s)\n", msg->req_type,
> > > drm_dp_mst_req_type_str(msg->req_type));
> > > @@ -1109,6 +1181,25 @@ static void build_power_updown_phy(struct drm_dp_sideband_msg_tx *msg,
> > > msg->path_msg = true;
> > > }
> > >
> > > +static int
> > > +build_query_stream_enc_status(struct drm_dp_sideband_msg_tx *msg, u8 stream_id,
> > > + u8 *q_id)
> > > +{
> > > + struct drm_dp_sideband_msg_req_body req;
> > > +
> > > + req.req_type = DP_QUERY_STREAM_ENC_STATUS;
> > > + req.u.enc_status.stream_id = stream_id;
> > > + memcpy(req.u.enc_status.client_id, q_id,
> > > + sizeof(req.u.enc_status.client_id));
> > > + req.u.enc_status.stream_event = 0;
> > > + req.u.enc_status.valid_stream_event = false;
> > > + req.u.enc_status.stream_behavior = 0;
> > > + req.u.enc_status.valid_stream_behavior = false;
> > > +
> > > + drm_dp_encode_sideband_req(&req, msg);
> > > + return 0;
> > > +}
> > > +
> > > static int drm_dp_mst_assign_payload_id(struct drm_dp_mst_topology_mgr *mgr,
> > > struct drm_dp_vcpi *vcpi)
> > > {
> > > @@ -3137,6 +3228,57 @@ int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr,
> > > }
> > > EXPORT_SYMBOL(drm_dp_send_power_updown_phy);
> > >
> > > +int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr,
> > > + struct drm_dp_mst_port *port,
> > > + struct drm_dp_query_stream_enc_status_ack_reply *status)
> > > +{
> > > + struct drm_dp_sideband_msg_tx *txmsg;
> > > + u8 nonce[7];
> > > + int len, ret;
> > > +
> > > + txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
> > > + if (!txmsg)
> > > + return -ENOMEM;
> > > +
> > > + port = drm_dp_mst_topology_get_port_validated(mgr, port);
> > > + if (!port) {
> > > + ret = -EINVAL;
> > > + goto out_get_port;
> > > + }
> > > +
> > > + get_random_bytes(nonce, sizeof(nonce));
> > > +
> > > + /*
> > > + * "Source device targets the QUERY_STREAM_ENCRYPTION_STATUS message
> > > + * transaction at the MST Branch device directly connected to the
> > > + * Source"
> > > + */
> > > + txmsg->dst = mgr->mst_primary;
> > > +
> > > + len = build_query_stream_enc_status(txmsg, port->vcpi.vcpi, nonce);
> > > +
> > > + drm_dp_queue_down_tx(mgr, txmsg);
> > > +
> > > + ret = drm_dp_mst_wait_tx_reply(mgr->mst_primary, txmsg);
> > > + if (ret < 0) {
> > > + goto out;
> > > + } else if (txmsg->reply.reply_type == DP_SIDEBAND_REPLY_NAK) {
> > > + DRM_DEBUG_KMS("query encryption status nak received\n");
> > > + ret = -ENXIO;
> > > + goto out;
> > > + }
> > > +
> > > + ret = 0;
> > > + memcpy(status, &txmsg->reply.u.enc_status, sizeof(*status));
> > > +
> > > +out:
> > > + drm_dp_mst_topology_put_port(port);
> > > +out_get_port:
> > > + kfree(txmsg);
> > > + return ret;
> > > +}
> > > +EXPORT_SYMBOL(drm_dp_send_query_stream_enc_status);
> > > +
> > > static int drm_dp_create_payload_step1(struct drm_dp_mst_topology_mgr *mgr,
> > > int id,
> > > struct drm_dp_payload *payload)
> > > diff --git a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
> > > index bd990d178765..1d696ec001cf 100644
> > > --- a/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
> > > +++ b/drivers/gpu/drm/selftests/test-drm_dp_mst_helper.c
> > > @@ -5,6 +5,8 @@
> > >
> > > #define PREFIX_STR "[drm_dp_mst_helper]"
> > >
> > > +#include <linux/random.h>
> > > +
> > > #include <drm/drm_dp_mst_helper.h>
> > > #include <drm/drm_print.h>
> > >
> > > @@ -237,6 +239,21 @@ int igt_dp_mst_sideband_msg_req_decode(void *unused)
> > > in.u.i2c_write.bytes = data;
> > > DO_TEST();
> > >
> > > + in.req_type = DP_QUERY_STREAM_ENC_STATUS;
> > > + in.u.enc_status.stream_id = 1;
> > > + DO_TEST();
> > > + get_random_bytes(in.u.enc_status.client_id,
> > > + sizeof(in.u.enc_status.client_id));
> > > + DO_TEST();
> > > + in.u.enc_status.stream_event = 3;
> > > + DO_TEST();
> > > + in.u.enc_status.valid_stream_event = 0;
> > > + DO_TEST();
> > > + in.u.enc_status.stream_behavior = 3;
> > > + DO_TEST();
> > > + in.u.enc_status.valid_stream_behavior = 1;
> > > + DO_TEST();
> > > +
> > > #undef DO_TEST
> > > return 0;
> > > }
> > > diff --git a/include/drm/drm_dp_helper.h b/include/drm/drm_dp_helper.h
> > > index e47dc22ebf50..e2d2df5e869e 100644
> > > --- a/include/drm/drm_dp_helper.h
> > > +++ b/include/drm/drm_dp_helper.h
> > > @@ -1108,6 +1108,9 @@
> > > #define DP_POWER_DOWN_PHY 0x25
> > > #define DP_SINK_EVENT_NOTIFY 0x30
> > > #define DP_QUERY_STREAM_ENC_STATUS 0x38
> > > +#define DP_QUERY_STREAM_ENC_STATUS_STATE_NO_EXIST 0
> > > +#define DP_QUERY_STREAM_ENC_STATUS_STATE_INACTIVE 1
> > > +#define DP_QUERY_STREAM_ENC_STATUS_STATE_ACTIVE 2
> > >
> > > /* DP 1.2 MST sideband reply types */
> > > #define DP_SIDEBAND_REPLY_ACK 0x00
> > > diff --git a/include/drm/drm_dp_mst_helper.h b/include/drm/drm_dp_mst_helper.h
> > > index 8b9eb4db3381..371eef8798ad 100644
> > > --- a/include/drm/drm_dp_mst_helper.h
> > > +++ b/include/drm/drm_dp_mst_helper.h
> > > @@ -313,6 +313,34 @@ struct drm_dp_remote_i2c_write_ack_reply {
> > > u8 port_number;
> > > };
> > >
> > > +struct drm_dp_query_stream_enc_status_ack_reply {
> > > + /* Bit[23:16]- Stream Id */
> > > + u8 stream_id;
> > > +
> > > + /* Bit[15]- Signed */
> > > + bool reply_signed;
> > > +
> > > + /* Bit[10:8]- Stream Output Sink Type */
> > > + bool unauthorizable_device_present;
> > > + bool legacy_device_present;
> > > + bool query_capable_device_present;
> > > +
> > > + /* Bit[12:11]- Stream Output CP Type */
> > > + bool hdcp_1x_device_present;
> > > + bool hdcp_2x_device_present;
> > > +
> > > + /* Bit[4]- Stream Authentication */
> > > + bool auth_completed;
> > > +
> > > + /* Bit[3]- Stream Encryption */
> > > + bool encryption_enabled;
> > > +
> > > + /* Bit[2]- Stream Repeater Function Present */
> > > + bool repeater_present;
> > > +
> > > + /* Bit[1:0]- Stream State */
> > > + u8 state;
reply msg also has 20 byte of signature L' (HDCP 1.4),
AFAIU it has lefted out for HDCP 2.2 implementation, which is of 32 bytes for HDCP 2.2.
Please correct me if i am wrong here.
Thanks,
Anshuman Gupta.
> > > +};
> > >
> > > #define DRM_DP_MAX_SDP_STREAMS 16
> > > struct drm_dp_allocate_payload {
> > > @@ -374,6 +402,15 @@ struct drm_dp_remote_i2c_write {
> > > u8 *bytes;
> > > };
> > >
> > > +struct drm_dp_query_stream_enc_status {
> > > + u8 stream_id;
> > > + u8 client_id[7]; /* 56-bit nonce */
> > > + u8 stream_event;
> > > + bool valid_stream_event;
> > > + u8 stream_behavior;
> > > + u8 valid_stream_behavior;
> > > +};
> > > +
> > > /* this covers ENUM_RESOURCES, POWER_DOWN_PHY, POWER_UP_PHY */
> > > struct drm_dp_port_number_req {
> > > u8 port_number;
> > > @@ -422,6 +459,8 @@ struct drm_dp_sideband_msg_req_body {
> > >
> > > struct drm_dp_remote_i2c_read i2c_read;
> > > struct drm_dp_remote_i2c_write i2c_write;
> > > +
> > > + struct drm_dp_query_stream_enc_status enc_status;
> > > } u;
> > > };
> > >
> > > @@ -444,6 +483,8 @@ struct drm_dp_sideband_msg_reply_body {
> > > struct drm_dp_remote_i2c_read_ack_reply remote_i2c_read_ack;
> > > struct drm_dp_remote_i2c_read_nak_reply remote_i2c_read_nack;
> > > struct drm_dp_remote_i2c_write_ack_reply remote_i2c_write_ack;
> > > +
> > > + struct drm_dp_query_stream_enc_status_ack_reply enc_status;
> > > } u;
> > > };
> > >
> > > @@ -808,6 +849,9 @@ drm_dp_atomic_release_vcpi_slots(struct drm_atomic_state *state,
> > > struct drm_dp_mst_port *port);
> > > int drm_dp_send_power_updown_phy(struct drm_dp_mst_topology_mgr *mgr,
> > > struct drm_dp_mst_port *port, bool power_up);
> > > +int drm_dp_send_query_stream_enc_status(struct drm_dp_mst_topology_mgr *mgr,
> > > + struct drm_dp_mst_port *port,
> > > + struct drm_dp_query_stream_enc_status_ack_reply *status);
> > > int __must_check drm_dp_mst_atomic_check(struct drm_atomic_state *state);
> > >
> > > void drm_dp_mst_get_port_malloc(struct drm_dp_mst_port *port);
> > > --
> > > Sean Paul, Software Engineer, Google / Chromium OS
> > >
> > > _______________________________________________
> > > Intel-gfx mailing list
> > > Intel-gfx at lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
More information about the dri-devel
mailing list