[PATCH v2 04/12] drm/i915: Intercept Aksv writes in the aux hooks
Ramalingam C
ramalingam.c at intel.com
Fri Dec 13 10:52:25 UTC 2019
On 2019-12-12 at 14:02:22 -0500, Sean Paul wrote:
> From: Sean Paul <seanpaul at chromium.org>
>
> Instead of hand rolling the transfer ourselves in the hdcp hook, inspect
> aux messages and add the aksv flag in the aux transfer hook.
>
> IIRC, this was the original implementation and folks wanted this hack to
> be isolated to the hdcp code, which makes sense.
>
> However in testing an LG monitor on my desk, I noticed it was passing
> back a DEFER reply. This wasn't handled in our hand-rolled code and HDCP
> auth was failing as a result. Instead of copy/pasting all of the retry
> logic and delays from drm dp helpers, let's just use the helpers and hide
> the aksv select as best as we can.
>
> Reviewed-by: Ville Syrjälä <ville.syrjala at linux.intel.com>
> Signed-off-by: Sean Paul <seanpaul at chromium.org>
> Link: https://patchwork.freedesktop.org/patch/msgid/20191203173638.94919-3-sean@poorly.run #v1
>
> Changes in v2:
> -Remove 'generate' in intel_dp_aux_generate_xfer_flags, make arg const (Ville)
> -Bundle Aksv if statement together (Ville)
> -Rename 'txbuf' to 'aksv' (Ville)
LGTM
Reviewed-by: Ramalingam C <ramalingam.c at intel.com>
> ---
> drivers/gpu/drm/i915/display/intel_dp.c | 62 ++++++++++++-------------
> 1 file changed, 29 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/gpu/drm/i915/display/intel_dp.c b/drivers/gpu/drm/i915/display/intel_dp.c
> index fe31bbfd6c62..5576193b4fed 100644
> --- a/drivers/gpu/drm/i915/display/intel_dp.c
> +++ b/drivers/gpu/drm/i915/display/intel_dp.c
> @@ -1515,12 +1515,27 @@ intel_dp_aux_header(u8 txbuf[HEADER_SIZE],
> txbuf[3] = msg->size - 1;
> }
>
> +static u32 intel_dp_aux_xfer_flags(const struct drm_dp_aux_msg *msg)
> +{
> + /*
> + * If we're trying to send the HDCP Aksv, we need to set a the Aksv
> + * select bit to inform the hardware to send the Aksv after our header
> + * since we can't access that data from software.
> + */
> + if ((msg->request & ~DP_AUX_I2C_MOT) == DP_AUX_NATIVE_WRITE &&
> + msg->address == DP_AUX_HDCP_AKSV)
> + return DP_AUX_CH_CTL_AUX_AKSV_SELECT;
> +
> + return 0;
> +}
> +
> static ssize_t
> intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
> {
> struct intel_dp *intel_dp = container_of(aux, struct intel_dp, aux);
> u8 txbuf[20], rxbuf[20];
> size_t txsize, rxsize;
> + u32 flags = intel_dp_aux_xfer_flags(msg);
> int ret;
>
> intel_dp_aux_header(txbuf, msg);
> @@ -1541,7 +1556,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
> memcpy(txbuf + HEADER_SIZE, msg->buffer, msg->size);
>
> ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
> - rxbuf, rxsize, 0);
> + rxbuf, rxsize, flags);
> if (ret > 0) {
> msg->reply = rxbuf[0] >> 4;
>
> @@ -1564,7 +1579,7 @@ intel_dp_aux_transfer(struct drm_dp_aux *aux, struct drm_dp_aux_msg *msg)
> return -E2BIG;
>
> ret = intel_dp_aux_xfer(intel_dp, txbuf, txsize,
> - rxbuf, rxsize, 0);
> + rxbuf, rxsize, flags);
> if (ret > 0) {
> msg->reply = rxbuf[0] >> 4;
> /*
> @@ -5904,17 +5919,9 @@ static
> int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
> u8 *an)
> {
> - struct intel_dp *intel_dp = enc_to_intel_dp(&intel_dig_port->base.base);
> - static const struct drm_dp_aux_msg msg = {
> - .request = DP_AUX_NATIVE_WRITE,
> - .address = DP_AUX_HDCP_AKSV,
> - .size = DRM_HDCP_KSV_LEN,
> - };
> - u8 txbuf[HEADER_SIZE + DRM_HDCP_KSV_LEN] = {}, rxbuf[2], reply = 0;
> + u8 aksv[DRM_HDCP_KSV_LEN] = {};
> ssize_t dpcd_ret;
> - int ret;
>
> - /* Output An first, that's easy */
> dpcd_ret = drm_dp_dpcd_write(&intel_dig_port->dp.aux, DP_AUX_HDCP_AN,
> an, DRM_HDCP_AN_LEN);
> if (dpcd_ret != DRM_HDCP_AN_LEN) {
> @@ -5924,29 +5931,18 @@ int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port,
> }
>
> /*
> - * Since Aksv is Oh-So-Secret, we can't access it in software. So in
> - * order to get it on the wire, we need to create the AUX header as if
> - * we were writing the data, and then tickle the hardware to output the
> - * data once the header is sent out.
> + * Since Aksv is Oh-So-Secret, we can't access it in software. So we
> + * send an empty buffer of the correct length through the DP helpers. On
> + * the other side, in the transfer hook, we'll generate a flag based on
> + * the destination address which will tickle the hardware to output the
> + * Aksv on our behalf after the header is sent.
> */
> - intel_dp_aux_header(txbuf, &msg);
> -
> - ret = intel_dp_aux_xfer(intel_dp, txbuf, HEADER_SIZE + msg.size,
> - rxbuf, sizeof(rxbuf),
> - DP_AUX_CH_CTL_AUX_AKSV_SELECT);
> - if (ret < 0) {
> - DRM_DEBUG_KMS("Write Aksv over DP/AUX failed (%d)\n", ret);
> - return ret;
> - } else if (ret == 0) {
> - DRM_DEBUG_KMS("Aksv write over DP/AUX was empty\n");
> - return -EIO;
> - }
> -
> - reply = (rxbuf[0] >> 4) & DP_AUX_NATIVE_REPLY_MASK;
> - if (reply != DP_AUX_NATIVE_REPLY_ACK) {
> - DRM_DEBUG_KMS("Aksv write: no DP_AUX_NATIVE_REPLY_ACK %x\n",
> - reply);
> - return -EIO;
> + dpcd_ret = drm_dp_dpcd_write(&intel_dig_port->dp.aux, DP_AUX_HDCP_AKSV,
> + aksv, DRM_HDCP_KSV_LEN);
> + if (dpcd_ret != DRM_HDCP_KSV_LEN) {
> + DRM_DEBUG_KMS("Failed to write Aksv over DP/AUX (%zd)\n",
> + dpcd_ret);
> + return dpcd_ret >= 0 ? -EIO : dpcd_ret;
> }
> return 0;
> }
> --
> Sean Paul, Software Engineer, Google / Chromium OS
>
More information about the dri-devel
mailing list