From: Ramalingam C Date: Sat, 16 Feb 2019 17:37:02 +0000 (+0530) Subject: drm/i915: CP_IRQ handling for DP HDCP2.2 msgs X-Git-Url: http://git.cdn.openwrt.org/?a=commitdiff_plain;h=cf9cb35ff731a784bdbb9ce621faa34346066a39;p=openwrt%2Fstaging%2Fblogic.git drm/i915: CP_IRQ handling for DP HDCP2.2 msgs Implements the Waitqueue is created to wait for CP_IRQ Signaling the CP_IRQ arrival through atomic variable. For applicable DP HDCP2.2 msgs read wait for CP_IRQ. As per HDCP2.2 spec "HDCP Transmitters must process CP_IRQ interrupts when they are received from HDCP Receivers" Without CP_IRQ processing, DP HDCP2.2 H_Prime msg was getting corrupted while reading it based on corresponding status bit. This creates the random failures in reading the DP HDCP2.2 msgs. v2: CP_IRQ arrival is tracked based on the atomic val inc [daniel] Recording the reviewed-by Daniel from IRC. Signed-off-by: Ramalingam C Reviewed-by: Daniel Vetter Signed-off-by: Daniel Vetter Link: https://patchwork.freedesktop.org/patch/msgid/1550338640-17470-16-git-send-email-ramalingam.c@intel.com --- diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c index e9fe25f21200..e1a051c0fbfe 100644 --- a/drivers/gpu/drm/i915/intel_dp.c +++ b/drivers/gpu/drm/i915/intel_dp.c @@ -5623,6 +5623,18 @@ void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder) edp_panel_vdd_off_sync(intel_dp); } +static void intel_dp_hdcp_wait_for_cp_irq(struct intel_hdcp *hdcp, int timeout) +{ + long ret; + +#define C (hdcp->cp_irq_count_cached != atomic_read(&hdcp->cp_irq_count)) + ret = wait_event_interruptible_timeout(hdcp->cp_irq_queue, C, + msecs_to_jiffies(timeout)); + + if (!ret) + DRM_DEBUG_KMS("Timedout at waiting for CP_IRQ\n"); +} + static int intel_dp_hdcp_write_an_aksv(struct intel_digital_port *intel_dig_port, u8 *an) @@ -5967,14 +5979,13 @@ intel_dp_hdcp2_wait_for_msg(struct intel_digital_port *intel_dig_port, mdelay(timeout); ret = 0; } else { - /* TODO: In case if you need to wait on CP_IRQ, do it here */ - ret = __wait_for(ret = - hdcp2_detect_msg_availability(intel_dig_port, - msg_id, - &msg_ready), - !ret && msg_ready, timeout * 1000, - 1000, 5 * 1000); - + /* + * As we want to check the msg availability at timeout, Ignoring + * the timeout at wait for CP_IRQ. + */ + intel_dp_hdcp_wait_for_cp_irq(hdcp, timeout); + ret = hdcp2_detect_msg_availability(intel_dig_port, + msg_id, &msg_ready); if (!msg_ready) ret = -ETIMEDOUT; } @@ -6001,6 +6012,8 @@ static int intel_dp_hdcp2_write_msg(struct intel_digital_port *intel_dig_port, void *buf, size_t size) { + struct intel_dp *dp = &intel_dig_port->dp; + struct intel_hdcp *hdcp = &dp->attached_connector->hdcp; unsigned int offset; u8 *byte = buf; ssize_t ret, bytes_to_write, len; @@ -6016,6 +6029,8 @@ int intel_dp_hdcp2_write_msg(struct intel_digital_port *intel_dig_port, bytes_to_write = size - 1; byte++; + hdcp->cp_irq_count_cached = atomic_read(&hdcp->cp_irq_count); + while (bytes_to_write) { len = bytes_to_write > DP_AUX_MAX_PAYLOAD_BYTES ? DP_AUX_MAX_PAYLOAD_BYTES : bytes_to_write; diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index 60f1a85ec384..c00ef43c6fe6 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -474,6 +474,14 @@ struct intel_hdcp { * over re-Auth has to be triggered. */ u32 seq_num_m; + + /* + * Work queue to signal the CP_IRQ. Used for the waiters to read the + * available information from HDCP DP sink. + */ + wait_queue_head_t cp_irq_queue; + atomic_t cp_irq_count; + int cp_irq_count_cached; }; struct intel_connector { diff --git a/drivers/gpu/drm/i915/intel_hdcp.c b/drivers/gpu/drm/i915/intel_hdcp.c index fe0445c0eaac..6178fe93f398 100644 --- a/drivers/gpu/drm/i915/intel_hdcp.c +++ b/drivers/gpu/drm/i915/intel_hdcp.c @@ -1806,6 +1806,7 @@ int intel_hdcp_init(struct intel_connector *connector, if (is_hdcp2_supported(dev_priv)) intel_hdcp2_init(connector); + init_waitqueue_head(&hdcp->cp_irq_queue); return 0; } @@ -1935,12 +1936,8 @@ void intel_hdcp_handle_cp_irq(struct intel_connector *connector) if (!hdcp->shim) return; - /* - * CP_IRQ could be triggered due to 1. HDCP2.2 auth msgs availability, - * 2. link failure and 3. repeater reauth request. At present we dont - * handle the CP_IRQ for the HDCP2.2 auth msg availability for read. - * To handle other two causes for CP_IRQ we have the work_fn which is - * scheduled here. - */ + atomic_inc(&connector->hdcp.cp_irq_count); + wake_up_all(&connector->hdcp.cp_irq_queue); + schedule_delayed_work(&hdcp->check_work, 0); }