All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook
@ 2018-01-17 19:21 Ville Syrjala
  2018-01-17 19:21 ` [PATCH v2 2/5] drm/i915: Reinitialize sink scrambling/TMDS clock ratio on HPD Ville Syrjala
                   ` (6 more replies)
  0 siblings, 7 replies; 23+ messages in thread
From: Ville Syrjala @ 2018-01-17 19:21 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Allow encoders to customize their hotplug processing by moving the
intel_hpd_irq_event() code into an encoder hotplug vfunc. Currently
only SDVO needs this to re-enable hotplug signalling in the SDVO
chip. We'll use this same hook for DP/HDMI link management later.

Reviewed-by: Jani Nikula <jani.nikula@intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_crt.c     |  4 +++-
 drivers/gpu/drm/i915/intel_ddi.c     |  1 +
 drivers/gpu/drm/i915/intel_dp.c      |  1 +
 drivers/gpu/drm/i915/intel_drv.h     |  6 ++++--
 drivers/gpu/drm/i915/intel_hdmi.c    |  1 +
 drivers/gpu/drm/i915/intel_hotplug.c | 24 ++++++++++++------------
 drivers/gpu/drm/i915/intel_sdvo.c    | 12 ++++++++++--
 7 files changed, 32 insertions(+), 17 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_crt.c b/drivers/gpu/drm/i915/intel_crt.c
index 9f31aea51dff..9bc47cff5409 100644
--- a/drivers/gpu/drm/i915/intel_crt.c
+++ b/drivers/gpu/drm/i915/intel_crt.c
@@ -966,8 +966,10 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
 	crt->base.power_domain = POWER_DOMAIN_PORT_CRT;
 
 	if (I915_HAS_HOTPLUG(dev_priv) &&
-	    !dmi_check_system(intel_spurious_crt_detect))
+	    !dmi_check_system(intel_spurious_crt_detect)) {
 		crt->base.hpd_pin = HPD_CRT;
+		crt->base.hotplug = intel_encoder_hotplug;
+	}
 
 	if (HAS_DDI(dev_priv)) {
 		crt->base.port = PORT_E;
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 6260a882fbe4..1aeae3e97013 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -2866,6 +2866,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
 	drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
 			 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
 
+	intel_encoder->hotplug = intel_encoder_hotplug;
 	intel_encoder->compute_output_type = intel_ddi_compute_output_type;
 	intel_encoder->compute_config = intel_ddi_compute_config;
 	intel_encoder->enable = intel_enable_ddi;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 68229f53d5b8..6bbf14410c2a 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -6400,6 +6400,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
 			     "DP %c", port_name(port)))
 		goto err_encoder_init;
 
+	intel_encoder->hotplug = intel_encoder_hotplug;
 	intel_encoder->compute_config = intel_dp_compute_config;
 	intel_encoder->get_hw_state = intel_dp_get_hw_state;
 	intel_encoder->get_config = intel_dp_get_config;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5c8e260ca2bc..5ea1dc3f63bf 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -214,7 +214,8 @@ struct intel_encoder {
 	enum intel_output_type type;
 	enum port port;
 	unsigned int cloneable;
-	void (*hot_plug)(struct intel_encoder *);
+	bool (*hotplug)(struct intel_encoder *encoder,
+			struct intel_connector *connector);
 	enum intel_output_type (*compute_output_type)(struct intel_encoder *,
 						      struct intel_crtc_state *,
 						      struct drm_connector_state *);
@@ -1690,7 +1691,8 @@ int intel_dsi_dcs_init_backlight_funcs(struct intel_connector *intel_connector);
 void intel_dvo_init(struct drm_i915_private *dev_priv);
 /* intel_hotplug.c */
 void intel_hpd_poll_init(struct drm_i915_private *dev_priv);
-
+bool intel_encoder_hotplug(struct intel_encoder *encoder,
+			   struct intel_connector *connector);
 
 /* legacy fbdev emulation in intel_fbdev.c */
 #ifdef CONFIG_DRM_FBDEV_EMULATION
diff --git a/drivers/gpu/drm/i915/intel_hdmi.c b/drivers/gpu/drm/i915/intel_hdmi.c
index 691f15b59124..4a93cfd7a28e 100644
--- a/drivers/gpu/drm/i915/intel_hdmi.c
+++ b/drivers/gpu/drm/i915/intel_hdmi.c
@@ -2348,6 +2348,7 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv,
 			 &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
 			 "HDMI %c", port_name(port));
 
+	intel_encoder->hotplug = intel_encoder_hotplug;
 	intel_encoder->compute_config = intel_hdmi_compute_config;
 	if (HAS_PCH_SPLIT(dev_priv)) {
 		intel_encoder->disable = pch_disable_hdmi;
diff --git a/drivers/gpu/drm/i915/intel_hotplug.c b/drivers/gpu/drm/i915/intel_hotplug.c
index 875d5d218d5c..0191c7831a06 100644
--- a/drivers/gpu/drm/i915/intel_hotplug.c
+++ b/drivers/gpu/drm/i915/intel_hotplug.c
@@ -263,24 +263,25 @@ static void intel_hpd_irq_storm_reenable_work(struct work_struct *work)
 	intel_runtime_pm_put(dev_priv);
 }
 
-static bool intel_hpd_irq_event(struct drm_device *dev,
-				struct drm_connector *connector)
+bool intel_encoder_hotplug(struct intel_encoder *encoder,
+			   struct intel_connector *connector)
 {
+	struct drm_device *dev = connector->base.dev;
 	enum drm_connector_status old_status;
 
 	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
-	old_status = connector->status;
+	old_status = connector->base.status;
 
-	connector->status = drm_helper_probe_detect(connector, NULL, false);
+	connector->base.status = drm_helper_probe_detect(&connector->base, NULL, false);
 
-	if (old_status == connector->status)
+	if (old_status == connector->base.status)
 		return false;
 
 	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
-		      connector->base.id,
-		      connector->name,
+		      connector->base.base.id,
+		      connector->base.name,
 		      drm_get_connector_status_name(old_status),
-		      drm_get_connector_status_name(connector->status));
+		      drm_get_connector_status_name(connector->base.status));
 
 	return true;
 }
@@ -370,10 +371,9 @@ static void i915_hotplug_work_func(struct work_struct *work)
 		if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
 			DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug event.\n",
 				      connector->name, intel_encoder->hpd_pin);
-			if (intel_encoder->hot_plug)
-				intel_encoder->hot_plug(intel_encoder);
-			if (intel_hpd_irq_event(dev, connector))
-				changed = true;
+
+			changed |= intel_encoder->hotplug(intel_encoder,
+							  intel_connector);
 		}
 	}
 	drm_connector_list_iter_end(&conn_iter);
diff --git a/drivers/gpu/drm/i915/intel_sdvo.c b/drivers/gpu/drm/i915/intel_sdvo.c
index 2b8764897d68..5b1ad42ec446 100644
--- a/drivers/gpu/drm/i915/intel_sdvo.c
+++ b/drivers/gpu/drm/i915/intel_sdvo.c
@@ -1692,7 +1692,15 @@ static void intel_sdvo_enable_hotplug(struct intel_encoder *encoder)
 	struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
 
 	intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG,
-			&intel_sdvo->hotplug_active, 2);
+			     &intel_sdvo->hotplug_active, 2);
+}
+
+static bool intel_sdvo_hotplug(struct intel_encoder *encoder,
+			       struct intel_connector *connector)
+{
+	intel_sdvo_enable_hotplug(encoder);
+
+	return intel_encoder_hotplug(encoder, connector);
 }
 
 static bool
@@ -2496,7 +2504,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int device)
 		/* Some SDVO devices have one-shot hotplug interrupts.
 		 * Ensure that they get re-enabled when an interrupt happens.
 		 */
-		intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
+		intel_encoder->hotplug = intel_sdvo_hotplug;
 		intel_sdvo_enable_hotplug(intel_encoder);
 	} else {
 		intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT | DRM_CONNECTOR_POLL_DISCONNECT;
-- 
2.13.6

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 2/5] drm/i915: Reinitialize sink scrambling/TMDS clock ratio on HPD
  2018-01-17 19:21 [PATCH 1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Ville Syrjala
@ 2018-01-17 19:21 ` Ville Syrjala
  2018-01-30 22:45   ` Lyude Paul
  2018-01-17 19:21 ` [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook Ville Syrjala
                   ` (5 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: Ville Syrjala @ 2018-01-17 19:21 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

The LG 4k TV I have doesn't deassert HPD when I turn the TV off, but
when I turn it back on it will pulse the HPD line. By that time it has
forgotten everything we told it about scrambling and the clock ratio.
Hence if we want to get a picture out if it again we have to tell it
whether we're currently sending scrambled data or not. Implement
that via the encoder->hotplug() hook.

v2: Force a full modeset to not follow the HDMI 2.0 spec more
    closely (Shashank)

Cc: Shashank Sharma <shashank.sharma@intel.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c | 146 ++++++++++++++++++++++++++++++++++++++-
 1 file changed, 145 insertions(+), 1 deletion(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 1aeae3e97013..25793bdc692f 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -25,6 +25,7 @@
  *
  */
 
+#include <drm/drm_scdc_helper.h>
 #include "i915_drv.h"
 #include "intel_drv.h"
 
@@ -2756,6 +2757,146 @@ intel_ddi_init_dp_connector(struct intel_digital_port *intel_dig_port)
 	return connector;
 }
 
+static int modeset_pipe(struct drm_crtc *crtc,
+			struct drm_modeset_acquire_ctx *ctx)
+{
+	struct drm_atomic_state *state;
+	struct drm_crtc_state *crtc_state;
+	int ret;
+
+	state = drm_atomic_state_alloc(crtc->dev);
+	if (!state)
+		return -ENOMEM;
+
+	state->acquire_ctx = ctx;
+
+	crtc_state = drm_atomic_get_crtc_state(state, crtc);
+	if (IS_ERR(crtc_state)) {
+		ret = PTR_ERR(crtc_state);
+		goto out;
+	}
+
+	crtc_state->mode_changed = true;
+
+	ret = drm_atomic_add_affected_connectors(state, crtc);
+	if (ret)
+		goto out;
+
+	ret = drm_atomic_add_affected_planes(state, crtc);
+	if (ret)
+		goto out;
+
+	ret = drm_atomic_commit(state);
+	if (ret)
+		goto out;
+
+	return 0;
+
+ out:
+	drm_atomic_state_put(state);
+
+	return ret;
+}
+
+static int intel_hdmi_reset_link(struct intel_encoder *encoder,
+				 struct drm_modeset_acquire_ctx *ctx)
+{
+	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
+	struct intel_hdmi *hdmi = enc_to_intel_hdmi(&encoder->base);
+	struct intel_connector *connector = hdmi->attached_connector;
+	struct i2c_adapter *adapter =
+		intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
+	struct drm_connector_state *conn_state;
+	struct intel_crtc_state *crtc_state;
+	struct intel_crtc *crtc;
+	u8 config;
+	int ret;
+
+	if (!connector || connector->base.status != connector_status_connected)
+		return 0;
+
+	ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, ctx);
+	if (ret)
+		return ret;
+
+	conn_state = connector->base.state;
+
+	crtc = to_intel_crtc(conn_state->crtc);
+	if (!crtc)
+		return 0;
+
+	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
+	if (ret)
+		return ret;
+
+	crtc_state = to_intel_crtc_state(crtc->base.state);
+
+	WARN_ON(!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI));
+
+	if (!crtc_state->base.active)
+		return 0;
+
+	if (!crtc_state->hdmi_high_tmds_clock_ratio &&
+	    !crtc_state->hdmi_scrambling)
+		return 0;
+
+	if (conn_state->commit &&
+	    !try_wait_for_completion(&conn_state->commit->hw_done))
+		return 0;
+
+	ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
+	if (ret < 0) {
+		DRM_ERROR("Failed to read TMDS config: %d\n", ret);
+		return 0;
+	}
+
+	if (!!(config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40) ==
+	    crtc_state->hdmi_high_tmds_clock_ratio &&
+	    !!(config & SCDC_SCRAMBLING_ENABLE) ==
+	    crtc_state->hdmi_scrambling)
+		return 0;
+
+	/*
+	 * HDMI 2.0 says that one should not send scrambled data
+	 * prior to configuring the sink scrambling, and that
+	 * TMDS clock/data transmission should be suspended when
+	 * changing the TMDS clock rate in the sink. So let's
+	 * just do a full modeset here, even though some sinks
+	 * would be perfectly happy if were to just reconfigure
+	 * the SCDC settings on the fly.
+	 */
+	return modeset_pipe(&crtc->base, ctx);
+}
+
+static bool intel_ddi_hotplug(struct intel_encoder *encoder,
+			      struct intel_connector *connector)
+{
+	struct drm_modeset_acquire_ctx ctx;
+	bool changed;
+	int ret;
+
+	changed = intel_encoder_hotplug(encoder, connector);
+
+	drm_modeset_acquire_init(&ctx, 0);
+
+	for (;;) {
+		ret = intel_hdmi_reset_link(encoder, &ctx);
+
+		if (ret == -EDEADLK) {
+			drm_modeset_backoff(&ctx);
+			continue;
+		}
+
+		break;
+	}
+
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+	WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
+
+	return changed;
+}
+
 static struct intel_connector *
 intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
 {
@@ -2866,7 +3007,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
 	drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
 			 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
 
-	intel_encoder->hotplug = intel_encoder_hotplug;
+	if (init_hdmi)
+		intel_encoder->hotplug = intel_ddi_hotplug;
+	else
+		intel_encoder->hotplug = intel_encoder_hotplug;
 	intel_encoder->compute_output_type = intel_ddi_compute_output_type;
 	intel_encoder->compute_config = intel_ddi_compute_config;
 	intel_encoder->enable = intel_enable_ddi;
-- 
2.13.6

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
  2018-01-17 19:21 [PATCH 1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Ville Syrjala
  2018-01-17 19:21 ` [PATCH v2 2/5] drm/i915: Reinitialize sink scrambling/TMDS clock ratio on HPD Ville Syrjala
@ 2018-01-17 19:21 ` Ville Syrjala
  2018-01-30 23:16   ` Lyude Paul
  2018-01-17 19:21 ` [PATCH 4/5] drm/i915: Nuke intel_dp->channel_eq_status Ville Syrjala
                   ` (4 subsequent siblings)
  6 siblings, 1 reply; 23+ messages in thread
From: Ville Syrjala @ 2018-01-17 19:21 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

Doing link retraining from the short pulse handler is problematic since
that might introduce deadlocks with MST sideband processing. Currently
we don't retrain MST links from this code, but we want to change that.
So better to move the entire thing to the hotplug work. We can utilize
the new encoder->hotplug() hook for this.

The only thing we leave in the short pulse handler is the link status
check. That one still depends on the link parameters stored under
intel_dp, so no locking around that but races should be mostly harmless
as the actual retraining code will recheck the link state if we
end up there by mistake.

v2: Rebase due to ->post_hotplug() now being just ->hotplug()
    Check the connector type to figure out if we should do
    the HDMI thing or the DP think for DDI

Cc: Manasi Navare <manasi.d.navare@intel.com>
Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c |  10 +-
 drivers/gpu/drm/i915/intel_dp.c  | 196 ++++++++++++++++++++++-----------------
 drivers/gpu/drm/i915/intel_drv.h |   2 +
 3 files changed, 120 insertions(+), 88 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 25793bdc692f..5f3d58f1ae6e 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -2880,7 +2880,10 @@ static bool intel_ddi_hotplug(struct intel_encoder *encoder,
 	drm_modeset_acquire_init(&ctx, 0);
 
 	for (;;) {
-		ret = intel_hdmi_reset_link(encoder, &ctx);
+		if (connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIA)
+			ret = intel_hdmi_reset_link(encoder, &ctx);
+		else
+			ret = intel_dp_retrain_link(encoder, &ctx);
 
 		if (ret == -EDEADLK) {
 			drm_modeset_backoff(&ctx);
@@ -3007,10 +3010,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
 	drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
 			 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
 
-	if (init_hdmi)
-		intel_encoder->hotplug = intel_ddi_hotplug;
-	else
-		intel_encoder->hotplug = intel_encoder_hotplug;
+	intel_encoder->hotplug = intel_ddi_hotplug;
 	intel_encoder->compute_output_type = intel_ddi_compute_output_type;
 	intel_encoder->compute_config = intel_ddi_compute_config;
 	intel_encoder->enable = intel_enable_ddi;
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 6bbf14410c2a..152016e09a11 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -4275,12 +4275,83 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
 	return -EINVAL;
 }
 
-static void
-intel_dp_retrain_link(struct intel_dp *intel_dp)
+static bool
+intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
+{
+	u8 link_status[DP_LINK_STATUS_SIZE];
+
+	if (!intel_dp_get_link_status(intel_dp, link_status)) {
+		DRM_ERROR("Failed to get link status\n");
+		return false;
+	}
+
+	/*
+	 * Validate the cached values of intel_dp->link_rate and
+	 * intel_dp->lane_count before attempting to retrain.
+	 */
+	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
+					intel_dp->lane_count))
+		return false;
+
+	/* Retrain if Channel EQ or CR not ok */
+	return !drm_dp_channel_eq_ok(link_status, intel_dp->lane_count);
+}
+
+/*
+ * If display is now connected check links status,
+ * there has been known issues of link loss triggering
+ * long pulse.
+ *
+ * Some sinks (eg. ASUS PB287Q) seem to perform some
+ * weird HPD ping pong during modesets. So we can apparently
+ * end up with HPD going low during a modeset, and then
+ * going back up soon after. And once that happens we must
+ * retrain the link to get a picture. That's in case no
+ * userspace component reacted to intermittent HPD dip.
+ */
+int intel_dp_retrain_link(struct intel_encoder *encoder,
+			  struct drm_modeset_acquire_ctx *ctx)
 {
-	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
 	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
-	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
+	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
+	struct intel_connector *connector = intel_dp->attached_connector;
+	struct drm_connector_state *conn_state;
+	struct intel_crtc_state *crtc_state;
+	struct intel_crtc *crtc;
+	int ret;
+
+	/* FIXME handle the MST connectors as well */
+
+	if (!connector || connector->base.status != connector_status_connected)
+		return 0;
+
+	ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, ctx);
+	if (ret)
+		return ret;
+
+	conn_state = connector->base.state;
+
+	crtc = to_intel_crtc(conn_state->crtc);
+	if (!crtc)
+		return 0;
+
+	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
+	if (ret)
+		return ret;
+
+	crtc_state = to_intel_crtc_state(crtc->base.state);
+
+	WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
+
+	if (!crtc_state->base.active)
+		return 0;
+
+	if (conn_state->commit &&
+	    !try_wait_for_completion(&conn_state->commit->hw_done))
+		return 0;
+
+	if (!intel_dp_needs_link_retrain(intel_dp))
+		return 0;
 
 	/* Suppress underruns caused by re-training */
 	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
@@ -4298,51 +4369,49 @@ intel_dp_retrain_link(struct intel_dp *intel_dp)
 	if (crtc->config->has_pch_encoder)
 		intel_set_pch_fifo_underrun_reporting(dev_priv,
 						      intel_crtc_pch_transcoder(crtc), true);
+
+	return 0;
 }
 
-static void
-intel_dp_check_link_status(struct intel_dp *intel_dp)
+/*
+ * If display is now connected check links status,
+ * there has been known issues of link loss triggering
+ * long pulse.
+ *
+ * Some sinks (eg. ASUS PB287Q) seem to perform some
+ * weird HPD ping pong during modesets. So we can apparently
+ * end up with HPD going low during a modeset, and then
+ * going back up soon after. And once that happens we must
+ * retrain the link to get a picture. That's in case no
+ * userspace component reacted to intermittent HPD dip.
+ */
+static bool intel_dp_hotplug(struct intel_encoder *encoder,
+			     struct intel_connector *connector)
 {
-	struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp));
-	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base;
-	struct drm_connector_state *conn_state =
-		intel_dp->attached_connector->base.state;
-	u8 link_status[DP_LINK_STATUS_SIZE];
-
-	WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
-
-	if (!intel_dp_get_link_status(intel_dp, link_status)) {
-		DRM_ERROR("Failed to get link status\n");
-		return;
-	}
+	struct drm_modeset_acquire_ctx ctx;
+	bool changed;
+	int ret;
 
-	if (!conn_state->crtc)
-		return;
+	changed = intel_encoder_hotplug(encoder, connector);
 
-	WARN_ON(!drm_modeset_is_locked(&conn_state->crtc->mutex));
+	drm_modeset_acquire_init(&ctx, 0);
 
-	if (!conn_state->crtc->state->active)
-		return;
+	for (;;) {
+		ret = intel_dp_retrain_link(encoder, &ctx);
 
-	if (conn_state->commit &&
-	    !try_wait_for_completion(&conn_state->commit->hw_done))
-		return;
+		if (ret == -EDEADLK) {
+			drm_modeset_backoff(&ctx);
+			continue;
+		}
 
-	/*
-	 * Validate the cached values of intel_dp->link_rate and
-	 * intel_dp->lane_count before attempting to retrain.
-	 */
-	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
-					intel_dp->lane_count))
-		return;
+		break;
+	}
 
-	/* Retrain if Channel EQ or CR not ok */
-	if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
-		DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
-			      intel_encoder->base.name);
+	drm_modeset_drop_locks(&ctx);
+	drm_modeset_acquire_fini(&ctx);
+	WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
 
-		intel_dp_retrain_link(intel_dp);
-	}
+	return changed;
 }
 
 /*
@@ -4400,7 +4469,9 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
 			DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
 	}
 
-	intel_dp_check_link_status(intel_dp);
+	/* defer to the hotplug work for link retraining if needed */
+	if (intel_dp_needs_link_retrain(intel_dp))
+		return false;
 
 	if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
 		DRM_DEBUG_KMS("Link Training Compliance Test requested\n");
@@ -4785,20 +4856,6 @@ intel_dp_long_pulse(struct intel_connector *connector)
 		 */
 		status = connector_status_disconnected;
 		goto out;
-	} else {
-		/*
-		 * If display is now connected check links status,
-		 * there has been known issues of link loss triggerring
-		 * long pulse.
-		 *
-		 * Some sinks (eg. ASUS PB287Q) seem to perform some
-		 * weird HPD ping pong during modesets. So we can apparently
-		 * end up with HPD going low during a modeset, and then
-		 * going back up soon after. And once that happens we must
-		 * retrain the link to get a picture. That's in case no
-		 * userspace component reacted to intermittent HPD dip.
-		 */
-		intel_dp_check_link_status(intel_dp);
 	}
 
 	/*
@@ -5340,37 +5397,10 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
 	}
 
 	if (!intel_dp->is_mst) {
-		struct drm_modeset_acquire_ctx ctx;
-		struct drm_connector *connector = &intel_dp->attached_connector->base;
-		struct drm_crtc *crtc;
-		int iret;
-		bool handled = false;
-
-		drm_modeset_acquire_init(&ctx, 0);
-retry:
-		iret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, &ctx);
-		if (iret)
-			goto err;
-
-		crtc = connector->state->crtc;
-		if (crtc) {
-			iret = drm_modeset_lock(&crtc->mutex, &ctx);
-			if (iret)
-				goto err;
-		}
+		bool handled;
 
 		handled = intel_dp_short_pulse(intel_dp);
 
-err:
-		if (iret == -EDEADLK) {
-			drm_modeset_backoff(&ctx);
-			goto retry;
-		}
-
-		drm_modeset_drop_locks(&ctx);
-		drm_modeset_acquire_fini(&ctx);
-		WARN(iret, "Acquiring modeset locks failed with %i\n", iret);
-
 		/* Short pulse can signify loss of hdcp authentication */
 		intel_hdcp_check_link(intel_dp->attached_connector);
 
@@ -6400,7 +6430,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
 			     "DP %c", port_name(port)))
 		goto err_encoder_init;
 
-	intel_encoder->hotplug = intel_encoder_hotplug;
+	intel_encoder->hotplug = intel_dp_hotplug;
 	intel_encoder->compute_config = intel_dp_compute_config;
 	intel_encoder->get_hw_state = intel_dp_get_hw_state;
 	intel_encoder->get_config = intel_dp_get_config;
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 5ea1dc3f63bf..ddf28a442cd7 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1611,6 +1611,8 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
 					    int link_rate, uint8_t lane_count);
 void intel_dp_start_link_train(struct intel_dp *intel_dp);
 void intel_dp_stop_link_train(struct intel_dp *intel_dp);
+int intel_dp_retrain_link(struct intel_encoder *encoder,
+			  struct drm_modeset_acquire_ctx *ctx);
 void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
 void intel_dp_encoder_reset(struct drm_encoder *encoder);
 void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
-- 
2.13.6

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 4/5] drm/i915: Nuke intel_dp->channel_eq_status
  2018-01-17 19:21 [PATCH 1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Ville Syrjala
  2018-01-17 19:21 ` [PATCH v2 2/5] drm/i915: Reinitialize sink scrambling/TMDS clock ratio on HPD Ville Syrjala
  2018-01-17 19:21 ` [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook Ville Syrjala
@ 2018-01-17 19:21 ` Ville Syrjala
  2018-01-19  6:59   ` Rodrigo Vivi
  2018-01-30 23:17   ` Lyude Paul
  2018-01-17 19:21 ` [PATCH 5/5] drm/i915: Track whether the DP link is trained or not Ville Syrjala
                   ` (3 subsequent siblings)
  6 siblings, 2 replies; 23+ messages in thread
From: Ville Syrjala @ 2018-01-17 19:21 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

intel_dp->channel_eq_status is used in exactly one function, and we
don't need it to persist between calls. So just go back to using a
local variable instead.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_dp_link_training.c | 6 +++---
 drivers/gpu/drm/i915/intel_drv.h              | 1 -
 2 files changed, 3 insertions(+), 4 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 05907fa8a553..1314f5d87d7d 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -248,6 +248,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 	int tries;
 	u32 training_pattern;
 	uint8_t link_status[DP_LINK_STATUS_SIZE];
+	bool channel_eq = false;
 
 	training_pattern = intel_dp_training_pattern(intel_dp);
 
@@ -259,7 +260,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 		return false;
 	}
 
-	intel_dp->channel_eq_status = false;
 	for (tries = 0; tries < 5; tries++) {
 
 		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
@@ -279,7 +279,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 
 		if (drm_dp_channel_eq_ok(link_status,
 					 intel_dp->lane_count)) {
-			intel_dp->channel_eq_status = true;
+			channel_eq = true;
 			DRM_DEBUG_KMS("Channel EQ done. DP Training "
 				      "successful\n");
 			break;
@@ -301,7 +301,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 
 	intel_dp_set_idle_link_train(intel_dp);
 
-	return intel_dp->channel_eq_status;
+	return channel_eq;
 
 }
 
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index ddf28a442cd7..1d018869ad02 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1045,7 +1045,6 @@ struct intel_dp {
 	bool link_mst;
 	bool has_audio;
 	bool detect_done;
-	bool channel_eq_status;
 	bool reset_link_params;
 	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
 	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
-- 
2.13.6

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* [PATCH 5/5] drm/i915: Track whether the DP link is trained or not
  2018-01-17 19:21 [PATCH 1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Ville Syrjala
                   ` (2 preceding siblings ...)
  2018-01-17 19:21 ` [PATCH 4/5] drm/i915: Nuke intel_dp->channel_eq_status Ville Syrjala
@ 2018-01-17 19:21 ` Ville Syrjala
  2018-01-30 23:19   ` Lyude Paul
  2018-02-28 20:08   ` Manasi Navare
  2018-01-18 11:21 ` ✓ Fi.CI.BAT: success for series starting with [1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Patchwork
                   ` (2 subsequent siblings)
  6 siblings, 2 replies; 23+ messages in thread
From: Ville Syrjala @ 2018-01-17 19:21 UTC (permalink / raw)
  To: intel-gfx

From: Ville Syrjälä <ville.syrjala@linux.intel.com>

LSPCON likes to throw short HPDs during the enable seqeunce prior to the
link being trained. These obviously result in the channel CR/EQ check
failing and thus we schedule a pointless hotplug work to retrain the
link. Avoid that by ignoring the bad CR/EQ status until we've actually
initially trained the link.

I've not actually investigated to see what LSPCON is trying to signal
with the short pulse. But as long as it signals anything I think we're
supposed to check the link status anyway, so I don't really see other
good ways to solve this. I've not seen these short pulses being
generated by normal DP sinks.

Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
---
 drivers/gpu/drm/i915/intel_ddi.c              |  2 ++
 drivers/gpu/drm/i915/intel_dp.c               | 10 +++++++---
 drivers/gpu/drm/i915/intel_dp_link_training.c |  2 ++
 drivers/gpu/drm/i915/intel_drv.h              |  1 +
 4 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index 5f3d58f1ae6e..7a4c5a2d36ed 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -2466,6 +2466,8 @@ static void intel_disable_ddi_dp(struct intel_encoder *encoder,
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
+	intel_dp->link_trained = false;
+
 	if (old_crtc_state->has_audio)
 		intel_audio_codec_disable(encoder,
 					  old_crtc_state, old_conn_state);
diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
index 152016e09a11..0cf92aa60f3e 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -1854,6 +1854,7 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp,
 			      int link_rate, uint8_t lane_count,
 			      bool link_mst)
 {
+	intel_dp->link_trained = false;
 	intel_dp->link_rate = link_rate;
 	intel_dp->lane_count = lane_count;
 	intel_dp->link_mst = link_mst;
@@ -2702,6 +2703,8 @@ static void intel_disable_dp(struct intel_encoder *encoder,
 {
 	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
 
+	intel_dp->link_trained = false;
+
 	if (old_crtc_state->has_audio)
 		intel_audio_codec_disable(encoder,
 					  old_crtc_state, old_conn_state);
@@ -4280,10 +4283,11 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
 {
 	u8 link_status[DP_LINK_STATUS_SIZE];
 
-	if (!intel_dp_get_link_status(intel_dp, link_status)) {
-		DRM_ERROR("Failed to get link status\n");
+	if (!intel_dp->link_trained)
+		return false;
+
+	if (!intel_dp_get_link_status(intel_dp, link_status))
 		return false;
-	}
 
 	/*
 	 * Validate the cached values of intel_dp->link_rate and
diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
index 1314f5d87d7d..78f1fe934da3 100644
--- a/drivers/gpu/drm/i915/intel_dp_link_training.c
+++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
@@ -307,6 +307,8 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
 
 void intel_dp_stop_link_train(struct intel_dp *intel_dp)
 {
+	intel_dp->link_trained = true;
+
 	intel_dp_set_link_train(intel_dp,
 				DP_TRAINING_PATTERN_DISABLE);
 }
diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
index 1d018869ad02..7a45ffb9e524 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1043,6 +1043,7 @@ struct intel_dp {
 	uint8_t lane_count;
 	uint8_t sink_count;
 	bool link_mst;
+	bool link_trained;
 	bool has_audio;
 	bool detect_done;
 	bool reset_link_params;
-- 
2.13.6

_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* ✓ Fi.CI.BAT: success for series starting with [1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook
  2018-01-17 19:21 [PATCH 1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Ville Syrjala
                   ` (3 preceding siblings ...)
  2018-01-17 19:21 ` [PATCH 5/5] drm/i915: Track whether the DP link is trained or not Ville Syrjala
@ 2018-01-18 11:21 ` Patchwork
  2018-01-18 13:04 ` ✓ Fi.CI.IGT: " Patchwork
  2018-01-30 23:22 ` [PATCH 1/5] " Lyude Paul
  6 siblings, 0 replies; 23+ messages in thread
From: Patchwork @ 2018-01-18 11:21 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook
URL   : https://patchwork.freedesktop.org/series/36645/
State : success

== Summary ==

Series 36645v1 series starting with [1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook
https://patchwork.freedesktop.org/api/1.0/series/36645/revisions/1/mbox/

Test debugfs_test:
        Subgroup read_all_entries:
                pass       -> FAIL       (fi-elk-e7500) fdo#103989
                pass       -> INCOMPLETE (fi-snb-2520m) fdo#103713
Test gem_mmap_gtt:
        Subgroup basic-small-bo-tiledx:
                fail       -> PASS       (fi-gdg-551) fdo#102575
Test kms_pipe_crc_basic:
        Subgroup suspend-read-crc-pipe-a:
                fail       -> PASS       (fi-skl-6700k2) fdo#103191

fdo#103989 https://bugs.freedesktop.org/show_bug.cgi?id=103989
fdo#103713 https://bugs.freedesktop.org/show_bug.cgi?id=103713
fdo#102575 https://bugs.freedesktop.org/show_bug.cgi?id=102575
fdo#103191 https://bugs.freedesktop.org/show_bug.cgi?id=103191

fi-bdw-5557u     total:288  pass:267  dwarn:0   dfail:0   fail:0   skip:21  time:419s
fi-bdw-gvtdvm    total:288  pass:264  dwarn:0   dfail:0   fail:0   skip:24  time:427s
fi-blb-e6850     total:288  pass:223  dwarn:1   dfail:0   fail:0   skip:64  time:370s
fi-bsw-n3050     total:288  pass:242  dwarn:0   dfail:0   fail:0   skip:46  time:489s
fi-bwr-2160      total:288  pass:183  dwarn:0   dfail:0   fail:0   skip:105 time:280s
fi-bxt-dsi       total:288  pass:258  dwarn:0   dfail:0   fail:0   skip:30  time:486s
fi-bxt-j4205     total:288  pass:259  dwarn:0   dfail:0   fail:0   skip:29  time:485s
fi-byt-j1900     total:288  pass:253  dwarn:0   dfail:0   fail:0   skip:35  time:465s
fi-byt-n2820     total:288  pass:249  dwarn:0   dfail:0   fail:0   skip:39  time:455s
fi-elk-e7500     total:224  pass:167  dwarn:10  dfail:0   fail:1   skip:45 
fi-gdg-551       total:288  pass:180  dwarn:0   dfail:0   fail:0   skip:108 time:277s
fi-glk-1         total:288  pass:260  dwarn:0   dfail:0   fail:0   skip:28  time:511s
fi-hsw-4770      total:288  pass:261  dwarn:0   dfail:0   fail:0   skip:27  time:391s
fi-hsw-4770r     total:288  pass:261  dwarn:0   dfail:0   fail:0   skip:27  time:399s
fi-ilk-650       total:288  pass:228  dwarn:0   dfail:0   fail:0   skip:60  time:410s
fi-ivb-3520m     total:288  pass:259  dwarn:0   dfail:0   fail:0   skip:29  time:451s
fi-ivb-3770      total:288  pass:255  dwarn:0   dfail:0   fail:0   skip:33  time:411s
fi-kbl-7500u     total:288  pass:263  dwarn:1   dfail:0   fail:0   skip:24  time:460s
fi-kbl-7560u     total:288  pass:269  dwarn:0   dfail:0   fail:0   skip:19  time:509s
fi-kbl-7567u     total:288  pass:268  dwarn:0   dfail:0   fail:0   skip:20  time:458s
fi-kbl-r         total:288  pass:261  dwarn:0   dfail:0   fail:0   skip:27  time:507s
fi-pnv-d510      total:288  pass:222  dwarn:1   dfail:0   fail:0   skip:65  time:580s
fi-skl-6260u     total:288  pass:268  dwarn:0   dfail:0   fail:0   skip:20  time:431s
fi-skl-6600u     total:288  pass:261  dwarn:0   dfail:0   fail:0   skip:27  time:513s
fi-skl-6700hq    total:288  pass:262  dwarn:0   dfail:0   fail:0   skip:26  time:533s
fi-skl-6700k2    total:288  pass:264  dwarn:0   dfail:0   fail:0   skip:24  time:494s
fi-skl-6770hq    total:288  pass:268  dwarn:0   dfail:0   fail:0   skip:20  time:489s
fi-skl-gvtdvm    total:288  pass:265  dwarn:0   dfail:0   fail:0   skip:23  time:432s
fi-snb-2520m     total:3    pass:2    dwarn:0   dfail:0   fail:0   skip:0  
fi-snb-2600      total:288  pass:248  dwarn:0   dfail:0   fail:0   skip:40  time:395s
Blacklisted hosts:
fi-cfl-s2        total:288  pass:262  dwarn:0   dfail:0   fail:0   skip:26  time:566s
fi-glk-dsi       total:288  pass:258  dwarn:0   dfail:0   fail:0   skip:30  time:471s

cb7287f74687f033ae8e50937b8294c16317170a drm-tip: 2018y-01m-18d-10h-31m-34s UTC integration manifest
d9a763b22cea drm/i915: Track whether the DP link is trained or not
735bae4ea266 drm/i915: Nuke intel_dp->channel_eq_status
a4fa60986939 drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
1d2c23dde9eb drm/i915: Reinitialize sink scrambling/TMDS clock ratio on HPD
95eb9426ffe5 drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_7704/issues.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* ✓ Fi.CI.IGT: success for series starting with [1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook
  2018-01-17 19:21 [PATCH 1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Ville Syrjala
                   ` (4 preceding siblings ...)
  2018-01-18 11:21 ` ✓ Fi.CI.BAT: success for series starting with [1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Patchwork
@ 2018-01-18 13:04 ` Patchwork
  2018-01-30 23:22 ` [PATCH 1/5] " Lyude Paul
  6 siblings, 0 replies; 23+ messages in thread
From: Patchwork @ 2018-01-18 13:04 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx

== Series Details ==

Series: series starting with [1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook
URL   : https://patchwork.freedesktop.org/series/36645/
State : success

== Summary ==

Test kms_cursor_crc:
        Subgroup cursor-128x128-suspend:
                skip       -> PASS       (shard-hsw) fdo#103540
Test perf:
        Subgroup polling:
                fail       -> PASS       (shard-hsw) fdo#102252
Test pm_rc6_residency:
        Subgroup rc6-accuracy:
                skip       -> PASS       (shard-snb)
Test kms_frontbuffer_tracking:
        Subgroup fbc-1p-primscrn-shrfb-pgflip-blt:
                skip       -> PASS       (shard-snb) fdo#101623 +1
Test kms_atomic_interruptible:
        Subgroup legacy-setmode:
                skip       -> PASS       (shard-snb)

fdo#103540 https://bugs.freedesktop.org/show_bug.cgi?id=103540
fdo#102252 https://bugs.freedesktop.org/show_bug.cgi?id=102252
fdo#101623 https://bugs.freedesktop.org/show_bug.cgi?id=101623

shard-hsw        total:2679 pass:1675 dwarn:1   dfail:0   fail:11  skip:990 time:15036s
shard-snb        total:2676 pass:1276 dwarn:1   dfail:0   fail:8   skip:1391 time:7469s
Blacklisted hosts:
shard-apl        total:2753 pass:1717 dwarn:1   dfail:0   fail:20  skip:1015 time:13883s
shard-kbl        total:2753 pass:1838 dwarn:1   dfail:0   fail:24  skip:890 time:10741s

== Logs ==

For more details see: https://intel-gfx-ci.01.org/tree/drm-tip/Patchwork_7704/shards.html
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 4/5] drm/i915: Nuke intel_dp->channel_eq_status
  2018-01-17 19:21 ` [PATCH 4/5] drm/i915: Nuke intel_dp->channel_eq_status Ville Syrjala
@ 2018-01-19  6:59   ` Rodrigo Vivi
  2018-02-28 20:12     ` Manasi Navare
  2018-01-30 23:17   ` Lyude Paul
  1 sibling, 1 reply; 23+ messages in thread
From: Rodrigo Vivi @ 2018-01-19  6:59 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx

On Wed, Jan 17, 2018 at 07:21:48PM +0000, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> intel_dp->channel_eq_status is used in exactly one function, and we
> don't need it to persist between calls. So just go back to using a
> local variable instead.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>

> ---
>  drivers/gpu/drm/i915/intel_dp_link_training.c | 6 +++---
>  drivers/gpu/drm/i915/intel_drv.h              | 1 -
>  2 files changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 05907fa8a553..1314f5d87d7d 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -248,6 +248,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  	int tries;
>  	u32 training_pattern;
>  	uint8_t link_status[DP_LINK_STATUS_SIZE];
> +	bool channel_eq = false;
>  
>  	training_pattern = intel_dp_training_pattern(intel_dp);
>  
> @@ -259,7 +260,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  		return false;
>  	}
>  
> -	intel_dp->channel_eq_status = false;
>  	for (tries = 0; tries < 5; tries++) {
>  
>  		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
> @@ -279,7 +279,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  
>  		if (drm_dp_channel_eq_ok(link_status,
>  					 intel_dp->lane_count)) {
> -			intel_dp->channel_eq_status = true;
> +			channel_eq = true;
>  			DRM_DEBUG_KMS("Channel EQ done. DP Training "
>  				      "successful\n");
>  			break;
> @@ -301,7 +301,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  
>  	intel_dp_set_idle_link_train(intel_dp);
>  
> -	return intel_dp->channel_eq_status;
> +	return channel_eq;
>  
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index ddf28a442cd7..1d018869ad02 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1045,7 +1045,6 @@ struct intel_dp {
>  	bool link_mst;
>  	bool has_audio;
>  	bool detect_done;
> -	bool channel_eq_status;
>  	bool reset_link_params;
>  	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
>  	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
> -- 
> 2.13.6
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 2/5] drm/i915: Reinitialize sink scrambling/TMDS clock ratio on HPD
  2018-01-17 19:21 ` [PATCH v2 2/5] drm/i915: Reinitialize sink scrambling/TMDS clock ratio on HPD Ville Syrjala
@ 2018-01-30 22:45   ` Lyude Paul
  0 siblings, 0 replies; 23+ messages in thread
From: Lyude Paul @ 2018-01-30 22:45 UTC (permalink / raw)
  To: Ville Syrjala, intel-gfx

On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> The LG 4k TV I have doesn't deassert HPD when I turn the TV off, but
> when I turn it back on it will pulse the HPD line. By that time it has
> forgotten everything we told it about scrambling and the clock ratio.
> Hence if we want to get a picture out if it again we have to tell it
> whether we're currently sending scrambled data or not. Implement
> that via the encoder->hotplug() hook.
> 
> v2: Force a full modeset to not follow the HDMI 2.0 spec more
>     closely (Shashank)
> 
> Cc: Shashank Sharma <shashank.sharma@intel.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c | 146
> ++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 145 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> b/drivers/gpu/drm/i915/intel_ddi.c
> index 1aeae3e97013..25793bdc692f 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -25,6 +25,7 @@
>   *
>   */
>  
> +#include <drm/drm_scdc_helper.h>
>  #include "i915_drv.h"
>  #include "intel_drv.h"
>  
> @@ -2756,6 +2757,146 @@ intel_ddi_init_dp_connector(struct intel_digital_port
> *intel_dig_port)
>  	return connector;
>  }
>  
> +static int modeset_pipe(struct drm_crtc *crtc,
> +			struct drm_modeset_acquire_ctx *ctx)
> +{
> +	struct drm_atomic_state *state;
> +	struct drm_crtc_state *crtc_state;
> +	int ret;
> +
> +	state = drm_atomic_state_alloc(crtc->dev);
> +	if (!state)
> +		return -ENOMEM;
> +
> +	state->acquire_ctx = ctx;
> +
> +	crtc_state = drm_atomic_get_crtc_state(state, crtc);
> +	if (IS_ERR(crtc_state)) {
> +		ret = PTR_ERR(crtc_state);
> +		goto out;
> +	}
> +
> +	crtc_state->mode_changed = true;
> +
> +	ret = drm_atomic_add_affected_connectors(state, crtc);
> +	if (ret)
> +		goto out;
> +
> +	ret = drm_atomic_add_affected_planes(state, crtc);
> +	if (ret)
> +		goto out;
> +
> +	ret = drm_atomic_commit(state);
> +	if (ret)
> +		goto out;
> +
> +	return 0;
> +
> + out:
> +	drm_atomic_state_put(state);
> +
> +	return ret;
> +}
> +
> +static int intel_hdmi_reset_link(struct intel_encoder *encoder,
> +				 struct drm_modeset_acquire_ctx *ctx)
> +{
> +	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> +	struct intel_hdmi *hdmi = enc_to_intel_hdmi(&encoder->base);
> +	struct intel_connector *connector = hdmi->attached_connector;
> +	struct i2c_adapter *adapter =
> +		intel_gmbus_get_adapter(dev_priv, hdmi->ddc_bus);
> +	struct drm_connector_state *conn_state;
> +	struct intel_crtc_state *crtc_state;
> +	struct intel_crtc *crtc;
> +	u8 config;
> +	int ret;
> +
> +	if (!connector || connector->base.status !=
> connector_status_connected)
> +		return 0;
> +
> +	ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
> ctx);
> +	if (ret)
> +		return ret;
> +
> +	conn_state = connector->base.state;
> +
> +	crtc = to_intel_crtc(conn_state->crtc);
> +	if (!crtc)
> +		return 0;
> +
> +	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
> +	if (ret)
> +		return ret;
> +
> +	crtc_state = to_intel_crtc_state(crtc->base.state);
> +
> +	WARN_ON(!intel_crtc_has_type(crtc_state, INTEL_OUTPUT_HDMI));
> +
> +	if (!crtc_state->base.active)
> +		return 0;
> +
> +	if (!crtc_state->hdmi_high_tmds_clock_ratio &&
> +	    !crtc_state->hdmi_scrambling)
> +		return 0;
> +
> +	if (conn_state->commit &&
> +	    !try_wait_for_completion(&conn_state->commit->hw_done))
> +		return 0;
Probably should make a helper function for this since we use this in both DP and
HDMI codepaths

> +
> +	ret = drm_scdc_readb(adapter, SCDC_TMDS_CONFIG, &config);
> +	if (ret < 0) {
> +		DRM_ERROR("Failed to read TMDS config: %d\n", ret);
> +		return 0;
> +	}
> +
> +	if (!!(config & SCDC_TMDS_BIT_CLOCK_RATIO_BY_40) ==
> +	    crtc_state->hdmi_high_tmds_clock_ratio &&
> +	    !!(config & SCDC_SCRAMBLING_ENABLE) ==
> +	    crtc_state->hdmi_scrambling)
> +		return 0;
> +
> +	/*
> +	 * HDMI 2.0 says that one should not send scrambled data
> +	 * prior to configuring the sink scrambling, and that
> +	 * TMDS clock/data transmission should be suspended when
> +	 * changing the TMDS clock rate in the sink. So let's
> +	 * just do a full modeset here, even though some sinks
> +	 * would be perfectly happy if were to just reconfigure
> +	 * the SCDC settings on the fly.
> +	 */
> +	return modeset_pipe(&crtc->base, ctx);
> +}
> +
> +static bool intel_ddi_hotplug(struct intel_encoder *encoder,
> +			      struct intel_connector *connector)
> +{
> +	struct drm_modeset_acquire_ctx ctx;
> +	bool changed;
> +	int ret;
> +
> +	changed = intel_encoder_hotplug(encoder, connector);
> +
> +	drm_modeset_acquire_init(&ctx, 0);
> +
> +	for (;;) {
> +		ret = intel_hdmi_reset_link(encoder, &ctx);
> +
> +		if (ret == -EDEADLK) {
> +			drm_modeset_backoff(&ctx);
> +			continue;
> +		}
> +
> +		break;
> +	}
> +
> +	drm_modeset_drop_locks(&ctx);
> +	drm_modeset_acquire_fini(&ctx);
> +	WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
> +
> +	return changed;
> +}
> +
>  static struct intel_connector *
>  intel_ddi_init_hdmi_connector(struct intel_digital_port *intel_dig_port)
>  {
> @@ -2866,7 +3007,10 @@ void intel_ddi_init(struct drm_i915_private *dev_priv,
> enum port port)
>  	drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
>  			 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
>  
> -	intel_encoder->hotplug = intel_encoder_hotplug;
> +	if (init_hdmi)
> +		intel_encoder->hotplug = intel_ddi_hotplug;
> +	else
> +		intel_encoder->hotplug = intel_encoder_hotplug;
>  	intel_encoder->compute_output_type = intel_ddi_compute_output_type;
>  	intel_encoder->compute_config = intel_ddi_compute_config;
>  	intel_encoder->enable = intel_enable_ddi;
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
  2018-01-17 19:21 ` [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook Ville Syrjala
@ 2018-01-30 23:16   ` Lyude Paul
  2018-01-31 13:27     ` Ville Syrjälä
  0 siblings, 1 reply; 23+ messages in thread
From: Lyude Paul @ 2018-01-30 23:16 UTC (permalink / raw)
  To: Ville Syrjala, intel-gfx

On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Doing link retraining from the short pulse handler is problematic since
> that might introduce deadlocks with MST sideband processing. Currently
> we don't retrain MST links from this code, but we want to change that.
> So better to move the entire thing to the hotplug work. We can utilize
> the new encoder->hotplug() hook for this.
> 
> The only thing we leave in the short pulse handler is the link status
> check. That one still depends on the link parameters stored under
> intel_dp, so no locking around that but races should be mostly harmless
> as the actual retraining code will recheck the link state if we
> end up there by mistake.
> 
> v2: Rebase due to ->post_hotplug() now being just ->hotplug()
>     Check the connector type to figure out if we should do
>     the HDMI thing or the DP think for DDI
> 
> Cc: Manasi Navare <manasi.d.navare@intel.com>
> Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c |  10 +-
>  drivers/gpu/drm/i915/intel_dp.c  | 196 ++++++++++++++++++++++--------------
> ---
>  drivers/gpu/drm/i915/intel_drv.h |   2 +
>  3 files changed, 120 insertions(+), 88 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> b/drivers/gpu/drm/i915/intel_ddi.c
> index 25793bdc692f..5f3d58f1ae6e 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -2880,7 +2880,10 @@ static bool intel_ddi_hotplug(struct intel_encoder
> *encoder,
>  	drm_modeset_acquire_init(&ctx, 0);
>  
>  	for (;;) {
> -		ret = intel_hdmi_reset_link(encoder, &ctx);
> +		if (connector->base.connector_type ==
> DRM_MODE_CONNECTOR_HDMIA)
> +			ret = intel_hdmi_reset_link(encoder, &ctx);
> +		else
> +			ret = intel_dp_retrain_link(encoder, &ctx);
>  
>  		if (ret == -EDEADLK) {
>  			drm_modeset_backoff(&ctx);
> @@ -3007,10 +3010,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv,
> enum port port)
>  	drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
>  			 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
>  
> -	if (init_hdmi)
> -		intel_encoder->hotplug = intel_ddi_hotplug;
> -	else
> -		intel_encoder->hotplug = intel_encoder_hotplug;
> +	intel_encoder->hotplug = intel_ddi_hotplug;
>  	intel_encoder->compute_output_type = intel_ddi_compute_output_type;
>  	intel_encoder->compute_config = intel_ddi_compute_config;
>  	intel_encoder->enable = intel_enable_ddi;
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 6bbf14410c2a..152016e09a11 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -4275,12 +4275,83 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
>  	return -EINVAL;
>  }
>  
> -static void
> -intel_dp_retrain_link(struct intel_dp *intel_dp)
> +static bool
> +intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
> +{
> +	u8 link_status[DP_LINK_STATUS_SIZE];
> +
> +	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> +		DRM_ERROR("Failed to get link status\n");
> +		return false;
> +	}
> +
> +	/*
> +	 * Validate the cached values of intel_dp->link_rate and
> +	 * intel_dp->lane_count before attempting to retrain.
> +	 */
> +	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
> +					intel_dp->lane_count))
> +		return false;
> +
> +	/* Retrain if Channel EQ or CR not ok */
> +	return !drm_dp_channel_eq_ok(link_status, intel_dp->lane_count);
> +}
> +
> +/*
> + * If display is now connected check links status,
> + * there has been known issues of link loss triggering
> + * long pulse.
> + *
> + * Some sinks (eg. ASUS PB287Q) seem to perform some
> + * weird HPD ping pong during modesets. So we can apparently
> + * end up with HPD going low during a modeset, and then
> + * going back up soon after. And once that happens we must
> + * retrain the link to get a picture. That's in case no
> + * userspace component reacted to intermittent HPD dip.
> + */
> +int intel_dp_retrain_link(struct intel_encoder *encoder,
> +			  struct drm_modeset_acquire_ctx *ctx)
>  {
> -	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
>  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> -	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
> +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> +	struct intel_connector *connector = intel_dp->attached_connector;
> +	struct drm_connector_state *conn_state;
> +	struct intel_crtc_state *crtc_state;
> +	struct intel_crtc *crtc;
> +	int ret;
> +
> +	/* FIXME handle the MST connectors as well */
> +
> +	if (!connector || connector->base.status !=
> connector_status_connected)
> +		return 0;
> +
> +	ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
> ctx);
> +	if (ret)
> +		return ret;
> +
> +	conn_state = connector->base.state;
> +
> +	crtc = to_intel_crtc(conn_state->crtc);
> +	if (!crtc)
> +		return 0;
> +
> +	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
> +	if (ret)
> +		return ret;
> +
> +	crtc_state = to_intel_crtc_state(crtc->base.state);
> +
> +	WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
> +
> +	if (!crtc_state->base.active)
> +		return 0;
> +
> +	if (conn_state->commit &&
> +	    !try_wait_for_completion(&conn_state->commit->hw_done))
> +		return 0;
> +
> +	if (!intel_dp_needs_link_retrain(intel_dp))
> +		return 0;
NAK, this definitely won't work for implementing MST retraining. There's some
pretty huge differences with how retraining needs to be handled on SST vs. MST.
An example with some normal SST sink vs. what happens on my caldigit TS3

SST:
    1. commit modeset, everything is OK
    2. something happens, sink sends shortpulse and changes link status registers
    in dpcd
    3. Source receives short pulse, tries retraining five times
    4. if this succeeds:
        5. we're done here
    6. if this fails:
        7. mark link status as bad
        8. get fallback parameters
        9. hotplug event

MST (i915 doesn't do this yet, but this is generally how it needs to be
handled):
    1. commit modeset, everything is OK
    2. something happens (in my case, the MST hub discovers it had the wrong max
    link rate/lane count), sink sends ESI indicating channel EQ has failed
    3. retraining commences with five retries.
    4. if this succeeds:
       5. continue
    6. if this fails (I actually haven't seen this once yet)
        7. mark link status as bad on all downstream connectors
        8. get fallback parameters
        9. hotplug event
    10. the retrain didn't actually work (despite what the SST link status
    registers told us). go back to step 3 five more times
    11. if this fails:
        12. mark link status as bad on all downstream connectors
        13. get fallback parameters
        14. hotplug event

simply put: we really should keep the "do we need to retrain?" logic out of the
actual retraining helpers so that SST/MST codepaths can do their own checks to
figure this out.

>  
>  	/* Suppress underruns caused by re-training */
>  	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
> @@ -4298,51 +4369,49 @@ intel_dp_retrain_link(struct intel_dp *intel_dp)
>  	if (crtc->config->has_pch_encoder)
>  		intel_set_pch_fifo_underrun_reporting(dev_priv,
>  						      intel_crtc_pch_transcod
> er(crtc), true);
> +
> +	return 0;
>  }
>  
> -static void
> -intel_dp_check_link_status(struct intel_dp *intel_dp)
> +/*
> + * If display is now connected check links status,
> + * there has been known issues of link loss triggering
> + * long pulse.
> + *
> + * Some sinks (eg. ASUS PB287Q) seem to perform some
> + * weird HPD ping pong during modesets. So we can apparently
> + * end up with HPD going low during a modeset, and then
> + * going back up soon after. And once that happens we must
> + * retrain the link to get a picture. That's in case no
> + * userspace component reacted to intermittent HPD dip.
> + */
> +static bool intel_dp_hotplug(struct intel_encoder *encoder,
> +			     struct intel_connector *connector)
>  {
> -	struct drm_i915_private *dev_priv =
> to_i915(intel_dp_to_dev(intel_dp));
> -	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)-
> >base;
> -	struct drm_connector_state *conn_state =
> -		intel_dp->attached_connector->base.state;
> -	u8 link_status[DP_LINK_STATUS_SIZE];
> -
> -	WARN_ON(!drm_modeset_is_locked(&dev_priv-
> >drm.mode_config.connection_mutex));
> -
> -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> -		DRM_ERROR("Failed to get link status\n");
> -		return;
> -	}
> +	struct drm_modeset_acquire_ctx ctx;
> +	bool changed;
> +	int ret;
>  
> -	if (!conn_state->crtc)
> -		return;
> +	changed = intel_encoder_hotplug(encoder, connector);
>  
> -	WARN_ON(!drm_modeset_is_locked(&conn_state->crtc->mutex));
> +	drm_modeset_acquire_init(&ctx, 0);
>  
> -	if (!conn_state->crtc->state->active)
> -		return;
> +	for (;;) {
> +		ret = intel_dp_retrain_link(encoder, &ctx);
>  
> -	if (conn_state->commit &&
> -	    !try_wait_for_completion(&conn_state->commit->hw_done))
> -		return;
> +		if (ret == -EDEADLK) {
> +			drm_modeset_backoff(&ctx);
> +			continue;
> +		}
>  
> -	/*
> -	 * Validate the cached values of intel_dp->link_rate and
> -	 * intel_dp->lane_count before attempting to retrain.
> -	 */
> -	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
> -					intel_dp->lane_count))
> -		return;
> +		break;
> +	}
>  
> -	/* Retrain if Channel EQ or CR not ok */
> -	if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
> -		DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
> -			      intel_encoder->base.name);
> +	drm_modeset_drop_locks(&ctx);
> +	drm_modeset_acquire_fini(&ctx);
> +	WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
>  
> -		intel_dp_retrain_link(intel_dp);
> -	}
> +	return changed;
>  }
>  
>  /*
> @@ -4400,7 +4469,9 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
>  			DRM_DEBUG_DRIVER("CP or sink specific irq
> unhandled\n");
>  	}
>  
> -	intel_dp_check_link_status(intel_dp);
> +	/* defer to the hotplug work for link retraining if needed */
> +	if (intel_dp_needs_link_retrain(intel_dp))
> +		return false;
>  
>  	if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
>  		DRM_DEBUG_KMS("Link Training Compliance Test requested\n");
> @@ -4785,20 +4856,6 @@ intel_dp_long_pulse(struct intel_connector *connector)
>  		 */
>  		status = connector_status_disconnected;
>  		goto out;
> -	} else {
> -		/*
> -		 * If display is now connected check links status,
> -		 * there has been known issues of link loss triggerring
> -		 * long pulse.
> -		 *
> -		 * Some sinks (eg. ASUS PB287Q) seem to perform some
> -		 * weird HPD ping pong during modesets. So we can apparently
> -		 * end up with HPD going low during a modeset, and then
> -		 * going back up soon after. And once that happens we must
> -		 * retrain the link to get a picture. That's in case no
> -		 * userspace component reacted to intermittent HPD dip.
> -		 */
> -		intel_dp_check_link_status(intel_dp);
>  	}
>  
>  	/*
> @@ -5340,37 +5397,10 @@ intel_dp_hpd_pulse(struct intel_digital_port
> *intel_dig_port, bool long_hpd)
>  	}
>  
>  	if (!intel_dp->is_mst) {
> -		struct drm_modeset_acquire_ctx ctx;
> -		struct drm_connector *connector = &intel_dp-
> >attached_connector->base;
> -		struct drm_crtc *crtc;
> -		int iret;
> -		bool handled = false;
> -
> -		drm_modeset_acquire_init(&ctx, 0);
> -retry:
> -		iret = drm_modeset_lock(&dev_priv-
> >drm.mode_config.connection_mutex, &ctx);
> -		if (iret)
> -			goto err;
> -
> -		crtc = connector->state->crtc;
> -		if (crtc) {
> -			iret = drm_modeset_lock(&crtc->mutex, &ctx);
> -			if (iret)
> -				goto err;
> -		}
> +		bool handled;
>  
>  		handled = intel_dp_short_pulse(intel_dp);
>  
> -err:
> -		if (iret == -EDEADLK) {
> -			drm_modeset_backoff(&ctx);
> -			goto retry;
> -		}
> -
> -		drm_modeset_drop_locks(&ctx);
> -		drm_modeset_acquire_fini(&ctx);
> -		WARN(iret, "Acquiring modeset locks failed with %i\n", iret);
> -
>  		/* Short pulse can signify loss of hdcp authentication */
>  		intel_hdcp_check_link(intel_dp->attached_connector);
>  
> @@ -6400,7 +6430,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
>  			     "DP %c", port_name(port)))
>  		goto err_encoder_init;
>  
> -	intel_encoder->hotplug = intel_encoder_hotplug;
> +	intel_encoder->hotplug = intel_dp_hotplug;
>  	intel_encoder->compute_config = intel_dp_compute_config;
>  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
>  	intel_encoder->get_config = intel_dp_get_config;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h
> index 5ea1dc3f63bf..ddf28a442cd7 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1611,6 +1611,8 @@ int intel_dp_get_link_train_fallback_values(struct
> intel_dp *intel_dp,
>  					    int link_rate, uint8_t
> lane_count);
>  void intel_dp_start_link_train(struct intel_dp *intel_dp);
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> +int intel_dp_retrain_link(struct intel_encoder *encoder,
> +			  struct drm_modeset_acquire_ctx *ctx);
>  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
>  void intel_dp_encoder_reset(struct drm_encoder *encoder);
>  void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 4/5] drm/i915: Nuke intel_dp->channel_eq_status
  2018-01-17 19:21 ` [PATCH 4/5] drm/i915: Nuke intel_dp->channel_eq_status Ville Syrjala
  2018-01-19  6:59   ` Rodrigo Vivi
@ 2018-01-30 23:17   ` Lyude Paul
  1 sibling, 0 replies; 23+ messages in thread
From: Lyude Paul @ 2018-01-30 23:17 UTC (permalink / raw)
  To: Ville Syrjala, intel-gfx

Reviewed-by: Lyude Paul <lyude@redhat.com>

On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> intel_dp->channel_eq_status is used in exactly one function, and we
> don't need it to persist between calls. So just go back to using a
> local variable instead.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_dp_link_training.c | 6 +++---
>  drivers/gpu/drm/i915/intel_drv.h              | 1 -
>  2 files changed, 3 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 05907fa8a553..1314f5d87d7d 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -248,6 +248,7 @@ intel_dp_link_training_channel_equalization(struct
> intel_dp *intel_dp)
>  	int tries;
>  	u32 training_pattern;
>  	uint8_t link_status[DP_LINK_STATUS_SIZE];
> +	bool channel_eq = false;
>  
>  	training_pattern = intel_dp_training_pattern(intel_dp);
>  
> @@ -259,7 +260,6 @@ intel_dp_link_training_channel_equalization(struct
> intel_dp *intel_dp)
>  		return false;
>  	}
>  
> -	intel_dp->channel_eq_status = false;
>  	for (tries = 0; tries < 5; tries++) {
>  
>  		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
> @@ -279,7 +279,7 @@ intel_dp_link_training_channel_equalization(struct
> intel_dp *intel_dp)
>  
>  		if (drm_dp_channel_eq_ok(link_status,
>  					 intel_dp->lane_count)) {
> -			intel_dp->channel_eq_status = true;
> +			channel_eq = true;
>  			DRM_DEBUG_KMS("Channel EQ done. DP Training "
>  				      "successful\n");
>  			break;
> @@ -301,7 +301,7 @@ intel_dp_link_training_channel_equalization(struct
> intel_dp *intel_dp)
>  
>  	intel_dp_set_idle_link_train(intel_dp);
>  
> -	return intel_dp->channel_eq_status;
> +	return channel_eq;
>  
>  }
>  
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h
> index ddf28a442cd7..1d018869ad02 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1045,7 +1045,6 @@ struct intel_dp {
>  	bool link_mst;
>  	bool has_audio;
>  	bool detect_done;
> -	bool channel_eq_status;
>  	bool reset_link_params;
>  	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
>  	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 5/5] drm/i915: Track whether the DP link is trained or not
  2018-01-17 19:21 ` [PATCH 5/5] drm/i915: Track whether the DP link is trained or not Ville Syrjala
@ 2018-01-30 23:19   ` Lyude Paul
  2018-02-28 20:08   ` Manasi Navare
  1 sibling, 0 replies; 23+ messages in thread
From: Lyude Paul @ 2018-01-30 23:19 UTC (permalink / raw)
  To: Ville Syrjala, intel-gfx

Reviewed-by: Lyude Paul <lyude@redhat.com>

On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> LSPCON likes to throw short HPDs during the enable seqeunce prior to the
> link being trained. These obviously result in the channel CR/EQ check
> failing and thus we schedule a pointless hotplug work to retrain the
> link. Avoid that by ignoring the bad CR/EQ status until we've actually
> initially trained the link.
> 
> I've not actually investigated to see what LSPCON is trying to signal
> with the short pulse. But as long as it signals anything I think we're
> supposed to check the link status anyway, so I don't really see other
> good ways to solve this. I've not seen these short pulses being
> generated by normal DP sinks.
> 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              |  2 ++
>  drivers/gpu/drm/i915/intel_dp.c               | 10 +++++++---
>  drivers/gpu/drm/i915/intel_dp_link_training.c |  2 ++
>  drivers/gpu/drm/i915/intel_drv.h              |  1 +
>  4 files changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> b/drivers/gpu/drm/i915/intel_ddi.c
> index 5f3d58f1ae6e..7a4c5a2d36ed 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -2466,6 +2466,8 @@ static void intel_disable_ddi_dp(struct intel_encoder
> *encoder,
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  
> +	intel_dp->link_trained = false;
> +
>  	if (old_crtc_state->has_audio)
>  		intel_audio_codec_disable(encoder,
>  					  old_crtc_state, old_conn_state);
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 152016e09a11..0cf92aa60f3e 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1854,6 +1854,7 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp,
>  			      int link_rate, uint8_t lane_count,
>  			      bool link_mst)
>  {
> +	intel_dp->link_trained = false;
>  	intel_dp->link_rate = link_rate;
>  	intel_dp->lane_count = lane_count;
>  	intel_dp->link_mst = link_mst;
> @@ -2702,6 +2703,8 @@ static void intel_disable_dp(struct intel_encoder
> *encoder,
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  
> +	intel_dp->link_trained = false;
> +
>  	if (old_crtc_state->has_audio)
>  		intel_audio_codec_disable(encoder,
>  					  old_crtc_state, old_conn_state);
> @@ -4280,10 +4283,11 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
>  {
>  	u8 link_status[DP_LINK_STATUS_SIZE];
>  
> -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> -		DRM_ERROR("Failed to get link status\n");
> +	if (!intel_dp->link_trained)
> +		return false;
> +
> +	if (!intel_dp_get_link_status(intel_dp, link_status))
>  		return false;
> -	}
>  
>  	/*
>  	 * Validate the cached values of intel_dp->link_rate and
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c
> b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 1314f5d87d7d..78f1fe934da3 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -307,6 +307,8 @@ intel_dp_link_training_channel_equalization(struct
> intel_dp *intel_dp)
>  
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>  {
> +	intel_dp->link_trained = true;
> +
>  	intel_dp_set_link_train(intel_dp,
>  				DP_TRAINING_PATTERN_DISABLE);
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h
> index 1d018869ad02..7a45ffb9e524 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1043,6 +1043,7 @@ struct intel_dp {
>  	uint8_t lane_count;
>  	uint8_t sink_count;
>  	bool link_mst;
> +	bool link_trained;
>  	bool has_audio;
>  	bool detect_done;
>  	bool reset_link_params;
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook
  2018-01-17 19:21 [PATCH 1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Ville Syrjala
                   ` (5 preceding siblings ...)
  2018-01-18 13:04 ` ✓ Fi.CI.IGT: " Patchwork
@ 2018-01-30 23:22 ` Lyude Paul
  6 siblings, 0 replies; 23+ messages in thread
From: Lyude Paul @ 2018-01-30 23:22 UTC (permalink / raw)
  To: Ville Syrjala, intel-gfx

Almost forgot to respond to this one!

Reviewed-by: Lyude Paul <lyude@redhat.com>

On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> Allow encoders to customize their hotplug processing by moving the
> intel_hpd_irq_event() code into an encoder hotplug vfunc. Currently
> only SDVO needs this to re-enable hotplug signalling in the SDVO
> chip. We'll use this same hook for DP/HDMI link management later.
> 
> Reviewed-by: Jani Nikula <jani.nikula@intel.com>
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_crt.c     |  4 +++-
>  drivers/gpu/drm/i915/intel_ddi.c     |  1 +
>  drivers/gpu/drm/i915/intel_dp.c      |  1 +
>  drivers/gpu/drm/i915/intel_drv.h     |  6 ++++--
>  drivers/gpu/drm/i915/intel_hdmi.c    |  1 +
>  drivers/gpu/drm/i915/intel_hotplug.c | 24 ++++++++++++------------
>  drivers/gpu/drm/i915/intel_sdvo.c    | 12 ++++++++++--
>  7 files changed, 32 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_crt.c
> b/drivers/gpu/drm/i915/intel_crt.c
> index 9f31aea51dff..9bc47cff5409 100644
> --- a/drivers/gpu/drm/i915/intel_crt.c
> +++ b/drivers/gpu/drm/i915/intel_crt.c
> @@ -966,8 +966,10 @@ void intel_crt_init(struct drm_i915_private *dev_priv)
>  	crt->base.power_domain = POWER_DOMAIN_PORT_CRT;
>  
>  	if (I915_HAS_HOTPLUG(dev_priv) &&
> -	    !dmi_check_system(intel_spurious_crt_detect))
> +	    !dmi_check_system(intel_spurious_crt_detect)) {
>  		crt->base.hpd_pin = HPD_CRT;
> +		crt->base.hotplug = intel_encoder_hotplug;
> +	}
>  
>  	if (HAS_DDI(dev_priv)) {
>  		crt->base.port = PORT_E;
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> b/drivers/gpu/drm/i915/intel_ddi.c
> index 6260a882fbe4..1aeae3e97013 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -2866,6 +2866,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv,
> enum port port)
>  	drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
>  			 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
>  
> +	intel_encoder->hotplug = intel_encoder_hotplug;
>  	intel_encoder->compute_output_type = intel_ddi_compute_output_type;
>  	intel_encoder->compute_config = intel_ddi_compute_config;
>  	intel_encoder->enable = intel_enable_ddi;
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 68229f53d5b8..6bbf14410c2a 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -6400,6 +6400,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
>  			     "DP %c", port_name(port)))
>  		goto err_encoder_init;
>  
> +	intel_encoder->hotplug = intel_encoder_hotplug;
>  	intel_encoder->compute_config = intel_dp_compute_config;
>  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
>  	intel_encoder->get_config = intel_dp_get_config;
> diff --git a/drivers/gpu/drm/i915/intel_drv.h
> b/drivers/gpu/drm/i915/intel_drv.h
> index 5c8e260ca2bc..5ea1dc3f63bf 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -214,7 +214,8 @@ struct intel_encoder {
>  	enum intel_output_type type;
>  	enum port port;
>  	unsigned int cloneable;
> -	void (*hot_plug)(struct intel_encoder *);
> +	bool (*hotplug)(struct intel_encoder *encoder,
> +			struct intel_connector *connector);
>  	enum intel_output_type (*compute_output_type)(struct intel_encoder *,
>  						      struct intel_crtc_state
> *,
>  						      struct
> drm_connector_state *);
> @@ -1690,7 +1691,8 @@ int intel_dsi_dcs_init_backlight_funcs(struct
> intel_connector *intel_connector);
>  void intel_dvo_init(struct drm_i915_private *dev_priv);
>  /* intel_hotplug.c */
>  void intel_hpd_poll_init(struct drm_i915_private *dev_priv);
> -
> +bool intel_encoder_hotplug(struct intel_encoder *encoder,
> +			   struct intel_connector *connector);
>  
>  /* legacy fbdev emulation in intel_fbdev.c */
>  #ifdef CONFIG_DRM_FBDEV_EMULATION
> diff --git a/drivers/gpu/drm/i915/intel_hdmi.c
> b/drivers/gpu/drm/i915/intel_hdmi.c
> index 691f15b59124..4a93cfd7a28e 100644
> --- a/drivers/gpu/drm/i915/intel_hdmi.c
> +++ b/drivers/gpu/drm/i915/intel_hdmi.c
> @@ -2348,6 +2348,7 @@ void intel_hdmi_init(struct drm_i915_private *dev_priv,
>  			 &intel_hdmi_enc_funcs, DRM_MODE_ENCODER_TMDS,
>  			 "HDMI %c", port_name(port));
>  
> +	intel_encoder->hotplug = intel_encoder_hotplug;
>  	intel_encoder->compute_config = intel_hdmi_compute_config;
>  	if (HAS_PCH_SPLIT(dev_priv)) {
>  		intel_encoder->disable = pch_disable_hdmi;
> diff --git a/drivers/gpu/drm/i915/intel_hotplug.c
> b/drivers/gpu/drm/i915/intel_hotplug.c
> index 875d5d218d5c..0191c7831a06 100644
> --- a/drivers/gpu/drm/i915/intel_hotplug.c
> +++ b/drivers/gpu/drm/i915/intel_hotplug.c
> @@ -263,24 +263,25 @@ static void intel_hpd_irq_storm_reenable_work(struct
> work_struct *work)
>  	intel_runtime_pm_put(dev_priv);
>  }
>  
> -static bool intel_hpd_irq_event(struct drm_device *dev,
> -				struct drm_connector *connector)
> +bool intel_encoder_hotplug(struct intel_encoder *encoder,
> +			   struct intel_connector *connector)
>  {
> +	struct drm_device *dev = connector->base.dev;
>  	enum drm_connector_status old_status;
>  
>  	WARN_ON(!mutex_is_locked(&dev->mode_config.mutex));
> -	old_status = connector->status;
> +	old_status = connector->base.status;
>  
> -	connector->status = drm_helper_probe_detect(connector, NULL, false);
> +	connector->base.status = drm_helper_probe_detect(&connector->base,
> NULL, false);
>  
> -	if (old_status == connector->status)
> +	if (old_status == connector->base.status)
>  		return false;
>  
>  	DRM_DEBUG_KMS("[CONNECTOR:%d:%s] status updated from %s to %s\n",
> -		      connector->base.id,
> -		      connector->name,
> +		      connector->base.base.id,
> +		      connector->base.name,
>  		      drm_get_connector_status_name(old_status),
> -		      drm_get_connector_status_name(connector->status));
> +		      drm_get_connector_status_name(connector->base.status));
>  
>  	return true;
>  }
> @@ -370,10 +371,9 @@ static void i915_hotplug_work_func(struct work_struct
> *work)
>  		if (hpd_event_bits & (1 << intel_encoder->hpd_pin)) {
>  			DRM_DEBUG_KMS("Connector %s (pin %i) received hotplug
> event.\n",
>  				      connector->name, intel_encoder-
> >hpd_pin);
> -			if (intel_encoder->hot_plug)
> -				intel_encoder->hot_plug(intel_encoder);
> -			if (intel_hpd_irq_event(dev, connector))
> -				changed = true;
> +
> +			changed |= intel_encoder->hotplug(intel_encoder,
> +							  intel_connector);
>  		}
>  	}
>  	drm_connector_list_iter_end(&conn_iter);
> diff --git a/drivers/gpu/drm/i915/intel_sdvo.c
> b/drivers/gpu/drm/i915/intel_sdvo.c
> index 2b8764897d68..5b1ad42ec446 100644
> --- a/drivers/gpu/drm/i915/intel_sdvo.c
> +++ b/drivers/gpu/drm/i915/intel_sdvo.c
> @@ -1692,7 +1692,15 @@ static void intel_sdvo_enable_hotplug(struct
> intel_encoder *encoder)
>  	struct intel_sdvo *intel_sdvo = to_sdvo(encoder);
>  
>  	intel_sdvo_write_cmd(intel_sdvo, SDVO_CMD_SET_ACTIVE_HOT_PLUG,
> -			&intel_sdvo->hotplug_active, 2);
> +			     &intel_sdvo->hotplug_active, 2);
> +}
> +
> +static bool intel_sdvo_hotplug(struct intel_encoder *encoder,
> +			       struct intel_connector *connector)
> +{
> +	intel_sdvo_enable_hotplug(encoder);
> +
> +	return intel_encoder_hotplug(encoder, connector);
>  }
>  
>  static bool
> @@ -2496,7 +2504,7 @@ intel_sdvo_dvi_init(struct intel_sdvo *intel_sdvo, int
> device)
>  		/* Some SDVO devices have one-shot hotplug interrupts.
>  		 * Ensure that they get re-enabled when an interrupt happens.
>  		 */
> -		intel_encoder->hot_plug = intel_sdvo_enable_hotplug;
> +		intel_encoder->hotplug = intel_sdvo_hotplug;
>  		intel_sdvo_enable_hotplug(intel_encoder);
>  	} else {
>  		intel_connector->polled = DRM_CONNECTOR_POLL_CONNECT |
> DRM_CONNECTOR_POLL_DISCONNECT;
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
  2018-01-30 23:16   ` Lyude Paul
@ 2018-01-31 13:27     ` Ville Syrjälä
  2018-02-28  7:17       ` Manasi Navare
  0 siblings, 1 reply; 23+ messages in thread
From: Ville Syrjälä @ 2018-01-31 13:27 UTC (permalink / raw)
  To: Lyude Paul; +Cc: intel-gfx

On Tue, Jan 30, 2018 at 06:16:59PM -0500, Lyude Paul wrote:
> On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > Doing link retraining from the short pulse handler is problematic since
> > that might introduce deadlocks with MST sideband processing. Currently
> > we don't retrain MST links from this code, but we want to change that.
> > So better to move the entire thing to the hotplug work. We can utilize
> > the new encoder->hotplug() hook for this.
> > 
> > The only thing we leave in the short pulse handler is the link status
> > check. That one still depends on the link parameters stored under
> > intel_dp, so no locking around that but races should be mostly harmless
> > as the actual retraining code will recheck the link state if we
> > end up there by mistake.
> > 
> > v2: Rebase due to ->post_hotplug() now being just ->hotplug()
> >     Check the connector type to figure out if we should do
> >     the HDMI thing or the DP think for DDI
> > 
> > Cc: Manasi Navare <manasi.d.navare@intel.com>
> > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > ---
> >  drivers/gpu/drm/i915/intel_ddi.c |  10 +-
> >  drivers/gpu/drm/i915/intel_dp.c  | 196 ++++++++++++++++++++++--------------
> > ---
> >  drivers/gpu/drm/i915/intel_drv.h |   2 +
> >  3 files changed, 120 insertions(+), 88 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > b/drivers/gpu/drm/i915/intel_ddi.c
> > index 25793bdc692f..5f3d58f1ae6e 100644
> > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > @@ -2880,7 +2880,10 @@ static bool intel_ddi_hotplug(struct intel_encoder
> > *encoder,
> >  	drm_modeset_acquire_init(&ctx, 0);
> >  
> >  	for (;;) {
> > -		ret = intel_hdmi_reset_link(encoder, &ctx);
> > +		if (connector->base.connector_type ==
> > DRM_MODE_CONNECTOR_HDMIA)
> > +			ret = intel_hdmi_reset_link(encoder, &ctx);
> > +		else
> > +			ret = intel_dp_retrain_link(encoder, &ctx);
> >  
> >  		if (ret == -EDEADLK) {
> >  			drm_modeset_backoff(&ctx);
> > @@ -3007,10 +3010,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv,
> > enum port port)
> >  	drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
> >  			 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
> >  
> > -	if (init_hdmi)
> > -		intel_encoder->hotplug = intel_ddi_hotplug;
> > -	else
> > -		intel_encoder->hotplug = intel_encoder_hotplug;
> > +	intel_encoder->hotplug = intel_ddi_hotplug;
> >  	intel_encoder->compute_output_type = intel_ddi_compute_output_type;
> >  	intel_encoder->compute_config = intel_ddi_compute_config;
> >  	intel_encoder->enable = intel_enable_ddi;
> > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > index 6bbf14410c2a..152016e09a11 100644
> > --- a/drivers/gpu/drm/i915/intel_dp.c
> > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > @@ -4275,12 +4275,83 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
> >  	return -EINVAL;
> >  }
> >  
> > -static void
> > -intel_dp_retrain_link(struct intel_dp *intel_dp)
> > +static bool
> > +intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
> > +{
> > +	u8 link_status[DP_LINK_STATUS_SIZE];
> > +
> > +	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > +		DRM_ERROR("Failed to get link status\n");
> > +		return false;
> > +	}
> > +
> > +	/*
> > +	 * Validate the cached values of intel_dp->link_rate and
> > +	 * intel_dp->lane_count before attempting to retrain.
> > +	 */
> > +	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
> > +					intel_dp->lane_count))
> > +		return false;
> > +
> > +	/* Retrain if Channel EQ or CR not ok */
> > +	return !drm_dp_channel_eq_ok(link_status, intel_dp->lane_count);
> > +}
> > +
> > +/*
> > + * If display is now connected check links status,
> > + * there has been known issues of link loss triggering
> > + * long pulse.
> > + *
> > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > + * weird HPD ping pong during modesets. So we can apparently
> > + * end up with HPD going low during a modeset, and then
> > + * going back up soon after. And once that happens we must
> > + * retrain the link to get a picture. That's in case no
> > + * userspace component reacted to intermittent HPD dip.
> > + */
> > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > +			  struct drm_modeset_acquire_ctx *ctx)
> >  {
> > -	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
> >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > -	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
> > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > +	struct intel_connector *connector = intel_dp->attached_connector;
> > +	struct drm_connector_state *conn_state;
> > +	struct intel_crtc_state *crtc_state;
> > +	struct intel_crtc *crtc;
> > +	int ret;
> > +
> > +	/* FIXME handle the MST connectors as well */
> > +
> > +	if (!connector || connector->base.status !=
> > connector_status_connected)
> > +		return 0;
> > +
> > +	ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
> > ctx);
> > +	if (ret)
> > +		return ret;
> > +
> > +	conn_state = connector->base.state;
> > +
> > +	crtc = to_intel_crtc(conn_state->crtc);
> > +	if (!crtc)
> > +		return 0;
> > +
> > +	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
> > +	if (ret)
> > +		return ret;
> > +
> > +	crtc_state = to_intel_crtc_state(crtc->base.state);
> > +
> > +	WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
> > +
> > +	if (!crtc_state->base.active)
> > +		return 0;
> > +
> > +	if (conn_state->commit &&
> > +	    !try_wait_for_completion(&conn_state->commit->hw_done))
> > +		return 0;
> > +
> > +	if (!intel_dp_needs_link_retrain(intel_dp))
> > +		return 0;
> NAK, this definitely won't work for implementing MST retraining. There's some
> pretty huge differences with how retraining needs to be handled on SST vs. MST.
> An example with some normal SST sink vs. what happens on my caldigit TS3
> 
> SST:
>     1. commit modeset, everything is OK
>     2. something happens, sink sends shortpulse and changes link status registers
>     in dpcd
>     3. Source receives short pulse, tries retraining five times
>     4. if this succeeds:
>         5. we're done here
>     6. if this fails:
>         7. mark link status as bad
>         8. get fallback parameters
>         9. hotplug event
> 
> MST (i915 doesn't do this yet, but this is generally how it needs to be
> handled):
>     1. commit modeset, everything is OK
>     2. something happens (in my case, the MST hub discovers it had the wrong max
>     link rate/lane count), sink sends ESI indicating channel EQ has failed
>     3. retraining commences with five retries.
>     4. if this succeeds:
>        5. continue
>     6. if this fails (I actually haven't seen this once yet)
>         7. mark link status as bad on all downstream connectors
>         8. get fallback parameters
>         9. hotplug event
>     10. the retrain didn't actually work (despite what the SST link status
>     registers told us). go back to step 3 five more times
>     11. if this fails:
>         12. mark link status as bad on all downstream connectors
>         13. get fallback parameters
>         14. hotplug event
> 
> simply put: we really should keep the "do we need to retrain?" logic out of the
> actual retraining helpers so that SST/MST codepaths can do their own checks to
> figure this out.

No, we need it since we want to check it *after* any modeset has
finished. With MST I think what we'll want to do is find all the pipes
affected by the link failure, lock them, and wait until they're done
with their modesets, then we check the link state. If it's bad we
proceed to retrain the link.

So basically just walking over the MST encoders in addition to the
SST encoder, and repeating most of the steps in this code for each.
Hence the the MST FIXME I left in there ;)

> 
> >  
> >  	/* Suppress underruns caused by re-training */
> >  	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
> > @@ -4298,51 +4369,49 @@ intel_dp_retrain_link(struct intel_dp *intel_dp)
> >  	if (crtc->config->has_pch_encoder)
> >  		intel_set_pch_fifo_underrun_reporting(dev_priv,
> >  						      intel_crtc_pch_transcod
> > er(crtc), true);
> > +
> > +	return 0;
> >  }
> >  
> > -static void
> > -intel_dp_check_link_status(struct intel_dp *intel_dp)
> > +/*
> > + * If display is now connected check links status,
> > + * there has been known issues of link loss triggering
> > + * long pulse.
> > + *
> > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > + * weird HPD ping pong during modesets. So we can apparently
> > + * end up with HPD going low during a modeset, and then
> > + * going back up soon after. And once that happens we must
> > + * retrain the link to get a picture. That's in case no
> > + * userspace component reacted to intermittent HPD dip.
> > + */
> > +static bool intel_dp_hotplug(struct intel_encoder *encoder,
> > +			     struct intel_connector *connector)
> >  {
> > -	struct drm_i915_private *dev_priv =
> > to_i915(intel_dp_to_dev(intel_dp));
> > -	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)-
> > >base;
> > -	struct drm_connector_state *conn_state =
> > -		intel_dp->attached_connector->base.state;
> > -	u8 link_status[DP_LINK_STATUS_SIZE];
> > -
> > -	WARN_ON(!drm_modeset_is_locked(&dev_priv-
> > >drm.mode_config.connection_mutex));
> > -
> > -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > -		DRM_ERROR("Failed to get link status\n");
> > -		return;
> > -	}
> > +	struct drm_modeset_acquire_ctx ctx;
> > +	bool changed;
> > +	int ret;
> >  
> > -	if (!conn_state->crtc)
> > -		return;
> > +	changed = intel_encoder_hotplug(encoder, connector);
> >  
> > -	WARN_ON(!drm_modeset_is_locked(&conn_state->crtc->mutex));
> > +	drm_modeset_acquire_init(&ctx, 0);
> >  
> > -	if (!conn_state->crtc->state->active)
> > -		return;
> > +	for (;;) {
> > +		ret = intel_dp_retrain_link(encoder, &ctx);
> >  
> > -	if (conn_state->commit &&
> > -	    !try_wait_for_completion(&conn_state->commit->hw_done))
> > -		return;
> > +		if (ret == -EDEADLK) {
> > +			drm_modeset_backoff(&ctx);
> > +			continue;
> > +		}
> >  
> > -	/*
> > -	 * Validate the cached values of intel_dp->link_rate and
> > -	 * intel_dp->lane_count before attempting to retrain.
> > -	 */
> > -	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
> > -					intel_dp->lane_count))
> > -		return;
> > +		break;
> > +	}
> >  
> > -	/* Retrain if Channel EQ or CR not ok */
> > -	if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
> > -		DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
> > -			      intel_encoder->base.name);
> > +	drm_modeset_drop_locks(&ctx);
> > +	drm_modeset_acquire_fini(&ctx);
> > +	WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
> >  
> > -		intel_dp_retrain_link(intel_dp);
> > -	}
> > +	return changed;
> >  }
> >  
> >  /*
> > @@ -4400,7 +4469,9 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
> >  			DRM_DEBUG_DRIVER("CP or sink specific irq
> > unhandled\n");
> >  	}
> >  
> > -	intel_dp_check_link_status(intel_dp);
> > +	/* defer to the hotplug work for link retraining if needed */
> > +	if (intel_dp_needs_link_retrain(intel_dp))
> > +		return false;
> >  
> >  	if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
> >  		DRM_DEBUG_KMS("Link Training Compliance Test requested\n");
> > @@ -4785,20 +4856,6 @@ intel_dp_long_pulse(struct intel_connector *connector)
> >  		 */
> >  		status = connector_status_disconnected;
> >  		goto out;
> > -	} else {
> > -		/*
> > -		 * If display is now connected check links status,
> > -		 * there has been known issues of link loss triggerring
> > -		 * long pulse.
> > -		 *
> > -		 * Some sinks (eg. ASUS PB287Q) seem to perform some
> > -		 * weird HPD ping pong during modesets. So we can apparently
> > -		 * end up with HPD going low during a modeset, and then
> > -		 * going back up soon after. And once that happens we must
> > -		 * retrain the link to get a picture. That's in case no
> > -		 * userspace component reacted to intermittent HPD dip.
> > -		 */
> > -		intel_dp_check_link_status(intel_dp);
> >  	}
> >  
> >  	/*
> > @@ -5340,37 +5397,10 @@ intel_dp_hpd_pulse(struct intel_digital_port
> > *intel_dig_port, bool long_hpd)
> >  	}
> >  
> >  	if (!intel_dp->is_mst) {
> > -		struct drm_modeset_acquire_ctx ctx;
> > -		struct drm_connector *connector = &intel_dp-
> > >attached_connector->base;
> > -		struct drm_crtc *crtc;
> > -		int iret;
> > -		bool handled = false;
> > -
> > -		drm_modeset_acquire_init(&ctx, 0);
> > -retry:
> > -		iret = drm_modeset_lock(&dev_priv-
> > >drm.mode_config.connection_mutex, &ctx);
> > -		if (iret)
> > -			goto err;
> > -
> > -		crtc = connector->state->crtc;
> > -		if (crtc) {
> > -			iret = drm_modeset_lock(&crtc->mutex, &ctx);
> > -			if (iret)
> > -				goto err;
> > -		}
> > +		bool handled;
> >  
> >  		handled = intel_dp_short_pulse(intel_dp);
> >  
> > -err:
> > -		if (iret == -EDEADLK) {
> > -			drm_modeset_backoff(&ctx);
> > -			goto retry;
> > -		}
> > -
> > -		drm_modeset_drop_locks(&ctx);
> > -		drm_modeset_acquire_fini(&ctx);
> > -		WARN(iret, "Acquiring modeset locks failed with %i\n", iret);
> > -
> >  		/* Short pulse can signify loss of hdcp authentication */
> >  		intel_hdcp_check_link(intel_dp->attached_connector);
> >  
> > @@ -6400,7 +6430,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
> >  			     "DP %c", port_name(port)))
> >  		goto err_encoder_init;
> >  
> > -	intel_encoder->hotplug = intel_encoder_hotplug;
> > +	intel_encoder->hotplug = intel_dp_hotplug;
> >  	intel_encoder->compute_config = intel_dp_compute_config;
> >  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
> >  	intel_encoder->get_config = intel_dp_get_config;
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > b/drivers/gpu/drm/i915/intel_drv.h
> > index 5ea1dc3f63bf..ddf28a442cd7 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1611,6 +1611,8 @@ int intel_dp_get_link_train_fallback_values(struct
> > intel_dp *intel_dp,
> >  					    int link_rate, uint8_t
> > lane_count);
> >  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > +			  struct drm_modeset_acquire_ctx *ctx);
> >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> >  void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);

-- 
Ville Syrjälä
Intel OTC
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
  2018-01-31 13:27     ` Ville Syrjälä
@ 2018-02-28  7:17       ` Manasi Navare
  2018-02-28 19:07         ` Lyude Paul
  0 siblings, 1 reply; 23+ messages in thread
From: Manasi Navare @ 2018-02-28  7:17 UTC (permalink / raw)
  To: Ville Syrjälä; +Cc: intel-gfx

Ville,  thanks for the patch and
Sorry for not being able to review this earlier.
Please find some comments below:

On Wed, Jan 31, 2018 at 03:27:10PM +0200, Ville Syrjälä wrote:
> On Tue, Jan 30, 2018 at 06:16:59PM -0500, Lyude Paul wrote:
> > On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > 
> > > Doing link retraining from the short pulse handler is problematic since
> > > that might introduce deadlocks with MST sideband processing. Currently
> > > we don't retrain MST links from this code, but we want to change that.
> > > So better to move the entire thing to the hotplug work. We can utilize
> > > the new encoder->hotplug() hook for this.
> > > 
> > > The only thing we leave in the short pulse handler is the link status
> > > check. That one still depends on the link parameters stored under
> > > intel_dp, so no locking around that but races should be mostly harmless
> > > as the actual retraining code will recheck the link state if we
> > > end up there by mistake.
> > > 
> > > v2: Rebase due to ->post_hotplug() now being just ->hotplug()
> > >     Check the connector type to figure out if we should do
> > >     the HDMI thing or the DP think for DDI
> > > 
> > > Cc: Manasi Navare <manasi.d.navare@intel.com>
> > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > ---
> > >  drivers/gpu/drm/i915/intel_ddi.c |  10 +-
> > >  drivers/gpu/drm/i915/intel_dp.c  | 196 ++++++++++++++++++++++--------------
> > > ---
> > >  drivers/gpu/drm/i915/intel_drv.h |   2 +
> > >  3 files changed, 120 insertions(+), 88 deletions(-)
> > > 
> > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > > b/drivers/gpu/drm/i915/intel_ddi.c
> > > index 25793bdc692f..5f3d58f1ae6e 100644
> > > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > > @@ -2880,7 +2880,10 @@ static bool intel_ddi_hotplug(struct intel_encoder
> > > *encoder,
> > >  	drm_modeset_acquire_init(&ctx, 0);
> > >  
> > >  	for (;;) {
> > > -		ret = intel_hdmi_reset_link(encoder, &ctx);
> > > +		if (connector->base.connector_type ==
> > > DRM_MODE_CONNECTOR_HDMIA)
> > > +			ret = intel_hdmi_reset_link(encoder, &ctx);
> > > +		else
> > > +			ret = intel_dp_retrain_link(encoder, &ctx);
> > >  
> > >  		if (ret == -EDEADLK) {
> > >  			drm_modeset_backoff(&ctx);
> > > @@ -3007,10 +3010,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv,
> > > enum port port)
> > >  	drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
> > >  			 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
> > >  
> > > -	if (init_hdmi)
> > > -		intel_encoder->hotplug = intel_ddi_hotplug;
> > > -	else
> > > -		intel_encoder->hotplug = intel_encoder_hotplug;
> > > +	intel_encoder->hotplug = intel_ddi_hotplug;
> > >  	intel_encoder->compute_output_type = intel_ddi_compute_output_type;
> > >  	intel_encoder->compute_config = intel_ddi_compute_config;
> > >  	intel_encoder->enable = intel_enable_ddi;
> > > diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> > > index 6bbf14410c2a..152016e09a11 100644
> > > --- a/drivers/gpu/drm/i915/intel_dp.c
> > > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > > @@ -4275,12 +4275,83 @@ intel_dp_check_mst_status(struct intel_dp *intel_dp)
> > >  	return -EINVAL;
> > >  }
> > >  
> > > -static void
> > > -intel_dp_retrain_link(struct intel_dp *intel_dp)
> > > +static bool
> > > +intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
> > > +{
> > > +	u8 link_status[DP_LINK_STATUS_SIZE];
> > > +
> > > +	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > > +		DRM_ERROR("Failed to get link status\n");
> > > +		return false;
> > > +	}
> > > +
> > > +	/*
> > > +	 * Validate the cached values of intel_dp->link_rate and
> > > +	 * intel_dp->lane_count before attempting to retrain.
> > > +	 */
> > > +	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
> > > +					intel_dp->lane_count))
> > > +		return false;
> > > +
> > > +	/* Retrain if Channel EQ or CR not ok */
> > > +	return !drm_dp_channel_eq_ok(link_status, intel_dp->lane_count);
> > > +}
> > > +
> > > +/*
> > > + * If display is now connected check links status,
> > > + * there has been known issues of link loss triggering
> > > + * long pulse.
> > > + *
> > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > + * weird HPD ping pong during modesets. So we can apparently
> > > + * end up with HPD going low during a modeset, and then
> > > + * going back up soon after. And once that happens we must
> > > + * retrain the link to get a picture. That's in case no
> > > + * userspace component reacted to intermittent HPD dip.
> > > + */
> > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > +			  struct drm_modeset_acquire_ctx *ctx)
> > >  {
> > > -	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
> > >  	struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
> > > -	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
> > > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > > +	struct intel_connector *connector = intel_dp->attached_connector;
> > > +	struct drm_connector_state *conn_state;
> > > +	struct intel_crtc_state *crtc_state;
> > > +	struct intel_crtc *crtc;
> > > +	int ret;
> > > +
> > > +	/* FIXME handle the MST connectors as well */
> > > +
> > > +	if (!connector || connector->base.status !=
> > > connector_status_connected)
> > > +		return 0;
> > > +
> > > +	ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
> > > ctx);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	conn_state = connector->base.state;
> > > +
> > > +	crtc = to_intel_crtc(conn_state->crtc);
> > > +	if (!crtc)
> > > +		return 0;
> > > +
> > > +	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
> > > +	if (ret)
> > > +		return ret;
> > > +
> > > +	crtc_state = to_intel_crtc_state(crtc->base.state);
> > > +
> > > +	WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
> > > +
> > > +	if (!crtc_state->base.active)
> > > +		return 0;
> > > +
> > > +	if (conn_state->commit &&
> > > +	    !try_wait_for_completion(&conn_state->commit->hw_done))
> > > +		return 0;
> > > +
> > > +	if (!intel_dp_needs_link_retrain(intel_dp))
> > > +		return 0;
> > NAK, this definitely won't work for implementing MST retraining. There's some
> > pretty huge differences with how retraining needs to be handled on SST vs. MST.
> > An example with some normal SST sink vs. what happens on my caldigit TS3
> > 
> > SST:
> >     1. commit modeset, everything is OK
> >     2. something happens, sink sends shortpulse and changes link status registers
> >     in dpcd
> >     3. Source receives short pulse, tries retraining five times
> >     4. if this succeeds:
> >         5. we're done here
> >     6. if this fails:
> >         7. mark link status as bad
> >         8. get fallback parameters
> >         9. hotplug event
> > 
> > MST (i915 doesn't do this yet, but this is generally how it needs to be
> > handled):
> >     1. commit modeset, everything is OK
> >     2. something happens (in my case, the MST hub discovers it had the wrong max
> >     link rate/lane count), sink sends ESI indicating channel EQ has failed
> >     3. retraining commences with five retries.
> >     4. if this succeeds:
> >        5. continue
> >     6. if this fails (I actually haven't seen this once yet)
> >         7. mark link status as bad on all downstream connectors
> >         8. get fallback parameters
> >         9. hotplug event
> >     10. the retrain didn't actually work (despite what the SST link status
> >     registers told us). go back to step 3 five more times
> >     11. if this fails:
> >         12. mark link status as bad on all downstream connectors
> >         13. get fallback parameters
> >         14. hotplug event
> > 
> > simply put: we really should keep the "do we need to retrain?" logic out of the
> > actual retraining helpers so that SST/MST codepaths can do their own checks to
> > figure this out.
> 
> No, we need it since we want to check it *after* any modeset has
> finished. With MST I think what we'll want to do is find all the pipes
> affected by the link failure, lock them, and wait until they're done
> with their modesets, then we check the link state. If it's bad we
> proceed to retrain the link.
> 
> So basically just walking over the MST encoders in addition to the
> SST encoder, and repeating most of the steps in this code for each.
> Hence the the MST FIXME I left in there ;)
> 

Lyude,

I agree with Ville here, can we add the MST retrain required check from
within the intel_dp_retrain_link()? So for now the FIXME should be left there
and MST retraining check can be added from your patches.

Manasi

> > 
> > >  
> > >  	/* Suppress underruns caused by re-training */
> > >  	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
> > > @@ -4298,51 +4369,49 @@ intel_dp_retrain_link(struct intel_dp *intel_dp)
> > >  	if (crtc->config->has_pch_encoder)
> > >  		intel_set_pch_fifo_underrun_reporting(dev_priv,
> > >  						      intel_crtc_pch_transcod
> > > er(crtc), true);
> > > +
> > > +	return 0;
> > >  }
> > >  
> > > -static void
> > > -intel_dp_check_link_status(struct intel_dp *intel_dp)
> > > +/*
> > > + * If display is now connected check links status,
> > > + * there has been known issues of link loss triggering
> > > + * long pulse.
> > > + *
> > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > + * weird HPD ping pong during modesets. So we can apparently
> > > + * end up with HPD going low during a modeset, and then
> > > + * going back up soon after. And once that happens we must
> > > + * retrain the link to get a picture. That's in case no
> > > + * userspace component reacted to intermittent HPD dip.
> > > + */
> > > +static bool intel_dp_hotplug(struct intel_encoder *encoder,
> > > +			     struct intel_connector *connector)
> > >  {
> > > -	struct drm_i915_private *dev_priv =
> > > to_i915(intel_dp_to_dev(intel_dp));
> > > -	struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)-
> > > >base;
> > > -	struct drm_connector_state *conn_state =
> > > -		intel_dp->attached_connector->base.state;
> > > -	u8 link_status[DP_LINK_STATUS_SIZE];
> > > -
> > > -	WARN_ON(!drm_modeset_is_locked(&dev_priv-
> > > >drm.mode_config.connection_mutex));
> > > -
> > > -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > > -		DRM_ERROR("Failed to get link status\n");
> > > -		return;
> > > -	}
> > > +	struct drm_modeset_acquire_ctx ctx;
> > > +	bool changed;
> > > +	int ret;
> > >  
> > > -	if (!conn_state->crtc)
> > > -		return;
> > > +	changed = intel_encoder_hotplug(encoder, connector);
> > >  
> > > -	WARN_ON(!drm_modeset_is_locked(&conn_state->crtc->mutex));
> > > +	drm_modeset_acquire_init(&ctx, 0);
> > >  
> > > -	if (!conn_state->crtc->state->active)
> > > -		return;
> > > +	for (;;) {

Here if this is getting executed due to hpd ping pong during the modeset
and that modeset is already happening at a link fallback parameter then
while we call retrain link, we should also validate the link parameters
so that it doesnt try to retrain with stale values.

I think we need to call intel_dp_link_params_valid() before retrain.

> > > +		ret = intel_dp_retrain_link(encoder, &ctx);
> > >  
> > > -	if (conn_state->commit &&
> > > -	    !try_wait_for_completion(&conn_state->commit->hw_done))
> > > -		return;
> > > +		if (ret == -EDEADLK) {
> > > +			drm_modeset_backoff(&ctx);
> > > +			continue;
> > > +		}
> > >  
> > > -	/*
> > > -	 * Validate the cached values of intel_dp->link_rate and
> > > -	 * intel_dp->lane_count before attempting to retrain.
> > > -	 */
> > > -	if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
> > > -					intel_dp->lane_count))
> > > -		return;
> > > +		break;
> > > +	}
> > >  
> > > -	/* Retrain if Channel EQ or CR not ok */
> > > -	if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) {
> > > -		DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
> > > -			      intel_encoder->base.name);
> > > +	drm_modeset_drop_locks(&ctx);
> > > +	drm_modeset_acquire_fini(&ctx);
> > > +	WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
> > >  
> > > -		intel_dp_retrain_link(intel_dp);
> > > -	}
> > > +	return changed;
> > >  }
> > >  
> > >  /*
> > > @@ -4400,7 +4469,9 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
> > >  			DRM_DEBUG_DRIVER("CP or sink specific irq
> > > unhandled\n");
> > >  	}
> > >  
> > > -	intel_dp_check_link_status(intel_dp);
> > > +	/* defer to the hotplug work for link retraining if needed */
> > > +	if (intel_dp_needs_link_retrain(intel_dp))
> > > +		return false;
> > >  
> > >  	if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
> > >  		DRM_DEBUG_KMS("Link Training Compliance Test requested\n");
> > > @@ -4785,20 +4856,6 @@ intel_dp_long_pulse(struct intel_connector *connector)
> > >  		 */
> > >  		status = connector_status_disconnected;
> > >  		goto out;
> > > -	} else {
> > > -		/*
> > > -		 * If display is now connected check links status,
> > > -		 * there has been known issues of link loss triggerring
> > > -		 * long pulse.
> > > -		 *
> > > -		 * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > -		 * weird HPD ping pong during modesets. So we can apparently
> > > -		 * end up with HPD going low during a modeset, and then
> > > -		 * going back up soon after. And once that happens we must
> > > -		 * retrain the link to get a picture. That's in case no
> > > -		 * userspace component reacted to intermittent HPD dip.
> > > -		 */
> > > -		intel_dp_check_link_status(intel_dp);
> > >  	}
> > >  
> > >  	/*
> > > @@ -5340,37 +5397,10 @@ intel_dp_hpd_pulse(struct intel_digital_port
> > > *intel_dig_port, bool long_hpd)
> > >  	}
> > >  
> > >  	if (!intel_dp->is_mst) {
> > > -		struct drm_modeset_acquire_ctx ctx;
> > > -		struct drm_connector *connector = &intel_dp-
> > > >attached_connector->base;
> > > -		struct drm_crtc *crtc;
> > > -		int iret;
> > > -		bool handled = false;
> > > -
> > > -		drm_modeset_acquire_init(&ctx, 0);
> > > -retry:
> > > -		iret = drm_modeset_lock(&dev_priv-
> > > >drm.mode_config.connection_mutex, &ctx);
> > > -		if (iret)
> > > -			goto err;
> > > -
> > > -		crtc = connector->state->crtc;
> > > -		if (crtc) {
> > > -			iret = drm_modeset_lock(&crtc->mutex, &ctx);
> > > -			if (iret)
> > > -				goto err;
> > > -		}
> > > +		bool handled;
> > >  
> > >  		handled = intel_dp_short_pulse(intel_dp);
> > >  
> > > -err:
> > > -		if (iret == -EDEADLK) {
> > > -			drm_modeset_backoff(&ctx);
> > > -			goto retry;
> > > -		}
> > > -
> > > -		drm_modeset_drop_locks(&ctx);
> > > -		drm_modeset_acquire_fini(&ctx);
> > > -		WARN(iret, "Acquiring modeset locks failed with %i\n", iret);
> > > -
> > >  		/* Short pulse can signify loss of hdcp authentication */
> > >  		intel_hdcp_check_link(intel_dp->attached_connector);
> > >  
> > > @@ -6400,7 +6430,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
> > >  			     "DP %c", port_name(port)))
> > >  		goto err_encoder_init;
> > >  
> > > -	intel_encoder->hotplug = intel_encoder_hotplug;
> > > +	intel_encoder->hotplug = intel_dp_hotplug;
> > >  	intel_encoder->compute_config = intel_dp_compute_config;
> > >  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
> > >  	intel_encoder->get_config = intel_dp_get_config;
> > > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > > b/drivers/gpu/drm/i915/intel_drv.h
> > > index 5ea1dc3f63bf..ddf28a442cd7 100644
> > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > @@ -1611,6 +1611,8 @@ int intel_dp_get_link_train_fallback_values(struct
> > > intel_dp *intel_dp,
> > >  					    int link_rate, uint8_t
> > > lane_count);
> > >  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > +			  struct drm_modeset_acquire_ctx *ctx);
> > >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> > >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > >  void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
> 
> -- 
> Ville Syrjälä
> Intel OTC
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
  2018-02-28  7:17       ` Manasi Navare
@ 2018-02-28 19:07         ` Lyude Paul
  2018-02-28 19:27           ` Manasi Navare
  0 siblings, 1 reply; 23+ messages in thread
From: Lyude Paul @ 2018-02-28 19:07 UTC (permalink / raw)
  To: Manasi Navare, Ville Syrjälä; +Cc: intel-gfx


On Tue, 2018-02-27 at 23:17 -0800, Manasi Navare wrote:
> Ville,  thanks for the patch and
> Sorry for not being able to review this earlier.
> Please find some comments below:
> 
> On Wed, Jan 31, 2018 at 03:27:10PM +0200, Ville Syrjälä wrote:
> > On Tue, Jan 30, 2018 at 06:16:59PM -0500, Lyude Paul wrote:
> > > On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > 
> > > > Doing link retraining from the short pulse handler is problematic
> > > > since
> > > > that might introduce deadlocks with MST sideband processing. Currently
> > > > we don't retrain MST links from this code, but we want to change that.
> > > > So better to move the entire thing to the hotplug work. We can utilize
> > > > the new encoder->hotplug() hook for this.
> > > > 
> > > > The only thing we leave in the short pulse handler is the link status
> > > > check. That one still depends on the link parameters stored under
> > > > intel_dp, so no locking around that but races should be mostly
> > > > harmless
> > > > as the actual retraining code will recheck the link state if we
> > > > end up there by mistake.
> > > > 
> > > > v2: Rebase due to ->post_hotplug() now being just ->hotplug()
> > > >     Check the connector type to figure out if we should do
> > > >     the HDMI thing or the DP think for DDI
> > > > 
> > > > Cc: Manasi Navare <manasi.d.navare@intel.com>
> > > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > ---
> > > >  drivers/gpu/drm/i915/intel_ddi.c |  10 +-
> > > >  drivers/gpu/drm/i915/intel_dp.c  | 196 ++++++++++++++++++++++------
> > > > --------
> > > > ---
> > > >  drivers/gpu/drm/i915/intel_drv.h |   2 +
> > > >  3 files changed, 120 insertions(+), 88 deletions(-)
> > > > 
> > > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > > > b/drivers/gpu/drm/i915/intel_ddi.c
> > > > index 25793bdc692f..5f3d58f1ae6e 100644
> > > > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > > > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > > > @@ -2880,7 +2880,10 @@ static bool intel_ddi_hotplug(struct
> > > > intel_encoder
> > > > *encoder,
> > > >  	drm_modeset_acquire_init(&ctx, 0);
> > > >  
> > > >  	for (;;) {
> > > > -		ret = intel_hdmi_reset_link(encoder, &ctx);
> > > > +		if (connector->base.connector_type ==
> > > > DRM_MODE_CONNECTOR_HDMIA)
> > > > +			ret = intel_hdmi_reset_link(encoder, &ctx);
> > > > +		else
> > > > +			ret = intel_dp_retrain_link(encoder, &ctx);
> > > >  
> > > >  		if (ret == -EDEADLK) {
> > > >  			drm_modeset_backoff(&ctx);
> > > > @@ -3007,10 +3010,7 @@ void intel_ddi_init(struct drm_i915_private
> > > > *dev_priv,
> > > > enum port port)
> > > >  	drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
> > > >  			 DRM_MODE_ENCODER_TMDS, "DDI %c",
> > > > port_name(port));
> > > >  
> > > > -	if (init_hdmi)
> > > > -		intel_encoder->hotplug = intel_ddi_hotplug;
> > > > -	else
> > > > -		intel_encoder->hotplug = intel_encoder_hotplug;
> > > > +	intel_encoder->hotplug = intel_ddi_hotplug;
> > > >  	intel_encoder->compute_output_type =
> > > > intel_ddi_compute_output_type;
> > > >  	intel_encoder->compute_config = intel_ddi_compute_config;
> > > >  	intel_encoder->enable = intel_enable_ddi;
> > > > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > > > b/drivers/gpu/drm/i915/intel_dp.c
> > > > index 6bbf14410c2a..152016e09a11 100644
> > > > --- a/drivers/gpu/drm/i915/intel_dp.c
> > > > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > > > @@ -4275,12 +4275,83 @@ intel_dp_check_mst_status(struct intel_dp
> > > > *intel_dp)
> > > >  	return -EINVAL;
> > > >  }
> > > >  
> > > > -static void
> > > > -intel_dp_retrain_link(struct intel_dp *intel_dp)
> > > > +static bool
> > > > +intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
> > > > +{
> > > > +	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > +
> > > > +	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > > > +		DRM_ERROR("Failed to get link status\n");
> > > > +		return false;
> > > > +	}
> > > > +
> > > > +	/*
> > > > +	 * Validate the cached values of intel_dp->link_rate and
> > > > +	 * intel_dp->lane_count before attempting to retrain.
> > > > +	 */
> > > > +	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > >link_rate,
> > > > +					intel_dp->lane_count))
> > > > +		return false;
> > > > +
> > > > +	/* Retrain if Channel EQ or CR not ok */
> > > > +	return !drm_dp_channel_eq_ok(link_status, intel_dp-
> > > > >lane_count);
> > > > +}
> > > > +
> > > > +/*
> > > > + * If display is now connected check links status,
> > > > + * there has been known issues of link loss triggering
> > > > + * long pulse.
> > > > + *
> > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > + * end up with HPD going low during a modeset, and then
> > > > + * going back up soon after. And once that happens we must
> > > > + * retrain the link to get a picture. That's in case no
> > > > + * userspace component reacted to intermittent HPD dip.
> > > > + */
> > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > +			  struct drm_modeset_acquire_ctx *ctx)
> > > >  {
> > > > -	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)-
> > > > >base;
> > > >  	struct drm_i915_private *dev_priv = to_i915(encoder-
> > > > >base.dev);
> > > > -	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
> > > > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > > > +	struct intel_connector *connector = intel_dp-
> > > > >attached_connector;
> > > > +	struct drm_connector_state *conn_state;
> > > > +	struct intel_crtc_state *crtc_state;
> > > > +	struct intel_crtc *crtc;
> > > > +	int ret;
> > > > +
> > > > +	/* FIXME handle the MST connectors as well */
> > > > +
> > > > +	if (!connector || connector->base.status !=
> > > > connector_status_connected)
> > > > +		return 0;
> > > > +
> > > > +	ret = drm_modeset_lock(&dev_priv-
> > > > >drm.mode_config.connection_mutex,
> > > > ctx);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	conn_state = connector->base.state;
> > > > +
> > > > +	crtc = to_intel_crtc(conn_state->crtc);
> > > > +	if (!crtc)
> > > > +		return 0;
> > > > +
> > > > +	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
> > > > +	if (ret)
> > > > +		return ret;
> > > > +
> > > > +	crtc_state = to_intel_crtc_state(crtc->base.state);
> > > > +
> > > > +	WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
> > > > +
> > > > +	if (!crtc_state->base.active)
> > > > +		return 0;
> > > > +
> > > > +	if (conn_state->commit &&
> > > > +	    !try_wait_for_completion(&conn_state->commit->hw_done))
> > > > +		return 0;
> > > > +
> > > > +	if (!intel_dp_needs_link_retrain(intel_dp))
> > > > +		return 0;
> > > 
> > > NAK, this definitely won't work for implementing MST retraining. There's
> > > some
> > > pretty huge differences with how retraining needs to be handled on SST
> > > vs. MST.
> > > An example with some normal SST sink vs. what happens on my caldigit TS3
> > > 
> > > SST:
> > >     1. commit modeset, everything is OK
> > >     2. something happens, sink sends shortpulse and changes link status
> > > registers
> > >     in dpcd
> > >     3. Source receives short pulse, tries retraining five times
> > >     4. if this succeeds:
> > >         5. we're done here
> > >     6. if this fails:
> > >         7. mark link status as bad
> > >         8. get fallback parameters
> > >         9. hotplug event
> > > 
> > > MST (i915 doesn't do this yet, but this is generally how it needs to be
> > > handled):
> > >     1. commit modeset, everything is OK
> > >     2. something happens (in my case, the MST hub discovers it had the
> > > wrong max
> > >     link rate/lane count), sink sends ESI indicating channel EQ has
> > > failed
> > >     3. retraining commences with five retries.
> > >     4. if this succeeds:
> > >        5. continue
> > >     6. if this fails (I actually haven't seen this once yet)
> > >         7. mark link status as bad on all downstream connectors
> > >         8. get fallback parameters
> > >         9. hotplug event
> > >     10. the retrain didn't actually work (despite what the SST link
> > > status
> > >     registers told us). go back to step 3 five more times
> > >     11. if this fails:
> > >         12. mark link status as bad on all downstream connectors
> > >         13. get fallback parameters
> > >         14. hotplug event
> > > 
> > > simply put: we really should keep the "do we need to retrain?" logic out
> > > of the
> > > actual retraining helpers so that SST/MST codepaths can do their own
> > > checks to
> > > figure this out.
> > 
> > No, we need it since we want to check it *after* any modeset has
> > finished. With MST I think what we'll want to do is find all the pipes
> > affected by the link failure, lock them, and wait until they're done
> > with their modesets, then we check the link state. If it's bad we
> > proceed to retrain the link.
> > 
> > So basically just walking over the MST encoders in addition to the
> > SST encoder, and repeating most of the steps in this code for each.
> > Hence the the MST FIXME I left in there ;)
> > 
> 
> Lyude,
> 
> I agree with Ville here, can we add the MST retrain required check from
> within the intel_dp_retrain_link()? So for now the FIXME should be left
> there
> and MST retraining check can be added from your patches.
> 
> Manasi

Yep! Sorry I probably should have reiterated this part over email since I only
mentioned it to ville directly: this part should definitely work fine, and
intel_dp_retrain_link() is actually where we handle MST retraining in the
latest version of the retraining series:

jfyi, you can find that here:
https://github.com/Lyude/linux/tree/wip/i915-mst-fallback-a4
It's almost ready for the ML, just want to get the other patches this is going
to rely on in first and fix some small concerns I've got about that series'
current implementation of handling modesets after a failed retrain sequence
> 
> > > 
> > > >  
> > > >  	/* Suppress underruns caused by re-training */
> > > >  	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe,
> > > > false);
> > > > @@ -4298,51 +4369,49 @@ intel_dp_retrain_link(struct intel_dp
> > > > *intel_dp)
> > > >  	if (crtc->config->has_pch_encoder)
> > > >  		intel_set_pch_fifo_underrun_reporting(dev_priv,
> > > >  						      intel_crtc_pch_
> > > > transcod
> > > > er(crtc), true);
> > > > +
> > > > +	return 0;
> > > >  }
> > > >  
> > > > -static void
> > > > -intel_dp_check_link_status(struct intel_dp *intel_dp)
> > > > +/*
> > > > + * If display is now connected check links status,
> > > > + * there has been known issues of link loss triggering
> > > > + * long pulse.
> > > > + *
> > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > + * end up with HPD going low during a modeset, and then
> > > > + * going back up soon after. And once that happens we must
> > > > + * retrain the link to get a picture. That's in case no
> > > > + * userspace component reacted to intermittent HPD dip.
> > > > + */
> > > > +static bool intel_dp_hotplug(struct intel_encoder *encoder,
> > > > +			     struct intel_connector *connector)
> > > >  {
> > > > -	struct drm_i915_private *dev_priv =
> > > > to_i915(intel_dp_to_dev(intel_dp));
> > > > -	struct intel_encoder *intel_encoder =
> > > > &dp_to_dig_port(intel_dp)-
> > > > > base;
> > > > 
> > > > -	struct drm_connector_state *conn_state =
> > > > -		intel_dp->attached_connector->base.state;
> > > > -	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > -
> > > > -	WARN_ON(!drm_modeset_is_locked(&dev_priv-
> > > > > drm.mode_config.connection_mutex));
> > > > 
> > > > -
> > > > -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > > > -		DRM_ERROR("Failed to get link status\n");
> > > > -		return;
> > > > -	}
> > > > +	struct drm_modeset_acquire_ctx ctx;
> > > > +	bool changed;
> > > > +	int ret;
> > > >  
> > > > -	if (!conn_state->crtc)
> > > > -		return;
> > > > +	changed = intel_encoder_hotplug(encoder, connector);
> > > >  
> > > > -	WARN_ON(!drm_modeset_is_locked(&conn_state->crtc->mutex));
> > > > +	drm_modeset_acquire_init(&ctx, 0);
> > > >  
> > > > -	if (!conn_state->crtc->state->active)
> > > > -		return;
> > > > +	for (;;) {
> 
> Here if this is getting executed due to hpd ping pong during the modeset
> and that modeset is already happening at a link fallback parameter then
> while we call retrain link, we should also validate the link parameters
> so that it doesnt try to retrain with stale values.
> 
> I think we need to call intel_dp_link_params_valid() before retrain.
> 
> > > > +		ret = intel_dp_retrain_link(encoder, &ctx);
> > > >  
> > > > -	if (conn_state->commit &&
> > > > -	    !try_wait_for_completion(&conn_state->commit->hw_done))
> > > > -		return;
> > > > +		if (ret == -EDEADLK) {
> > > > +			drm_modeset_backoff(&ctx);
> > > > +			continue;
> > > > +		}
> > > >  
> > > > -	/*
> > > > -	 * Validate the cached values of intel_dp->link_rate and
> > > > -	 * intel_dp->lane_count before attempting to retrain.
> > > > -	 */
> > > > -	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > >link_rate,
> > > > -					intel_dp->lane_count))
> > > > -		return;
> > > > +		break;
> > > > +	}
> > > >  
> > > > -	/* Retrain if Channel EQ or CR not ok */
> > > > -	if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) 
> > > > {
> > > > -		DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
> > > > -			      intel_encoder->base.name);
> > > > +	drm_modeset_drop_locks(&ctx);
> > > > +	drm_modeset_acquire_fini(&ctx);
> > > > +	WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
> > > >  
> > > > -		intel_dp_retrain_link(intel_dp);
> > > > -	}
> > > > +	return changed;
> > > >  }
> > > >  
> > > >  /*
> > > > @@ -4400,7 +4469,9 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
> > > >  			DRM_DEBUG_DRIVER("CP or sink specific irq
> > > > unhandled\n");
> > > >  	}
> > > >  
> > > > -	intel_dp_check_link_status(intel_dp);
> > > > +	/* defer to the hotplug work for link retraining if needed */
> > > > +	if (intel_dp_needs_link_retrain(intel_dp))
> > > > +		return false;
> > > >  
> > > >  	if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING)
> > > > {
> > > >  		DRM_DEBUG_KMS("Link Training Compliance Test
> > > > requested\n");
> > > > @@ -4785,20 +4856,6 @@ intel_dp_long_pulse(struct intel_connector
> > > > *connector)
> > > >  		 */
> > > >  		status = connector_status_disconnected;
> > > >  		goto out;
> > > > -	} else {
> > > > -		/*
> > > > -		 * If display is now connected check links status,
> > > > -		 * there has been known issues of link loss
> > > > triggerring
> > > > -		 * long pulse.
> > > > -		 *
> > > > -		 * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > -		 * weird HPD ping pong during modesets. So we can
> > > > apparently
> > > > -		 * end up with HPD going low during a modeset, and
> > > > then
> > > > -		 * going back up soon after. And once that happens we
> > > > must
> > > > -		 * retrain the link to get a picture. That's in case
> > > > no
> > > > -		 * userspace component reacted to intermittent HPD
> > > > dip.
> > > > -		 */
> > > > -		intel_dp_check_link_status(intel_dp);
> > > >  	}
> > > >  
> > > >  	/*
> > > > @@ -5340,37 +5397,10 @@ intel_dp_hpd_pulse(struct intel_digital_port
> > > > *intel_dig_port, bool long_hpd)
> > > >  	}
> > > >  
> > > >  	if (!intel_dp->is_mst) {
> > > > -		struct drm_modeset_acquire_ctx ctx;
> > > > -		struct drm_connector *connector = &intel_dp-
> > > > > attached_connector->base;
> > > > 
> > > > -		struct drm_crtc *crtc;
> > > > -		int iret;
> > > > -		bool handled = false;
> > > > -
> > > > -		drm_modeset_acquire_init(&ctx, 0);
> > > > -retry:
> > > > -		iret = drm_modeset_lock(&dev_priv-
> > > > > drm.mode_config.connection_mutex, &ctx);
> > > > 
> > > > -		if (iret)
> > > > -			goto err;
> > > > -
> > > > -		crtc = connector->state->crtc;
> > > > -		if (crtc) {
> > > > -			iret = drm_modeset_lock(&crtc->mutex, &ctx);
> > > > -			if (iret)
> > > > -				goto err;
> > > > -		}
> > > > +		bool handled;
> > > >  
> > > >  		handled = intel_dp_short_pulse(intel_dp);
> > > >  
> > > > -err:
> > > > -		if (iret == -EDEADLK) {
> > > > -			drm_modeset_backoff(&ctx);
> > > > -			goto retry;
> > > > -		}
> > > > -
> > > > -		drm_modeset_drop_locks(&ctx);
> > > > -		drm_modeset_acquire_fini(&ctx);
> > > > -		WARN(iret, "Acquiring modeset locks failed with
> > > > %i\n", iret);
> > > > -
> > > >  		/* Short pulse can signify loss of hdcp
> > > > authentication */
> > > >  		intel_hdcp_check_link(intel_dp->attached_connector);
> > > >  
> > > > @@ -6400,7 +6430,7 @@ bool intel_dp_init(struct drm_i915_private
> > > > *dev_priv,
> > > >  			     "DP %c", port_name(port)))
> > > >  		goto err_encoder_init;
> > > >  
> > > > -	intel_encoder->hotplug = intel_encoder_hotplug;
> > > > +	intel_encoder->hotplug = intel_dp_hotplug;
> > > >  	intel_encoder->compute_config = intel_dp_compute_config;
> > > >  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
> > > >  	intel_encoder->get_config = intel_dp_get_config;
> > > > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > > > b/drivers/gpu/drm/i915/intel_drv.h
> > > > index 5ea1dc3f63bf..ddf28a442cd7 100644
> > > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > > @@ -1611,6 +1611,8 @@ int
> > > > intel_dp_get_link_train_fallback_values(struct
> > > > intel_dp *intel_dp,
> > > >  					    int link_rate, uint8_t
> > > > lane_count);
> > > >  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > > >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > +			  struct drm_modeset_acquire_ctx *ctx);
> > > >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> > > >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > > >  void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
> > 
> > -- 
> > Ville Syrjälä
> > Intel OTC
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
-- 
Cheers,
	Lyude Paul
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
  2018-02-28 19:07         ` Lyude Paul
@ 2018-02-28 19:27           ` Manasi Navare
  2018-02-28 19:41             ` Lyude Paul
  0 siblings, 1 reply; 23+ messages in thread
From: Manasi Navare @ 2018-02-28 19:27 UTC (permalink / raw)
  To: Lyude Paul; +Cc: intel-gfx

On Wed, Feb 28, 2018 at 02:07:34PM -0500, Lyude Paul wrote:
> 
> On Tue, 2018-02-27 at 23:17 -0800, Manasi Navare wrote:
> > Ville,  thanks for the patch and
> > Sorry for not being able to review this earlier.
> > Please find some comments below:
> > 
> > On Wed, Jan 31, 2018 at 03:27:10PM +0200, Ville Syrjälä wrote:
> > > On Tue, Jan 30, 2018 at 06:16:59PM -0500, Lyude Paul wrote:
> > > > On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > 
> > > > > Doing link retraining from the short pulse handler is problematic
> > > > > since
> > > > > that might introduce deadlocks with MST sideband processing. Currently
> > > > > we don't retrain MST links from this code, but we want to change that.
> > > > > So better to move the entire thing to the hotplug work. We can utilize
> > > > > the new encoder->hotplug() hook for this.
> > > > > 
> > > > > The only thing we leave in the short pulse handler is the link status
> > > > > check. That one still depends on the link parameters stored under
> > > > > intel_dp, so no locking around that but races should be mostly
> > > > > harmless
> > > > > as the actual retraining code will recheck the link state if we
> > > > > end up there by mistake.
> > > > > 
> > > > > v2: Rebase due to ->post_hotplug() now being just ->hotplug()
> > > > >     Check the connector type to figure out if we should do
> > > > >     the HDMI thing or the DP think for DDI
> > > > > 
> > > > > Cc: Manasi Navare <manasi.d.navare@intel.com>
> > > > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > ---
> > > > >  drivers/gpu/drm/i915/intel_ddi.c |  10 +-
> > > > >  drivers/gpu/drm/i915/intel_dp.c  | 196 ++++++++++++++++++++++------
> > > > > --------
> > > > > ---
> > > > >  drivers/gpu/drm/i915/intel_drv.h |   2 +
> > > > >  3 files changed, 120 insertions(+), 88 deletions(-)
> > > > > 
> > > > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > > > > b/drivers/gpu/drm/i915/intel_ddi.c
> > > > > index 25793bdc692f..5f3d58f1ae6e 100644
> > > > > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > > > > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > > > > @@ -2880,7 +2880,10 @@ static bool intel_ddi_hotplug(struct
> > > > > intel_encoder
> > > > > *encoder,
> > > > >  	drm_modeset_acquire_init(&ctx, 0);
> > > > >  
> > > > >  	for (;;) {
> > > > > -		ret = intel_hdmi_reset_link(encoder, &ctx);
> > > > > +		if (connector->base.connector_type ==
> > > > > DRM_MODE_CONNECTOR_HDMIA)
> > > > > +			ret = intel_hdmi_reset_link(encoder, &ctx);
> > > > > +		else
> > > > > +			ret = intel_dp_retrain_link(encoder, &ctx);
> > > > >  
> > > > >  		if (ret == -EDEADLK) {
> > > > >  			drm_modeset_backoff(&ctx);
> > > > > @@ -3007,10 +3010,7 @@ void intel_ddi_init(struct drm_i915_private
> > > > > *dev_priv,
> > > > > enum port port)
> > > > >  	drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
> > > > >  			 DRM_MODE_ENCODER_TMDS, "DDI %c",
> > > > > port_name(port));
> > > > >  
> > > > > -	if (init_hdmi)
> > > > > -		intel_encoder->hotplug = intel_ddi_hotplug;
> > > > > -	else
> > > > > -		intel_encoder->hotplug = intel_encoder_hotplug;
> > > > > +	intel_encoder->hotplug = intel_ddi_hotplug;
> > > > >  	intel_encoder->compute_output_type =
> > > > > intel_ddi_compute_output_type;
> > > > >  	intel_encoder->compute_config = intel_ddi_compute_config;
> > > > >  	intel_encoder->enable = intel_enable_ddi;
> > > > > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > > > > b/drivers/gpu/drm/i915/intel_dp.c
> > > > > index 6bbf14410c2a..152016e09a11 100644
> > > > > --- a/drivers/gpu/drm/i915/intel_dp.c
> > > > > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > > > > @@ -4275,12 +4275,83 @@ intel_dp_check_mst_status(struct intel_dp
> > > > > *intel_dp)
> > > > >  	return -EINVAL;
> > > > >  }
> > > > >  
> > > > > -static void
> > > > > -intel_dp_retrain_link(struct intel_dp *intel_dp)
> > > > > +static bool
> > > > > +intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
> > > > > +{
> > > > > +	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > > +
> > > > > +	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > > > > +		DRM_ERROR("Failed to get link status\n");
> > > > > +		return false;
> > > > > +	}
> > > > > +
> > > > > +	/*
> > > > > +	 * Validate the cached values of intel_dp->link_rate and
> > > > > +	 * intel_dp->lane_count before attempting to retrain.
> > > > > +	 */
> > > > > +	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > > >link_rate,
> > > > > +					intel_dp->lane_count))
> > > > > +		return false;
> > > > > +
> > > > > +	/* Retrain if Channel EQ or CR not ok */
> > > > > +	return !drm_dp_channel_eq_ok(link_status, intel_dp-
> > > > > >lane_count);
> > > > > +}
> > > > > +
> > > > > +/*
> > > > > + * If display is now connected check links status,
> > > > > + * there has been known issues of link loss triggering
> > > > > + * long pulse.
> > > > > + *
> > > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > > + * end up with HPD going low during a modeset, and then
> > > > > + * going back up soon after. And once that happens we must
> > > > > + * retrain the link to get a picture. That's in case no
> > > > > + * userspace component reacted to intermittent HPD dip.
> > > > > + */
> > > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > > +			  struct drm_modeset_acquire_ctx *ctx)
> > > > >  {
> > > > > -	struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)-
> > > > > >base;
> > > > >  	struct drm_i915_private *dev_priv = to_i915(encoder-
> > > > > >base.dev);
> > > > > -	struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc);
> > > > > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
> > > > > +	struct intel_connector *connector = intel_dp-
> > > > > >attached_connector;
> > > > > +	struct drm_connector_state *conn_state;
> > > > > +	struct intel_crtc_state *crtc_state;
> > > > > +	struct intel_crtc *crtc;
> > > > > +	int ret;
> > > > > +
> > > > > +	/* FIXME handle the MST connectors as well */
> > > > > +
> > > > > +	if (!connector || connector->base.status !=
> > > > > connector_status_connected)
> > > > > +		return 0;
> > > > > +
> > > > > +	ret = drm_modeset_lock(&dev_priv-
> > > > > >drm.mode_config.connection_mutex,
> > > > > ctx);
> > > > > +	if (ret)
> > > > > +		return ret;
> > > > > +
> > > > > +	conn_state = connector->base.state;
> > > > > +
> > > > > +	crtc = to_intel_crtc(conn_state->crtc);
> > > > > +	if (!crtc)
> > > > > +		return 0;
> > > > > +
> > > > > +	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
> > > > > +	if (ret)
> > > > > +		return ret;
> > > > > +
> > > > > +	crtc_state = to_intel_crtc_state(crtc->base.state);
> > > > > +
> > > > > +	WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
> > > > > +
> > > > > +	if (!crtc_state->base.active)
> > > > > +		return 0;
> > > > > +
> > > > > +	if (conn_state->commit &&
> > > > > +	    !try_wait_for_completion(&conn_state->commit->hw_done))
> > > > > +		return 0;
> > > > > +
> > > > > +	if (!intel_dp_needs_link_retrain(intel_dp))
> > > > > +		return 0;
> > > > 
> > > > NAK, this definitely won't work for implementing MST retraining. There's
> > > > some
> > > > pretty huge differences with how retraining needs to be handled on SST
> > > > vs. MST.
> > > > An example with some normal SST sink vs. what happens on my caldigit TS3
> > > > 
> > > > SST:
> > > >     1. commit modeset, everything is OK
> > > >     2. something happens, sink sends shortpulse and changes link status
> > > > registers
> > > >     in dpcd
> > > >     3. Source receives short pulse, tries retraining five times
> > > >     4. if this succeeds:
> > > >         5. we're done here
> > > >     6. if this fails:
> > > >         7. mark link status as bad
> > > >         8. get fallback parameters
> > > >         9. hotplug event
> > > > 
> > > > MST (i915 doesn't do this yet, but this is generally how it needs to be
> > > > handled):
> > > >     1. commit modeset, everything is OK
> > > >     2. something happens (in my case, the MST hub discovers it had the
> > > > wrong max
> > > >     link rate/lane count), sink sends ESI indicating channel EQ has
> > > > failed
> > > >     3. retraining commences with five retries.
> > > >     4. if this succeeds:
> > > >        5. continue
> > > >     6. if this fails (I actually haven't seen this once yet)
> > > >         7. mark link status as bad on all downstream connectors
> > > >         8. get fallback parameters
> > > >         9. hotplug event
> > > >     10. the retrain didn't actually work (despite what the SST link
> > > > status
> > > >     registers told us). go back to step 3 five more times
> > > >     11. if this fails:
> > > >         12. mark link status as bad on all downstream connectors
> > > >         13. get fallback parameters
> > > >         14. hotplug event
> > > > 
> > > > simply put: we really should keep the "do we need to retrain?" logic out
> > > > of the
> > > > actual retraining helpers so that SST/MST codepaths can do their own
> > > > checks to
> > > > figure this out.
> > > 
> > > No, we need it since we want to check it *after* any modeset has
> > > finished. With MST I think what we'll want to do is find all the pipes
> > > affected by the link failure, lock them, and wait until they're done
> > > with their modesets, then we check the link state. If it's bad we
> > > proceed to retrain the link.
> > > 
> > > So basically just walking over the MST encoders in addition to the
> > > SST encoder, and repeating most of the steps in this code for each.
> > > Hence the the MST FIXME I left in there ;)
> > > 
> > 
> > Lyude,
> > 
> > I agree with Ville here, can we add the MST retrain required check from
> > within the intel_dp_retrain_link()? So for now the FIXME should be left
> > there
> > and MST retraining check can be added from your patches.
> > 
> > Manasi
> 
> Yep! Sorry I probably should have reiterated this part over email since I only
> mentioned it to ville directly: this part should definitely work fine, and
> intel_dp_retrain_link() is actually where we handle MST retraining in the
> latest version of the retraining series:
> 
> jfyi, you can find that here:
> https://github.com/Lyude/linux/tree/wip/i915-mst-fallback-a4
> It's almost ready for the ML, just want to get the other patches this is going
> to rely on in first and fix some small concerns I've got about that series'
> current implementation of handling modesets after a failed retrain sequence
> >

Great!
After the failed retrain sequence, it will keep on retrying until has tried all
the link rate/lane count combinations until RBR 1 lane and then fail with a ERROR message.
What was the concern on the current implementation of modeste after failed retrain?

Manasi
 
> > > > 
> > > > >  
> > > > >  	/* Suppress underruns caused by re-training */
> > > > >  	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe,
> > > > > false);
> > > > > @@ -4298,51 +4369,49 @@ intel_dp_retrain_link(struct intel_dp
> > > > > *intel_dp)
> > > > >  	if (crtc->config->has_pch_encoder)
> > > > >  		intel_set_pch_fifo_underrun_reporting(dev_priv,
> > > > >  						      intel_crtc_pch_
> > > > > transcod
> > > > > er(crtc), true);
> > > > > +
> > > > > +	return 0;
> > > > >  }
> > > > >  
> > > > > -static void
> > > > > -intel_dp_check_link_status(struct intel_dp *intel_dp)
> > > > > +/*
> > > > > + * If display is now connected check links status,
> > > > > + * there has been known issues of link loss triggering
> > > > > + * long pulse.
> > > > > + *
> > > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > > + * end up with HPD going low during a modeset, and then
> > > > > + * going back up soon after. And once that happens we must
> > > > > + * retrain the link to get a picture. That's in case no
> > > > > + * userspace component reacted to intermittent HPD dip.
> > > > > + */
> > > > > +static bool intel_dp_hotplug(struct intel_encoder *encoder,
> > > > > +			     struct intel_connector *connector)
> > > > >  {
> > > > > -	struct drm_i915_private *dev_priv =
> > > > > to_i915(intel_dp_to_dev(intel_dp));
> > > > > -	struct intel_encoder *intel_encoder =
> > > > > &dp_to_dig_port(intel_dp)-
> > > > > > base;
> > > > > 
> > > > > -	struct drm_connector_state *conn_state =
> > > > > -		intel_dp->attached_connector->base.state;
> > > > > -	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > > -
> > > > > -	WARN_ON(!drm_modeset_is_locked(&dev_priv-
> > > > > > drm.mode_config.connection_mutex));
> > > > > 
> > > > > -
> > > > > -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > > > > -		DRM_ERROR("Failed to get link status\n");
> > > > > -		return;
> > > > > -	}
> > > > > +	struct drm_modeset_acquire_ctx ctx;
> > > > > +	bool changed;
> > > > > +	int ret;
> > > > >  
> > > > > -	if (!conn_state->crtc)
> > > > > -		return;
> > > > > +	changed = intel_encoder_hotplug(encoder, connector);
> > > > >  
> > > > > -	WARN_ON(!drm_modeset_is_locked(&conn_state->crtc->mutex));
> > > > > +	drm_modeset_acquire_init(&ctx, 0);
> > > > >  
> > > > > -	if (!conn_state->crtc->state->active)
> > > > > -		return;
> > > > > +	for (;;) {
> > 
> > Here if this is getting executed due to hpd ping pong during the modeset
> > and that modeset is already happening at a link fallback parameter then
> > while we call retrain link, we should also validate the link parameters
> > so that it doesnt try to retrain with stale values.
> > 
> > I think we need to call intel_dp_link_params_valid() before retrain.
> > 
> > > > > +		ret = intel_dp_retrain_link(encoder, &ctx);
> > > > >  
> > > > > -	if (conn_state->commit &&
> > > > > -	    !try_wait_for_completion(&conn_state->commit->hw_done))
> > > > > -		return;
> > > > > +		if (ret == -EDEADLK) {
> > > > > +			drm_modeset_backoff(&ctx);
> > > > > +			continue;
> > > > > +		}
> > > > >  
> > > > > -	/*
> > > > > -	 * Validate the cached values of intel_dp->link_rate and
> > > > > -	 * intel_dp->lane_count before attempting to retrain.
> > > > > -	 */
> > > > > -	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > > >link_rate,
> > > > > -					intel_dp->lane_count))
> > > > > -		return;
> > > > > +		break;
> > > > > +	}
> > > > >  
> > > > > -	/* Retrain if Channel EQ or CR not ok */
> > > > > -	if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) 
> > > > > {
> > > > > -		DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n",
> > > > > -			      intel_encoder->base.name);
> > > > > +	drm_modeset_drop_locks(&ctx);
> > > > > +	drm_modeset_acquire_fini(&ctx);
> > > > > +	WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
> > > > >  
> > > > > -		intel_dp_retrain_link(intel_dp);
> > > > > -	}
> > > > > +	return changed;
> > > > >  }
> > > > >  
> > > > >  /*
> > > > > @@ -4400,7 +4469,9 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
> > > > >  			DRM_DEBUG_DRIVER("CP or sink specific irq
> > > > > unhandled\n");
> > > > >  	}
> > > > >  
> > > > > -	intel_dp_check_link_status(intel_dp);
> > > > > +	/* defer to the hotplug work for link retraining if needed */
> > > > > +	if (intel_dp_needs_link_retrain(intel_dp))
> > > > > +		return false;
> > > > >  
> > > > >  	if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING)
> > > > > {
> > > > >  		DRM_DEBUG_KMS("Link Training Compliance Test
> > > > > requested\n");
> > > > > @@ -4785,20 +4856,6 @@ intel_dp_long_pulse(struct intel_connector
> > > > > *connector)
> > > > >  		 */
> > > > >  		status = connector_status_disconnected;
> > > > >  		goto out;
> > > > > -	} else {
> > > > > -		/*
> > > > > -		 * If display is now connected check links status,
> > > > > -		 * there has been known issues of link loss
> > > > > triggerring
> > > > > -		 * long pulse.
> > > > > -		 *
> > > > > -		 * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > -		 * weird HPD ping pong during modesets. So we can
> > > > > apparently
> > > > > -		 * end up with HPD going low during a modeset, and
> > > > > then
> > > > > -		 * going back up soon after. And once that happens we
> > > > > must
> > > > > -		 * retrain the link to get a picture. That's in case
> > > > > no
> > > > > -		 * userspace component reacted to intermittent HPD
> > > > > dip.
> > > > > -		 */
> > > > > -		intel_dp_check_link_status(intel_dp);
> > > > >  	}
> > > > >  
> > > > >  	/*
> > > > > @@ -5340,37 +5397,10 @@ intel_dp_hpd_pulse(struct intel_digital_port
> > > > > *intel_dig_port, bool long_hpd)
> > > > >  	}
> > > > >  
> > > > >  	if (!intel_dp->is_mst) {
> > > > > -		struct drm_modeset_acquire_ctx ctx;
> > > > > -		struct drm_connector *connector = &intel_dp-
> > > > > > attached_connector->base;
> > > > > 
> > > > > -		struct drm_crtc *crtc;
> > > > > -		int iret;
> > > > > -		bool handled = false;
> > > > > -
> > > > > -		drm_modeset_acquire_init(&ctx, 0);
> > > > > -retry:
> > > > > -		iret = drm_modeset_lock(&dev_priv-
> > > > > > drm.mode_config.connection_mutex, &ctx);
> > > > > 
> > > > > -		if (iret)
> > > > > -			goto err;
> > > > > -
> > > > > -		crtc = connector->state->crtc;
> > > > > -		if (crtc) {
> > > > > -			iret = drm_modeset_lock(&crtc->mutex, &ctx);
> > > > > -			if (iret)
> > > > > -				goto err;
> > > > > -		}
> > > > > +		bool handled;
> > > > >  
> > > > >  		handled = intel_dp_short_pulse(intel_dp);
> > > > >  
> > > > > -err:
> > > > > -		if (iret == -EDEADLK) {
> > > > > -			drm_modeset_backoff(&ctx);
> > > > > -			goto retry;
> > > > > -		}
> > > > > -
> > > > > -		drm_modeset_drop_locks(&ctx);
> > > > > -		drm_modeset_acquire_fini(&ctx);
> > > > > -		WARN(iret, "Acquiring modeset locks failed with
> > > > > %i\n", iret);
> > > > > -
> > > > >  		/* Short pulse can signify loss of hdcp
> > > > > authentication */
> > > > >  		intel_hdcp_check_link(intel_dp->attached_connector);
> > > > >  
> > > > > @@ -6400,7 +6430,7 @@ bool intel_dp_init(struct drm_i915_private
> > > > > *dev_priv,
> > > > >  			     "DP %c", port_name(port)))
> > > > >  		goto err_encoder_init;
> > > > >  
> > > > > -	intel_encoder->hotplug = intel_encoder_hotplug;
> > > > > +	intel_encoder->hotplug = intel_dp_hotplug;
> > > > >  	intel_encoder->compute_config = intel_dp_compute_config;
> > > > >  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
> > > > >  	intel_encoder->get_config = intel_dp_get_config;
> > > > > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > > > > b/drivers/gpu/drm/i915/intel_drv.h
> > > > > index 5ea1dc3f63bf..ddf28a442cd7 100644
> > > > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > > > @@ -1611,6 +1611,8 @@ int
> > > > > intel_dp_get_link_train_fallback_values(struct
> > > > > intel_dp *intel_dp,
> > > > >  					    int link_rate, uint8_t
> > > > > lane_count);
> > > > >  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > > > >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> > > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > > +			  struct drm_modeset_acquire_ctx *ctx);
> > > > >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> > > > >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > > > >  void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);
> > > 
> > > -- 
> > > Ville Syrjälä
> > > Intel OTC
> > > _______________________________________________
> > > Intel-gfx mailing list
> > > Intel-gfx@lists.freedesktop.org
> > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> -- 
> Cheers,
> 	Lyude Paul
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
  2018-02-28 19:27           ` Manasi Navare
@ 2018-02-28 19:41             ` Lyude Paul
  2018-02-28 19:57               ` Manasi Navare
  0 siblings, 1 reply; 23+ messages in thread
From: Lyude Paul @ 2018-02-28 19:41 UTC (permalink / raw)
  To: Manasi Navare; +Cc: intel-gfx

On Wed, 2018-02-28 at 11:27 -0800, Manasi Navare wrote:
> On Wed, Feb 28, 2018 at 02:07:34PM -0500, Lyude Paul wrote:
> > 
> > On Tue, 2018-02-27 at 23:17 -0800, Manasi Navare wrote:
> > > Ville,  thanks for the patch and
> > > Sorry for not being able to review this earlier.
> > > Please find some comments below:
> > > 
> > > On Wed, Jan 31, 2018 at 03:27:10PM +0200, Ville Syrjälä wrote:
> > > > On Tue, Jan 30, 2018 at 06:16:59PM -0500, Lyude Paul wrote:
> > > > > On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> > > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > 
> > > > > > Doing link retraining from the short pulse handler is problematic
> > > > > > since
> > > > > > that might introduce deadlocks with MST sideband processing.
> > > > > > Currently
> > > > > > we don't retrain MST links from this code, but we want to change
> > > > > > that.
> > > > > > So better to move the entire thing to the hotplug work. We can
> > > > > > utilize
> > > > > > the new encoder->hotplug() hook for this.
> > > > > > 
> > > > > > The only thing we leave in the short pulse handler is the link
> > > > > > status
> > > > > > check. That one still depends on the link parameters stored under
> > > > > > intel_dp, so no locking around that but races should be mostly
> > > > > > harmless
> > > > > > as the actual retraining code will recheck the link state if we
> > > > > > end up there by mistake.
> > > > > > 
> > > > > > v2: Rebase due to ->post_hotplug() now being just ->hotplug()
> > > > > >     Check the connector type to figure out if we should do
> > > > > >     the HDMI thing or the DP think for DDI
> > > > > > 
> > > > > > Cc: Manasi Navare <manasi.d.navare@intel.com>
> > > > > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > ---
> > > > > >  drivers/gpu/drm/i915/intel_ddi.c |  10 +-
> > > > > >  drivers/gpu/drm/i915/intel_dp.c  | 196 ++++++++++++++++++++++--
> > > > > > ----
> > > > > > --------
> > > > > > ---
> > > > > >  drivers/gpu/drm/i915/intel_drv.h |   2 +
> > > > > >  3 files changed, 120 insertions(+), 88 deletions(-)
> > > > > > 
> > > > > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > b/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > index 25793bdc692f..5f3d58f1ae6e 100644
> > > > > > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > @@ -2880,7 +2880,10 @@ static bool intel_ddi_hotplug(struct
> > > > > > intel_encoder
> > > > > > *encoder,
> > > > > >  	drm_modeset_acquire_init(&ctx, 0);
> > > > > >  
> > > > > >  	for (;;) {
> > > > > > -		ret = intel_hdmi_reset_link(encoder, &ctx);
> > > > > > +		if (connector->base.connector_type ==
> > > > > > DRM_MODE_CONNECTOR_HDMIA)
> > > > > > +			ret = intel_hdmi_reset_link(encoder,
> > > > > > &ctx);
> > > > > > +		else
> > > > > > +			ret = intel_dp_retrain_link(encoder,
> > > > > > &ctx);
> > > > > >  
> > > > > >  		if (ret == -EDEADLK) {
> > > > > >  			drm_modeset_backoff(&ctx);
> > > > > > @@ -3007,10 +3010,7 @@ void intel_ddi_init(struct drm_i915_private
> > > > > > *dev_priv,
> > > > > > enum port port)
> > > > > >  	drm_encoder_init(&dev_priv->drm, encoder,
> > > > > > &intel_ddi_funcs,
> > > > > >  			 DRM_MODE_ENCODER_TMDS, "DDI %c",
> > > > > > port_name(port));
> > > > > >  
> > > > > > -	if (init_hdmi)
> > > > > > -		intel_encoder->hotplug = intel_ddi_hotplug;
> > > > > > -	else
> > > > > > -		intel_encoder->hotplug = intel_encoder_hotplug;
> > > > > > +	intel_encoder->hotplug = intel_ddi_hotplug;
> > > > > >  	intel_encoder->compute_output_type =
> > > > > > intel_ddi_compute_output_type;
> > > > > >  	intel_encoder->compute_config = intel_ddi_compute_config;
> > > > > >  	intel_encoder->enable = intel_enable_ddi;
> > > > > > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > > > > > b/drivers/gpu/drm/i915/intel_dp.c
> > > > > > index 6bbf14410c2a..152016e09a11 100644
> > > > > > --- a/drivers/gpu/drm/i915/intel_dp.c
> > > > > > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > > > > > @@ -4275,12 +4275,83 @@ intel_dp_check_mst_status(struct intel_dp
> > > > > > *intel_dp)
> > > > > >  	return -EINVAL;
> > > > > >  }
> > > > > >  
> > > > > > -static void
> > > > > > -intel_dp_retrain_link(struct intel_dp *intel_dp)
> > > > > > +static bool
> > > > > > +intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
> > > > > > +{
> > > > > > +	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > > > +
> > > > > > +	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > > > > > +		DRM_ERROR("Failed to get link status\n");
> > > > > > +		return false;
> > > > > > +	}
> > > > > > +
> > > > > > +	/*
> > > > > > +	 * Validate the cached values of intel_dp->link_rate and
> > > > > > +	 * intel_dp->lane_count before attempting to retrain.
> > > > > > +	 */
> > > > > > +	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > > > > link_rate,
> > > > > > 
> > > > > > +					intel_dp->lane_count))
> > > > > > +		return false;
> > > > > > +
> > > > > > +	/* Retrain if Channel EQ or CR not ok */
> > > > > > +	return !drm_dp_channel_eq_ok(link_status, intel_dp-
> > > > > > > lane_count);
> > > > > > 
> > > > > > +}
> > > > > > +
> > > > > > +/*
> > > > > > + * If display is now connected check links status,
> > > > > > + * there has been known issues of link loss triggering
> > > > > > + * long pulse.
> > > > > > + *
> > > > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > > > + * end up with HPD going low during a modeset, and then
> > > > > > + * going back up soon after. And once that happens we must
> > > > > > + * retrain the link to get a picture. That's in case no
> > > > > > + * userspace component reacted to intermittent HPD dip.
> > > > > > + */
> > > > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > > > +			  struct drm_modeset_acquire_ctx *ctx)
> > > > > >  {
> > > > > > -	struct intel_encoder *encoder =
> > > > > > &dp_to_dig_port(intel_dp)-
> > > > > > > base;
> > > > > > 
> > > > > >  	struct drm_i915_private *dev_priv = to_i915(encoder-
> > > > > > > base.dev);
> > > > > > 
> > > > > > -	struct intel_crtc *crtc = to_intel_crtc(encoder-
> > > > > > >base.crtc);
> > > > > > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder-
> > > > > > >base);
> > > > > > +	struct intel_connector *connector = intel_dp-
> > > > > > > attached_connector;
> > > > > > 
> > > > > > +	struct drm_connector_state *conn_state;
> > > > > > +	struct intel_crtc_state *crtc_state;
> > > > > > +	struct intel_crtc *crtc;
> > > > > > +	int ret;
> > > > > > +
> > > > > > +	/* FIXME handle the MST connectors as well */
> > > > > > +
> > > > > > +	if (!connector || connector->base.status !=
> > > > > > connector_status_connected)
> > > > > > +		return 0;
> > > > > > +
> > > > > > +	ret = drm_modeset_lock(&dev_priv-
> > > > > > > drm.mode_config.connection_mutex,
> > > > > > 
> > > > > > ctx);
> > > > > > +	if (ret)
> > > > > > +		return ret;
> > > > > > +
> > > > > > +	conn_state = connector->base.state;
> > > > > > +
> > > > > > +	crtc = to_intel_crtc(conn_state->crtc);
> > > > > > +	if (!crtc)
> > > > > > +		return 0;
> > > > > > +
> > > > > > +	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
> > > > > > +	if (ret)
> > > > > > +		return ret;
> > > > > > +
> > > > > > +	crtc_state = to_intel_crtc_state(crtc->base.state);
> > > > > > +
> > > > > > +	WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
> > > > > > +
> > > > > > +	if (!crtc_state->base.active)
> > > > > > +		return 0;
> > > > > > +
> > > > > > +	if (conn_state->commit &&
> > > > > > +	    !try_wait_for_completion(&conn_state->commit-
> > > > > > >hw_done))
> > > > > > +		return 0;
> > > > > > +
> > > > > > +	if (!intel_dp_needs_link_retrain(intel_dp))
> > > > > > +		return 0;
> > > > > 
> > > > > NAK, this definitely won't work for implementing MST retraining.
> > > > > There's
> > > > > some
> > > > > pretty huge differences with how retraining needs to be handled on
> > > > > SST
> > > > > vs. MST.
> > > > > An example with some normal SST sink vs. what happens on my caldigit
> > > > > TS3
> > > > > 
> > > > > SST:
> > > > >     1. commit modeset, everything is OK
> > > > >     2. something happens, sink sends shortpulse and changes link
> > > > > status
> > > > > registers
> > > > >     in dpcd
> > > > >     3. Source receives short pulse, tries retraining five times
> > > > >     4. if this succeeds:
> > > > >         5. we're done here
> > > > >     6. if this fails:
> > > > >         7. mark link status as bad
> > > > >         8. get fallback parameters
> > > > >         9. hotplug event
> > > > > 
> > > > > MST (i915 doesn't do this yet, but this is generally how it needs to
> > > > > be
> > > > > handled):
> > > > >     1. commit modeset, everything is OK
> > > > >     2. something happens (in my case, the MST hub discovers it had
> > > > > the
> > > > > wrong max
> > > > >     link rate/lane count), sink sends ESI indicating channel EQ has
> > > > > failed
> > > > >     3. retraining commences with five retries.
> > > > >     4. if this succeeds:
> > > > >        5. continue
> > > > >     6. if this fails (I actually haven't seen this once yet)
> > > > >         7. mark link status as bad on all downstream connectors
> > > > >         8. get fallback parameters
> > > > >         9. hotplug event
> > > > >     10. the retrain didn't actually work (despite what the SST link
> > > > > status
> > > > >     registers told us). go back to step 3 five more times
> > > > >     11. if this fails:
> > > > >         12. mark link status as bad on all downstream connectors
> > > > >         13. get fallback parameters
> > > > >         14. hotplug event
> > > > > 
> > > > > simply put: we really should keep the "do we need to retrain?" logic
> > > > > out
> > > > > of the
> > > > > actual retraining helpers so that SST/MST codepaths can do their own
> > > > > checks to
> > > > > figure this out.
> > > > 
> > > > No, we need it since we want to check it *after* any modeset has
> > > > finished. With MST I think what we'll want to do is find all the pipes
> > > > affected by the link failure, lock them, and wait until they're done
> > > > with their modesets, then we check the link state. If it's bad we
> > > > proceed to retrain the link.
> > > > 
> > > > So basically just walking over the MST encoders in addition to the
> > > > SST encoder, and repeating most of the steps in this code for each.
> > > > Hence the the MST FIXME I left in there ;)
> > > > 
> > > 
> > > Lyude,
> > > 
> > > I agree with Ville here, can we add the MST retrain required check from
> > > within the intel_dp_retrain_link()? So for now the FIXME should be left
> > > there
> > > and MST retraining check can be added from your patches.
> > > 
> > > Manasi
> > 
> > Yep! Sorry I probably should have reiterated this part over email since I
> > only
> > mentioned it to ville directly: this part should definitely work fine, and
> > intel_dp_retrain_link() is actually where we handle MST retraining in the
> > latest version of the retraining series:
> > 
> > jfyi, you can find that here:
> > https://github.com/Lyude/linux/tree/wip/i915-mst-fallback-a4
> > It's almost ready for the ML, just want to get the other patches this is
> > going
> > to rely on in first and fix some small concerns I've got about that
> > series'
> > current implementation of handling modesets after a failed retrain
> > sequence
> > > 
> 
> Great!
> After the failed retrain sequence, it will keep on retrying until has tried
> all
> the link rate/lane count combinations until RBR 1 lane and then fail with a
> ERROR message.
> What was the concern on the current implementation of modeste after failed
> retrain?
I actually take that back. Was worried that not freeing existing VCPI
allocations during the first atomic check phase for the first modeset after a
retrain failure might cause atomic checks to fail from not having enough VCPI 
space, but then I realized that wouldn't matter since if we're not able to fit
one display into the VCPI with a reduced pbn_div, that just means fitting both
displays with a reduced pbn_div would also be impossible :P.

> 
> Manasi
>  
> > > > > 
> > > > > >  
> > > > > >  	/* Suppress underruns caused by re-training */
> > > > > >  	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc-
> > > > > > >pipe,
> > > > > > false);
> > > > > > @@ -4298,51 +4369,49 @@ intel_dp_retrain_link(struct intel_dp
> > > > > > *intel_dp)
> > > > > >  	if (crtc->config->has_pch_encoder)
> > > > > >  		intel_set_pch_fifo_underrun_reporting(dev_priv,
> > > > > >  						      intel_crtc_
> > > > > > pch_
> > > > > > transcod
> > > > > > er(crtc), true);
> > > > > > +
> > > > > > +	return 0;
> > > > > >  }
> > > > > >  
> > > > > > -static void
> > > > > > -intel_dp_check_link_status(struct intel_dp *intel_dp)
> > > > > > +/*
> > > > > > + * If display is now connected check links status,
> > > > > > + * there has been known issues of link loss triggering
> > > > > > + * long pulse.
> > > > > > + *
> > > > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > > > + * end up with HPD going low during a modeset, and then
> > > > > > + * going back up soon after. And once that happens we must
> > > > > > + * retrain the link to get a picture. That's in case no
> > > > > > + * userspace component reacted to intermittent HPD dip.
> > > > > > + */
> > > > > > +static bool intel_dp_hotplug(struct intel_encoder *encoder,
> > > > > > +			     struct intel_connector *connector)
> > > > > >  {
> > > > > > -	struct drm_i915_private *dev_priv =
> > > > > > to_i915(intel_dp_to_dev(intel_dp));
> > > > > > -	struct intel_encoder *intel_encoder =
> > > > > > &dp_to_dig_port(intel_dp)-
> > > > > > > base;
> > > > > > 
> > > > > > -	struct drm_connector_state *conn_state =
> > > > > > -		intel_dp->attached_connector->base.state;
> > > > > > -	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > > > -
> > > > > > -	WARN_ON(!drm_modeset_is_locked(&dev_priv-
> > > > > > > drm.mode_config.connection_mutex));
> > > > > > 
> > > > > > -
> > > > > > -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > > > > > -		DRM_ERROR("Failed to get link status\n");
> > > > > > -		return;
> > > > > > -	}
> > > > > > +	struct drm_modeset_acquire_ctx ctx;
> > > > > > +	bool changed;
> > > > > > +	int ret;
> > > > > >  
> > > > > > -	if (!conn_state->crtc)
> > > > > > -		return;
> > > > > > +	changed = intel_encoder_hotplug(encoder, connector);
> > > > > >  
> > > > > > -	WARN_ON(!drm_modeset_is_locked(&conn_state->crtc-
> > > > > > >mutex));
> > > > > > +	drm_modeset_acquire_init(&ctx, 0);
> > > > > >  
> > > > > > -	if (!conn_state->crtc->state->active)
> > > > > > -		return;
> > > > > > +	for (;;) {
> > > 
> > > Here if this is getting executed due to hpd ping pong during the modeset
> > > and that modeset is already happening at a link fallback parameter then
> > > while we call retrain link, we should also validate the link parameters
> > > so that it doesnt try to retrain with stale values.
> > > 
> > > I think we need to call intel_dp_link_params_valid() before retrain.
> > > 
> > > > > > +		ret = intel_dp_retrain_link(encoder, &ctx);
> > > > > >  
> > > > > > -	if (conn_state->commit &&
> > > > > > -	    !try_wait_for_completion(&conn_state->commit-
> > > > > > >hw_done))
> > > > > > -		return;
> > > > > > +		if (ret == -EDEADLK) {
> > > > > > +			drm_modeset_backoff(&ctx);
> > > > > > +			continue;
> > > > > > +		}
> > > > > >  
> > > > > > -	/*
> > > > > > -	 * Validate the cached values of intel_dp->link_rate and
> > > > > > -	 * intel_dp->lane_count before attempting to retrain.
> > > > > > -	 */
> > > > > > -	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > > > > link_rate,
> > > > > > 
> > > > > > -					intel_dp->lane_count))
> > > > > > -		return;
> > > > > > +		break;
> > > > > > +	}
> > > > > >  
> > > > > > -	/* Retrain if Channel EQ or CR not ok */
> > > > > > -	if (!drm_dp_channel_eq_ok(link_status, intel_dp-
> > > > > > >lane_count)) 
> > > > > > {
> > > > > > -		DRM_DEBUG_KMS("%s: channel EQ not ok,
> > > > > > retraining\n",
> > > > > > -			      intel_encoder->base.name);
> > > > > > +	drm_modeset_drop_locks(&ctx);
> > > > > > +	drm_modeset_acquire_fini(&ctx);
> > > > > > +	WARN(ret, "Acquiring modeset locks failed with %i\n",
> > > > > > ret);
> > > > > >  
> > > > > > -		intel_dp_retrain_link(intel_dp);
> > > > > > -	}
> > > > > > +	return changed;
> > > > > >  }
> > > > > >  
> > > > > >  /*
> > > > > > @@ -4400,7 +4469,9 @@ intel_dp_short_pulse(struct intel_dp
> > > > > > *intel_dp)
> > > > > >  			DRM_DEBUG_DRIVER("CP or sink specific irq
> > > > > > unhandled\n");
> > > > > >  	}
> > > > > >  
> > > > > > -	intel_dp_check_link_status(intel_dp);
> > > > > > +	/* defer to the hotplug work for link retraining if
> > > > > > needed */
> > > > > > +	if (intel_dp_needs_link_retrain(intel_dp))
> > > > > > +		return false;
> > > > > >  
> > > > > >  	if (intel_dp->compliance.test_type ==
> > > > > > DP_TEST_LINK_TRAINING)
> > > > > > {
> > > > > >  		DRM_DEBUG_KMS("Link Training Compliance Test
> > > > > > requested\n");
> > > > > > @@ -4785,20 +4856,6 @@ intel_dp_long_pulse(struct intel_connector
> > > > > > *connector)
> > > > > >  		 */
> > > > > >  		status = connector_status_disconnected;
> > > > > >  		goto out;
> > > > > > -	} else {
> > > > > > -		/*
> > > > > > -		 * If display is now connected check links
> > > > > > status,
> > > > > > -		 * there has been known issues of link loss
> > > > > > triggerring
> > > > > > -		 * long pulse.
> > > > > > -		 *
> > > > > > -		 * Some sinks (eg. ASUS PB287Q) seem to perform
> > > > > > some
> > > > > > -		 * weird HPD ping pong during modesets. So we can
> > > > > > apparently
> > > > > > -		 * end up with HPD going low during a modeset,
> > > > > > and
> > > > > > then
> > > > > > -		 * going back up soon after. And once that
> > > > > > happens we
> > > > > > must
> > > > > > -		 * retrain the link to get a picture. That's in
> > > > > > case
> > > > > > no
> > > > > > -		 * userspace component reacted to intermittent
> > > > > > HPD
> > > > > > dip.
> > > > > > -		 */
> > > > > > -		intel_dp_check_link_status(intel_dp);
> > > > > >  	}
> > > > > >  
> > > > > >  	/*
> > > > > > @@ -5340,37 +5397,10 @@ intel_dp_hpd_pulse(struct
> > > > > > intel_digital_port
> > > > > > *intel_dig_port, bool long_hpd)
> > > > > >  	}
> > > > > >  
> > > > > >  	if (!intel_dp->is_mst) {
> > > > > > -		struct drm_modeset_acquire_ctx ctx;
> > > > > > -		struct drm_connector *connector = &intel_dp-
> > > > > > > attached_connector->base;
> > > > > > 
> > > > > > -		struct drm_crtc *crtc;
> > > > > > -		int iret;
> > > > > > -		bool handled = false;
> > > > > > -
> > > > > > -		drm_modeset_acquire_init(&ctx, 0);
> > > > > > -retry:
> > > > > > -		iret = drm_modeset_lock(&dev_priv-
> > > > > > > drm.mode_config.connection_mutex, &ctx);
> > > > > > 
> > > > > > -		if (iret)
> > > > > > -			goto err;
> > > > > > -
> > > > > > -		crtc = connector->state->crtc;
> > > > > > -		if (crtc) {
> > > > > > -			iret = drm_modeset_lock(&crtc->mutex,
> > > > > > &ctx);
> > > > > > -			if (iret)
> > > > > > -				goto err;
> > > > > > -		}
> > > > > > +		bool handled;
> > > > > >  
> > > > > >  		handled = intel_dp_short_pulse(intel_dp);
> > > > > >  
> > > > > > -err:
> > > > > > -		if (iret == -EDEADLK) {
> > > > > > -			drm_modeset_backoff(&ctx);
> > > > > > -			goto retry;
> > > > > > -		}
> > > > > > -
> > > > > > -		drm_modeset_drop_locks(&ctx);
> > > > > > -		drm_modeset_acquire_fini(&ctx);
> > > > > > -		WARN(iret, "Acquiring modeset locks failed with
> > > > > > %i\n", iret);
> > > > > > -
> > > > > >  		/* Short pulse can signify loss of hdcp
> > > > > > authentication */
> > > > > >  		intel_hdcp_check_link(intel_dp-
> > > > > > >attached_connector);
> > > > > >  
> > > > > > @@ -6400,7 +6430,7 @@ bool intel_dp_init(struct drm_i915_private
> > > > > > *dev_priv,
> > > > > >  			     "DP %c", port_name(port)))
> > > > > >  		goto err_encoder_init;
> > > > > >  
> > > > > > -	intel_encoder->hotplug = intel_encoder_hotplug;
> > > > > > +	intel_encoder->hotplug = intel_dp_hotplug;
> > > > > >  	intel_encoder->compute_config = intel_dp_compute_config;
> > > > > >  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
> > > > > >  	intel_encoder->get_config = intel_dp_get_config;
> > > > > > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > > > > > b/drivers/gpu/drm/i915/intel_drv.h
> > > > > > index 5ea1dc3f63bf..ddf28a442cd7 100644
> > > > > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > > > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > > > > @@ -1611,6 +1611,8 @@ int
> > > > > > intel_dp_get_link_train_fallback_values(struct
> > > > > > intel_dp *intel_dp,
> > > > > >  					    int link_rate,
> > > > > > uint8_t
> > > > > > lane_count);
> > > > > >  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > > > > >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> > > > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > > > +			  struct drm_modeset_acquire_ctx *ctx);
> > > > > >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> > > > > >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > > > > >  void intel_dp_encoder_suspend(struct intel_encoder
> > > > > > *intel_encoder);
> > > > 
> > > > -- 
> > > > Ville Syrjälä
> > > > Intel OTC
> > > > _______________________________________________
> > > > Intel-gfx mailing list
> > > > Intel-gfx@lists.freedesktop.org
> > > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > 
> > -- 
> > Cheers,
> > 	Lyude Paul
-- 
Cheers,
	Lyude Paul
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
  2018-02-28 19:41             ` Lyude Paul
@ 2018-02-28 19:57               ` Manasi Navare
  2018-02-28 20:10                 ` Lyude Paul
  0 siblings, 1 reply; 23+ messages in thread
From: Manasi Navare @ 2018-02-28 19:57 UTC (permalink / raw)
  To: Lyude Paul; +Cc: intel-gfx

On Wed, Feb 28, 2018 at 02:41:06PM -0500, Lyude Paul wrote:
> On Wed, 2018-02-28 at 11:27 -0800, Manasi Navare wrote:
> > On Wed, Feb 28, 2018 at 02:07:34PM -0500, Lyude Paul wrote:
> > > 
> > > On Tue, 2018-02-27 at 23:17 -0800, Manasi Navare wrote:
> > > > Ville,  thanks for the patch and
> > > > Sorry for not being able to review this earlier.
> > > > Please find some comments below:
> > > > 
> > > > On Wed, Jan 31, 2018 at 03:27:10PM +0200, Ville Syrjälä wrote:
> > > > > On Tue, Jan 30, 2018 at 06:16:59PM -0500, Lyude Paul wrote:
> > > > > > On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> > > > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > > 
> > > > > > > Doing link retraining from the short pulse handler is problematic
> > > > > > > since
> > > > > > > that might introduce deadlocks with MST sideband processing.
> > > > > > > Currently
> > > > > > > we don't retrain MST links from this code, but we want to change
> > > > > > > that.
> > > > > > > So better to move the entire thing to the hotplug work. We can
> > > > > > > utilize
> > > > > > > the new encoder->hotplug() hook for this.
> > > > > > > 
> > > > > > > The only thing we leave in the short pulse handler is the link
> > > > > > > status
> > > > > > > check. That one still depends on the link parameters stored under
> > > > > > > intel_dp, so no locking around that but races should be mostly
> > > > > > > harmless
> > > > > > > as the actual retraining code will recheck the link state if we
> > > > > > > end up there by mistake.
> > > > > > > 
> > > > > > > v2: Rebase due to ->post_hotplug() now being just ->hotplug()
> > > > > > >     Check the connector type to figure out if we should do
> > > > > > >     the HDMI thing or the DP think for DDI
> > > > > > > 
> > > > > > > Cc: Manasi Navare <manasi.d.navare@intel.com>
> > > > > > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > > ---
> > > > > > >  drivers/gpu/drm/i915/intel_ddi.c |  10 +-
> > > > > > >  drivers/gpu/drm/i915/intel_dp.c  | 196 ++++++++++++++++++++++--
> > > > > > > ----
> > > > > > > --------
> > > > > > > ---
> > > > > > >  drivers/gpu/drm/i915/intel_drv.h |   2 +
> > > > > > >  3 files changed, 120 insertions(+), 88 deletions(-)
> > > > > > > 
> > > > > > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > b/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > index 25793bdc692f..5f3d58f1ae6e 100644
> > > > > > > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > @@ -2880,7 +2880,10 @@ static bool intel_ddi_hotplug(struct
> > > > > > > intel_encoder
> > > > > > > *encoder,
> > > > > > >  	drm_modeset_acquire_init(&ctx, 0);
> > > > > > >  
> > > > > > >  	for (;;) {
> > > > > > > -		ret = intel_hdmi_reset_link(encoder, &ctx);
> > > > > > > +		if (connector->base.connector_type ==
> > > > > > > DRM_MODE_CONNECTOR_HDMIA)
> > > > > > > +			ret = intel_hdmi_reset_link(encoder,
> > > > > > > &ctx);
> > > > > > > +		else
> > > > > > > +			ret = intel_dp_retrain_link(encoder,
> > > > > > > &ctx);
> > > > > > >  
> > > > > > >  		if (ret == -EDEADLK) {
> > > > > > >  			drm_modeset_backoff(&ctx);
> > > > > > > @@ -3007,10 +3010,7 @@ void intel_ddi_init(struct drm_i915_private
> > > > > > > *dev_priv,
> > > > > > > enum port port)
> > > > > > >  	drm_encoder_init(&dev_priv->drm, encoder,
> > > > > > > &intel_ddi_funcs,
> > > > > > >  			 DRM_MODE_ENCODER_TMDS, "DDI %c",
> > > > > > > port_name(port));
> > > > > > >  
> > > > > > > -	if (init_hdmi)
> > > > > > > -		intel_encoder->hotplug = intel_ddi_hotplug;
> > > > > > > -	else
> > > > > > > -		intel_encoder->hotplug = intel_encoder_hotplug;
> > > > > > > +	intel_encoder->hotplug = intel_ddi_hotplug;
> > > > > > >  	intel_encoder->compute_output_type =
> > > > > > > intel_ddi_compute_output_type;
> > > > > > >  	intel_encoder->compute_config = intel_ddi_compute_config;
> > > > > > >  	intel_encoder->enable = intel_enable_ddi;
> > > > > > > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > b/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > index 6bbf14410c2a..152016e09a11 100644
> > > > > > > --- a/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > @@ -4275,12 +4275,83 @@ intel_dp_check_mst_status(struct intel_dp
> > > > > > > *intel_dp)
> > > > > > >  	return -EINVAL;
> > > > > > >  }
> > > > > > >  
> > > > > > > -static void
> > > > > > > -intel_dp_retrain_link(struct intel_dp *intel_dp)
> > > > > > > +static bool
> > > > > > > +intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
> > > > > > > +{
> > > > > > > +	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > > > > +
> > > > > > > +	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > > > > > > +		DRM_ERROR("Failed to get link status\n");
> > > > > > > +		return false;
> > > > > > > +	}
> > > > > > > +
> > > > > > > +	/*
> > > > > > > +	 * Validate the cached values of intel_dp->link_rate and
> > > > > > > +	 * intel_dp->lane_count before attempting to retrain.
> > > > > > > +	 */
> > > > > > > +	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > > > > > link_rate,
> > > > > > > 
> > > > > > > +					intel_dp->lane_count))
> > > > > > > +		return false;
> > > > > > > +
> > > > > > > +	/* Retrain if Channel EQ or CR not ok */
> > > > > > > +	return !drm_dp_channel_eq_ok(link_status, intel_dp-
> > > > > > > > lane_count);
> > > > > > > 
> > > > > > > +}
> > > > > > > +
> > > > > > > +/*
> > > > > > > + * If display is now connected check links status,
> > > > > > > + * there has been known issues of link loss triggering
> > > > > > > + * long pulse.
> > > > > > > + *
> > > > > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > > > > + * end up with HPD going low during a modeset, and then
> > > > > > > + * going back up soon after. And once that happens we must
> > > > > > > + * retrain the link to get a picture. That's in case no
> > > > > > > + * userspace component reacted to intermittent HPD dip.
> > > > > > > + */
> > > > > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > > > > +			  struct drm_modeset_acquire_ctx *ctx)
> > > > > > >  {
> > > > > > > -	struct intel_encoder *encoder =
> > > > > > > &dp_to_dig_port(intel_dp)-
> > > > > > > > base;
> > > > > > > 
> > > > > > >  	struct drm_i915_private *dev_priv = to_i915(encoder-
> > > > > > > > base.dev);
> > > > > > > 
> > > > > > > -	struct intel_crtc *crtc = to_intel_crtc(encoder-
> > > > > > > >base.crtc);
> > > > > > > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder-
> > > > > > > >base);
> > > > > > > +	struct intel_connector *connector = intel_dp-
> > > > > > > > attached_connector;
> > > > > > > 
> > > > > > > +	struct drm_connector_state *conn_state;
> > > > > > > +	struct intel_crtc_state *crtc_state;
> > > > > > > +	struct intel_crtc *crtc;
> > > > > > > +	int ret;
> > > > > > > +
> > > > > > > +	/* FIXME handle the MST connectors as well */
> > > > > > > +
> > > > > > > +	if (!connector || connector->base.status !=
> > > > > > > connector_status_connected)
> > > > > > > +		return 0;
> > > > > > > +
> > > > > > > +	ret = drm_modeset_lock(&dev_priv-
> > > > > > > > drm.mode_config.connection_mutex,
> > > > > > > 
> > > > > > > ctx);
> > > > > > > +	if (ret)
> > > > > > > +		return ret;
> > > > > > > +
> > > > > > > +	conn_state = connector->base.state;
> > > > > > > +
> > > > > > > +	crtc = to_intel_crtc(conn_state->crtc);
> > > > > > > +	if (!crtc)
> > > > > > > +		return 0;
> > > > > > > +
> > > > > > > +	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
> > > > > > > +	if (ret)
> > > > > > > +		return ret;
> > > > > > > +
> > > > > > > +	crtc_state = to_intel_crtc_state(crtc->base.state);
> > > > > > > +
> > > > > > > +	WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
> > > > > > > +
> > > > > > > +	if (!crtc_state->base.active)
> > > > > > > +		return 0;
> > > > > > > +
> > > > > > > +	if (conn_state->commit &&
> > > > > > > +	    !try_wait_for_completion(&conn_state->commit-
> > > > > > > >hw_done))
> > > > > > > +		return 0;
> > > > > > > +
> > > > > > > +	if (!intel_dp_needs_link_retrain(intel_dp))
> > > > > > > +		return 0;
> > > > > > 
> > > > > > NAK, this definitely won't work for implementing MST retraining.
> > > > > > There's
> > > > > > some
> > > > > > pretty huge differences with how retraining needs to be handled on
> > > > > > SST
> > > > > > vs. MST.
> > > > > > An example with some normal SST sink vs. what happens on my caldigit
> > > > > > TS3
> > > > > > 
> > > > > > SST:
> > > > > >     1. commit modeset, everything is OK
> > > > > >     2. something happens, sink sends shortpulse and changes link
> > > > > > status
> > > > > > registers
> > > > > >     in dpcd
> > > > > >     3. Source receives short pulse, tries retraining five times
> > > > > >     4. if this succeeds:
> > > > > >         5. we're done here
> > > > > >     6. if this fails:
> > > > > >         7. mark link status as bad
> > > > > >         8. get fallback parameters
> > > > > >         9. hotplug event
> > > > > > 
> > > > > > MST (i915 doesn't do this yet, but this is generally how it needs to
> > > > > > be
> > > > > > handled):
> > > > > >     1. commit modeset, everything is OK
> > > > > >     2. something happens (in my case, the MST hub discovers it had
> > > > > > the
> > > > > > wrong max
> > > > > >     link rate/lane count), sink sends ESI indicating channel EQ has
> > > > > > failed
> > > > > >     3. retraining commences with five retries.
> > > > > >     4. if this succeeds:
> > > > > >        5. continue
> > > > > >     6. if this fails (I actually haven't seen this once yet)
> > > > > >         7. mark link status as bad on all downstream connectors
> > > > > >         8. get fallback parameters
> > > > > >         9. hotplug event
> > > > > >     10. the retrain didn't actually work (despite what the SST link
> > > > > > status
> > > > > >     registers told us). go back to step 3 five more times
> > > > > >     11. if this fails:
> > > > > >         12. mark link status as bad on all downstream connectors
> > > > > >         13. get fallback parameters
> > > > > >         14. hotplug event
> > > > > > 
> > > > > > simply put: we really should keep the "do we need to retrain?" logic
> > > > > > out
> > > > > > of the
> > > > > > actual retraining helpers so that SST/MST codepaths can do their own
> > > > > > checks to
> > > > > > figure this out.
> > > > > 
> > > > > No, we need it since we want to check it *after* any modeset has
> > > > > finished. With MST I think what we'll want to do is find all the pipes
> > > > > affected by the link failure, lock them, and wait until they're done
> > > > > with their modesets, then we check the link state. If it's bad we
> > > > > proceed to retrain the link.
> > > > > 
> > > > > So basically just walking over the MST encoders in addition to the
> > > > > SST encoder, and repeating most of the steps in this code for each.
> > > > > Hence the the MST FIXME I left in there ;)
> > > > > 
> > > > 
> > > > Lyude,
> > > > 
> > > > I agree with Ville here, can we add the MST retrain required check from
> > > > within the intel_dp_retrain_link()? So for now the FIXME should be left
> > > > there
> > > > and MST retraining check can be added from your patches.
> > > > 
> > > > Manasi
> > > 
> > > Yep! Sorry I probably should have reiterated this part over email since I
> > > only
> > > mentioned it to ville directly: this part should definitely work fine, and
> > > intel_dp_retrain_link() is actually where we handle MST retraining in the
> > > latest version of the retraining series:
> > > 
> > > jfyi, you can find that here:
> > > https://github.com/Lyude/linux/tree/wip/i915-mst-fallback-a4
> > > It's almost ready for the ML, just want to get the other patches this is
> > > going
> > > to rely on in first and fix some small concerns I've got about that
> > > series'
> > > current implementation of handling modesets after a failed retrain
> > > sequence
> > > > 
> > 
> > Great!
> > After the failed retrain sequence, it will keep on retrying until has tried
> > all
> > the link rate/lane count combinations until RBR 1 lane and then fail with a
> > ERROR message.
> > What was the concern on the current implementation of modeste after failed
> > retrain?
> I actually take that back. Was worried that not freeing existing VCPI
> allocations during the first atomic check phase for the first modeset after a
> retrain failure might cause atomic checks to fail from not having enough VCPI 
> space, but then I realized that wouldn't matter since if we're not able to fit
> one display into the VCPI with a reduced pbn_div, that just means fitting both
> displays with a reduced pbn_div would also be impossible :P.
>

But then in that case, in oredr to retry at lower link rates, both these monitors will
have to drop to the next lower resolutions to fit the reduced pbn_div.

Manasi
 
> > 
> > Manasi
> >  
> > > > > > 
> > > > > > >  
> > > > > > >  	/* Suppress underruns caused by re-training */
> > > > > > >  	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc-
> > > > > > > >pipe,
> > > > > > > false);
> > > > > > > @@ -4298,51 +4369,49 @@ intel_dp_retrain_link(struct intel_dp
> > > > > > > *intel_dp)
> > > > > > >  	if (crtc->config->has_pch_encoder)
> > > > > > >  		intel_set_pch_fifo_underrun_reporting(dev_priv,
> > > > > > >  						      intel_crtc_
> > > > > > > pch_
> > > > > > > transcod
> > > > > > > er(crtc), true);
> > > > > > > +
> > > > > > > +	return 0;
> > > > > > >  }
> > > > > > >  
> > > > > > > -static void
> > > > > > > -intel_dp_check_link_status(struct intel_dp *intel_dp)
> > > > > > > +/*
> > > > > > > + * If display is now connected check links status,
> > > > > > > + * there has been known issues of link loss triggering
> > > > > > > + * long pulse.
> > > > > > > + *
> > > > > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > > > > + * end up with HPD going low during a modeset, and then
> > > > > > > + * going back up soon after. And once that happens we must
> > > > > > > + * retrain the link to get a picture. That's in case no
> > > > > > > + * userspace component reacted to intermittent HPD dip.
> > > > > > > + */
> > > > > > > +static bool intel_dp_hotplug(struct intel_encoder *encoder,
> > > > > > > +			     struct intel_connector *connector)
> > > > > > >  {
> > > > > > > -	struct drm_i915_private *dev_priv =
> > > > > > > to_i915(intel_dp_to_dev(intel_dp));
> > > > > > > -	struct intel_encoder *intel_encoder =
> > > > > > > &dp_to_dig_port(intel_dp)-
> > > > > > > > base;
> > > > > > > 
> > > > > > > -	struct drm_connector_state *conn_state =
> > > > > > > -		intel_dp->attached_connector->base.state;
> > > > > > > -	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > > > > -
> > > > > > > -	WARN_ON(!drm_modeset_is_locked(&dev_priv-
> > > > > > > > drm.mode_config.connection_mutex));
> > > > > > > 
> > > > > > > -
> > > > > > > -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> > > > > > > -		DRM_ERROR("Failed to get link status\n");
> > > > > > > -		return;
> > > > > > > -	}
> > > > > > > +	struct drm_modeset_acquire_ctx ctx;
> > > > > > > +	bool changed;
> > > > > > > +	int ret;
> > > > > > >  
> > > > > > > -	if (!conn_state->crtc)
> > > > > > > -		return;
> > > > > > > +	changed = intel_encoder_hotplug(encoder, connector);
> > > > > > >  
> > > > > > > -	WARN_ON(!drm_modeset_is_locked(&conn_state->crtc-
> > > > > > > >mutex));
> > > > > > > +	drm_modeset_acquire_init(&ctx, 0);
> > > > > > >  
> > > > > > > -	if (!conn_state->crtc->state->active)
> > > > > > > -		return;
> > > > > > > +	for (;;) {
> > > > 
> > > > Here if this is getting executed due to hpd ping pong during the modeset
> > > > and that modeset is already happening at a link fallback parameter then
> > > > while we call retrain link, we should also validate the link parameters
> > > > so that it doesnt try to retrain with stale values.
> > > > 
> > > > I think we need to call intel_dp_link_params_valid() before retrain.
> > > > 
> > > > > > > +		ret = intel_dp_retrain_link(encoder, &ctx);
> > > > > > >  
> > > > > > > -	if (conn_state->commit &&
> > > > > > > -	    !try_wait_for_completion(&conn_state->commit-
> > > > > > > >hw_done))
> > > > > > > -		return;
> > > > > > > +		if (ret == -EDEADLK) {
> > > > > > > +			drm_modeset_backoff(&ctx);
> > > > > > > +			continue;
> > > > > > > +		}
> > > > > > >  
> > > > > > > -	/*
> > > > > > > -	 * Validate the cached values of intel_dp->link_rate and
> > > > > > > -	 * intel_dp->lane_count before attempting to retrain.
> > > > > > > -	 */
> > > > > > > -	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > > > > > link_rate,
> > > > > > > 
> > > > > > > -					intel_dp->lane_count))
> > > > > > > -		return;
> > > > > > > +		break;
> > > > > > > +	}
> > > > > > >  
> > > > > > > -	/* Retrain if Channel EQ or CR not ok */
> > > > > > > -	if (!drm_dp_channel_eq_ok(link_status, intel_dp-
> > > > > > > >lane_count)) 
> > > > > > > {
> > > > > > > -		DRM_DEBUG_KMS("%s: channel EQ not ok,
> > > > > > > retraining\n",
> > > > > > > -			      intel_encoder->base.name);
> > > > > > > +	drm_modeset_drop_locks(&ctx);
> > > > > > > +	drm_modeset_acquire_fini(&ctx);
> > > > > > > +	WARN(ret, "Acquiring modeset locks failed with %i\n",
> > > > > > > ret);
> > > > > > >  
> > > > > > > -		intel_dp_retrain_link(intel_dp);
> > > > > > > -	}
> > > > > > > +	return changed;
> > > > > > >  }
> > > > > > >  
> > > > > > >  /*
> > > > > > > @@ -4400,7 +4469,9 @@ intel_dp_short_pulse(struct intel_dp
> > > > > > > *intel_dp)
> > > > > > >  			DRM_DEBUG_DRIVER("CP or sink specific irq
> > > > > > > unhandled\n");
> > > > > > >  	}
> > > > > > >  
> > > > > > > -	intel_dp_check_link_status(intel_dp);
> > > > > > > +	/* defer to the hotplug work for link retraining if
> > > > > > > needed */
> > > > > > > +	if (intel_dp_needs_link_retrain(intel_dp))
> > > > > > > +		return false;
> > > > > > >  
> > > > > > >  	if (intel_dp->compliance.test_type ==
> > > > > > > DP_TEST_LINK_TRAINING)
> > > > > > > {
> > > > > > >  		DRM_DEBUG_KMS("Link Training Compliance Test
> > > > > > > requested\n");
> > > > > > > @@ -4785,20 +4856,6 @@ intel_dp_long_pulse(struct intel_connector
> > > > > > > *connector)
> > > > > > >  		 */
> > > > > > >  		status = connector_status_disconnected;
> > > > > > >  		goto out;
> > > > > > > -	} else {
> > > > > > > -		/*
> > > > > > > -		 * If display is now connected check links
> > > > > > > status,
> > > > > > > -		 * there has been known issues of link loss
> > > > > > > triggerring
> > > > > > > -		 * long pulse.
> > > > > > > -		 *
> > > > > > > -		 * Some sinks (eg. ASUS PB287Q) seem to perform
> > > > > > > some
> > > > > > > -		 * weird HPD ping pong during modesets. So we can
> > > > > > > apparently
> > > > > > > -		 * end up with HPD going low during a modeset,
> > > > > > > and
> > > > > > > then
> > > > > > > -		 * going back up soon after. And once that
> > > > > > > happens we
> > > > > > > must
> > > > > > > -		 * retrain the link to get a picture. That's in
> > > > > > > case
> > > > > > > no
> > > > > > > -		 * userspace component reacted to intermittent
> > > > > > > HPD
> > > > > > > dip.
> > > > > > > -		 */
> > > > > > > -		intel_dp_check_link_status(intel_dp);
> > > > > > >  	}
> > > > > > >  
> > > > > > >  	/*
> > > > > > > @@ -5340,37 +5397,10 @@ intel_dp_hpd_pulse(struct
> > > > > > > intel_digital_port
> > > > > > > *intel_dig_port, bool long_hpd)
> > > > > > >  	}
> > > > > > >  
> > > > > > >  	if (!intel_dp->is_mst) {
> > > > > > > -		struct drm_modeset_acquire_ctx ctx;
> > > > > > > -		struct drm_connector *connector = &intel_dp-
> > > > > > > > attached_connector->base;
> > > > > > > 
> > > > > > > -		struct drm_crtc *crtc;
> > > > > > > -		int iret;
> > > > > > > -		bool handled = false;
> > > > > > > -
> > > > > > > -		drm_modeset_acquire_init(&ctx, 0);
> > > > > > > -retry:
> > > > > > > -		iret = drm_modeset_lock(&dev_priv-
> > > > > > > > drm.mode_config.connection_mutex, &ctx);
> > > > > > > 
> > > > > > > -		if (iret)
> > > > > > > -			goto err;
> > > > > > > -
> > > > > > > -		crtc = connector->state->crtc;
> > > > > > > -		if (crtc) {
> > > > > > > -			iret = drm_modeset_lock(&crtc->mutex,
> > > > > > > &ctx);
> > > > > > > -			if (iret)
> > > > > > > -				goto err;
> > > > > > > -		}
> > > > > > > +		bool handled;
> > > > > > >  
> > > > > > >  		handled = intel_dp_short_pulse(intel_dp);
> > > > > > >  
> > > > > > > -err:
> > > > > > > -		if (iret == -EDEADLK) {
> > > > > > > -			drm_modeset_backoff(&ctx);
> > > > > > > -			goto retry;
> > > > > > > -		}
> > > > > > > -
> > > > > > > -		drm_modeset_drop_locks(&ctx);
> > > > > > > -		drm_modeset_acquire_fini(&ctx);
> > > > > > > -		WARN(iret, "Acquiring modeset locks failed with
> > > > > > > %i\n", iret);
> > > > > > > -
> > > > > > >  		/* Short pulse can signify loss of hdcp
> > > > > > > authentication */
> > > > > > >  		intel_hdcp_check_link(intel_dp-
> > > > > > > >attached_connector);
> > > > > > >  
> > > > > > > @@ -6400,7 +6430,7 @@ bool intel_dp_init(struct drm_i915_private
> > > > > > > *dev_priv,
> > > > > > >  			     "DP %c", port_name(port)))
> > > > > > >  		goto err_encoder_init;
> > > > > > >  
> > > > > > > -	intel_encoder->hotplug = intel_encoder_hotplug;
> > > > > > > +	intel_encoder->hotplug = intel_dp_hotplug;
> > > > > > >  	intel_encoder->compute_config = intel_dp_compute_config;
> > > > > > >  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
> > > > > > >  	intel_encoder->get_config = intel_dp_get_config;
> > > > > > > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > b/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > index 5ea1dc3f63bf..ddf28a442cd7 100644
> > > > > > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > @@ -1611,6 +1611,8 @@ int
> > > > > > > intel_dp_get_link_train_fallback_values(struct
> > > > > > > intel_dp *intel_dp,
> > > > > > >  					    int link_rate,
> > > > > > > uint8_t
> > > > > > > lane_count);
> > > > > > >  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > > > > > >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> > > > > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > > > > +			  struct drm_modeset_acquire_ctx *ctx);
> > > > > > >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> > > > > > >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > > > > > >  void intel_dp_encoder_suspend(struct intel_encoder
> > > > > > > *intel_encoder);
> > > > > 
> > > > > -- 
> > > > > Ville Syrjälä
> > > > > Intel OTC
> > > > > _______________________________________________
> > > > > Intel-gfx mailing list
> > > > > Intel-gfx@lists.freedesktop.org
> > > > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > > 
> > > -- 
> > > Cheers,
> > > 	Lyude Paul
> -- 
> Cheers,
> 	Lyude Paul
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 5/5] drm/i915: Track whether the DP link is trained or not
  2018-01-17 19:21 ` [PATCH 5/5] drm/i915: Track whether the DP link is trained or not Ville Syrjala
  2018-01-30 23:19   ` Lyude Paul
@ 2018-02-28 20:08   ` Manasi Navare
  1 sibling, 0 replies; 23+ messages in thread
From: Manasi Navare @ 2018-02-28 20:08 UTC (permalink / raw)
  To: Ville Syrjala; +Cc: intel-gfx

On Wed, Jan 17, 2018 at 09:21:49PM +0200, Ville Syrjala wrote:
> From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> 
> LSPCON likes to throw short HPDs during the enable seqeunce prior to the
> link being trained. These obviously result in the channel CR/EQ check
> failing and thus we schedule a pointless hotplug work to retrain the
> link. Avoid that by ignoring the bad CR/EQ status until we've actually
> initially trained the link.
> 
> I've not actually investigated to see what LSPCON is trying to signal
> with the short pulse. But as long as it signals anything I think we're
> supposed to check the link status anyway, so I don't really see other
> good ways to solve this. I've not seen these short pulses being
> generated by normal DP sinks.
>

I agree with avoiding the retraining of the link through these HPDs
when its not trained even for the first time.
The only concern I have here is that we probably shouldnt set the link_trained to true
unless it has been sucessfully trained. So move it to the intel_dp_start_link_train
before failure handling. This will also avoid the case where we are in the retraining
and we get these short HPDs.
Also the link_trained should be set to false in failure_handling in intel_dp_start_link_train()
before scheduling the retry modeset work function.
Thoughts?
 
> Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> ---
>  drivers/gpu/drm/i915/intel_ddi.c              |  2 ++
>  drivers/gpu/drm/i915/intel_dp.c               | 10 +++++++---
>  drivers/gpu/drm/i915/intel_dp_link_training.c |  2 ++
>  drivers/gpu/drm/i915/intel_drv.h              |  1 +
>  4 files changed, 12 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
> index 5f3d58f1ae6e..7a4c5a2d36ed 100644
> --- a/drivers/gpu/drm/i915/intel_ddi.c
> +++ b/drivers/gpu/drm/i915/intel_ddi.c
> @@ -2466,6 +2466,8 @@ static void intel_disable_ddi_dp(struct intel_encoder *encoder,
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  
> +	intel_dp->link_trained = false;
> +
>  	if (old_crtc_state->has_audio)
>  		intel_audio_codec_disable(encoder,
>  					  old_crtc_state, old_conn_state);
> diff --git a/drivers/gpu/drm/i915/intel_dp.c b/drivers/gpu/drm/i915/intel_dp.c
> index 152016e09a11..0cf92aa60f3e 100644
> --- a/drivers/gpu/drm/i915/intel_dp.c
> +++ b/drivers/gpu/drm/i915/intel_dp.c
> @@ -1854,6 +1854,7 @@ void intel_dp_set_link_params(struct intel_dp *intel_dp,
>  			      int link_rate, uint8_t lane_count,
>  			      bool link_mst)
>  {
> +	intel_dp->link_trained = false;
>  	intel_dp->link_rate = link_rate;
>  	intel_dp->lane_count = lane_count;
>  	intel_dp->link_mst = link_mst;
> @@ -2702,6 +2703,8 @@ static void intel_disable_dp(struct intel_encoder *encoder,
>  {
>  	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
>  
> +	intel_dp->link_trained = false;
> +
>  	if (old_crtc_state->has_audio)
>  		intel_audio_codec_disable(encoder,
>  					  old_crtc_state, old_conn_state);
> @@ -4280,10 +4283,11 @@ intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
>  {
>  	u8 link_status[DP_LINK_STATUS_SIZE];
>  
> -	if (!intel_dp_get_link_status(intel_dp, link_status)) {
> -		DRM_ERROR("Failed to get link status\n");
> +	if (!intel_dp->link_trained)
> +		return false;
> +
> +	if (!intel_dp_get_link_status(intel_dp, link_status))
>  		return false;
> -	}
>  
>  	/*
>  	 * Validate the cached values of intel_dp->link_rate and
> diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> index 1314f5d87d7d..78f1fe934da3 100644
> --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> @@ -307,6 +307,8 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
>  
>  void intel_dp_stop_link_train(struct intel_dp *intel_dp)
>  {
> +	intel_dp->link_trained = true;
> +

Move to intel_dp_start_link_train() on successful link train?

Manasi

>  	intel_dp_set_link_train(intel_dp,
>  				DP_TRAINING_PATTERN_DISABLE);
>  }
> diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> index 1d018869ad02..7a45ffb9e524 100644
> --- a/drivers/gpu/drm/i915/intel_drv.h
> +++ b/drivers/gpu/drm/i915/intel_drv.h
> @@ -1043,6 +1043,7 @@ struct intel_dp {
>  	uint8_t lane_count;
>  	uint8_t sink_count;
>  	bool link_mst;
> +	bool link_trained;
>  	bool has_audio;
>  	bool detect_done;
>  	bool reset_link_params;
> -- 
> 2.13.6
> 
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
  2018-02-28 19:57               ` Manasi Navare
@ 2018-02-28 20:10                 ` Lyude Paul
  2018-03-05 23:41                   ` Manasi Navare
  0 siblings, 1 reply; 23+ messages in thread
From: Lyude Paul @ 2018-02-28 20:10 UTC (permalink / raw)
  To: Manasi Navare; +Cc: intel-gfx

On Wed, 2018-02-28 at 11:57 -0800, Manasi Navare wrote:
> On Wed, Feb 28, 2018 at 02:41:06PM -0500, Lyude Paul wrote:
> > On Wed, 2018-02-28 at 11:27 -0800, Manasi Navare wrote:
> > > On Wed, Feb 28, 2018 at 02:07:34PM -0500, Lyude Paul wrote:
> > > > 
> > > > On Tue, 2018-02-27 at 23:17 -0800, Manasi Navare wrote:
> > > > > Ville,  thanks for the patch and
> > > > > Sorry for not being able to review this earlier.
> > > > > Please find some comments below:
> > > > > 
> > > > > On Wed, Jan 31, 2018 at 03:27:10PM +0200, Ville Syrjälä wrote:
> > > > > > On Tue, Jan 30, 2018 at 06:16:59PM -0500, Lyude Paul wrote:
> > > > > > > On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> > > > > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > > > 
> > > > > > > > Doing link retraining from the short pulse handler is
> > > > > > > > problematic
> > > > > > > > since
> > > > > > > > that might introduce deadlocks with MST sideband processing.
> > > > > > > > Currently
> > > > > > > > we don't retrain MST links from this code, but we want to
> > > > > > > > change
> > > > > > > > that.
> > > > > > > > So better to move the entire thing to the hotplug work. We can
> > > > > > > > utilize
> > > > > > > > the new encoder->hotplug() hook for this.
> > > > > > > > 
> > > > > > > > The only thing we leave in the short pulse handler is the link
> > > > > > > > status
> > > > > > > > check. That one still depends on the link parameters stored
> > > > > > > > under
> > > > > > > > intel_dp, so no locking around that but races should be mostly
> > > > > > > > harmless
> > > > > > > > as the actual retraining code will recheck the link state if
> > > > > > > > we
> > > > > > > > end up there by mistake.
> > > > > > > > 
> > > > > > > > v2: Rebase due to ->post_hotplug() now being just ->hotplug()
> > > > > > > >     Check the connector type to figure out if we should do
> > > > > > > >     the HDMI thing or the DP think for DDI
> > > > > > > > 
> > > > > > > > Cc: Manasi Navare <manasi.d.navare@intel.com>
> > > > > > > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > > > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > > > ---
> > > > > > > >  drivers/gpu/drm/i915/intel_ddi.c |  10 +-
> > > > > > > >  drivers/gpu/drm/i915/intel_dp.c  | 196
> > > > > > > > ++++++++++++++++++++++--
> > > > > > > > ----
> > > > > > > > --------
> > > > > > > > ---
> > > > > > > >  drivers/gpu/drm/i915/intel_drv.h |   2 +
> > > > > > > >  3 files changed, 120 insertions(+), 88 deletions(-)
> > > > > > > > 
> > > > > > > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > > b/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > > index 25793bdc692f..5f3d58f1ae6e 100644
> > > > > > > > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > > @@ -2880,7 +2880,10 @@ static bool intel_ddi_hotplug(struct
> > > > > > > > intel_encoder
> > > > > > > > *encoder,
> > > > > > > >  	drm_modeset_acquire_init(&ctx, 0);
> > > > > > > >  
> > > > > > > >  	for (;;) {
> > > > > > > > -		ret = intel_hdmi_reset_link(encoder, &ctx);
> > > > > > > > +		if (connector->base.connector_type ==
> > > > > > > > DRM_MODE_CONNECTOR_HDMIA)
> > > > > > > > +			ret = intel_hdmi_reset_link(encoder,
> > > > > > > > &ctx);
> > > > > > > > +		else
> > > > > > > > +			ret = intel_dp_retrain_link(encoder,
> > > > > > > > &ctx);
> > > > > > > >  
> > > > > > > >  		if (ret == -EDEADLK) {
> > > > > > > >  			drm_modeset_backoff(&ctx);
> > > > > > > > @@ -3007,10 +3010,7 @@ void intel_ddi_init(struct
> > > > > > > > drm_i915_private
> > > > > > > > *dev_priv,
> > > > > > > > enum port port)
> > > > > > > >  	drm_encoder_init(&dev_priv->drm, encoder,
> > > > > > > > &intel_ddi_funcs,
> > > > > > > >  			 DRM_MODE_ENCODER_TMDS, "DDI %c",
> > > > > > > > port_name(port));
> > > > > > > >  
> > > > > > > > -	if (init_hdmi)
> > > > > > > > -		intel_encoder->hotplug = intel_ddi_hotplug;
> > > > > > > > -	else
> > > > > > > > -		intel_encoder->hotplug =
> > > > > > > > intel_encoder_hotplug;
> > > > > > > > +	intel_encoder->hotplug = intel_ddi_hotplug;
> > > > > > > >  	intel_encoder->compute_output_type =
> > > > > > > > intel_ddi_compute_output_type;
> > > > > > > >  	intel_encoder->compute_config =
> > > > > > > > intel_ddi_compute_config;
> > > > > > > >  	intel_encoder->enable = intel_enable_ddi;
> > > > > > > > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > > b/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > > index 6bbf14410c2a..152016e09a11 100644
> > > > > > > > --- a/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > > @@ -4275,12 +4275,83 @@ intel_dp_check_mst_status(struct
> > > > > > > > intel_dp
> > > > > > > > *intel_dp)
> > > > > > > >  	return -EINVAL;
> > > > > > > >  }
> > > > > > > >  
> > > > > > > > -static void
> > > > > > > > -intel_dp_retrain_link(struct intel_dp *intel_dp)
> > > > > > > > +static bool
> > > > > > > > +intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
> > > > > > > > +{
> > > > > > > > +	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > > > > > +
> > > > > > > > +	if (!intel_dp_get_link_status(intel_dp, link_status))
> > > > > > > > {
> > > > > > > > +		DRM_ERROR("Failed to get link status\n");
> > > > > > > > +		return false;
> > > > > > > > +	}
> > > > > > > > +
> > > > > > > > +	/*
> > > > > > > > +	 * Validate the cached values of intel_dp->link_rate
> > > > > > > > and
> > > > > > > > +	 * intel_dp->lane_count before attempting to retrain.
> > > > > > > > +	 */
> > > > > > > > +	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > > > > > > link_rate,
> > > > > > > > 
> > > > > > > > +					intel_dp-
> > > > > > > > >lane_count))
> > > > > > > > +		return false;
> > > > > > > > +
> > > > > > > > +	/* Retrain if Channel EQ or CR not ok */
> > > > > > > > +	return !drm_dp_channel_eq_ok(link_status, intel_dp-
> > > > > > > > > lane_count);
> > > > > > > > 
> > > > > > > > +}
> > > > > > > > +
> > > > > > > > +/*
> > > > > > > > + * If display is now connected check links status,
> > > > > > > > + * there has been known issues of link loss triggering
> > > > > > > > + * long pulse.
> > > > > > > > + *
> > > > > > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > > > > > + * end up with HPD going low during a modeset, and then
> > > > > > > > + * going back up soon after. And once that happens we must
> > > > > > > > + * retrain the link to get a picture. That's in case no
> > > > > > > > + * userspace component reacted to intermittent HPD dip.
> > > > > > > > + */
> > > > > > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > > > > > +			  struct drm_modeset_acquire_ctx
> > > > > > > > *ctx)
> > > > > > > >  {
> > > > > > > > -	struct intel_encoder *encoder =
> > > > > > > > &dp_to_dig_port(intel_dp)-
> > > > > > > > > base;
> > > > > > > > 
> > > > > > > >  	struct drm_i915_private *dev_priv = to_i915(encoder-
> > > > > > > > > base.dev);
> > > > > > > > 
> > > > > > > > -	struct intel_crtc *crtc = to_intel_crtc(encoder-
> > > > > > > > > base.crtc);
> > > > > > > > 
> > > > > > > > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder-
> > > > > > > > > base);
> > > > > > > > 
> > > > > > > > +	struct intel_connector *connector = intel_dp-
> > > > > > > > > attached_connector;
> > > > > > > > 
> > > > > > > > +	struct drm_connector_state *conn_state;
> > > > > > > > +	struct intel_crtc_state *crtc_state;
> > > > > > > > +	struct intel_crtc *crtc;
> > > > > > > > +	int ret;
> > > > > > > > +
> > > > > > > > +	/* FIXME handle the MST connectors as well */
> > > > > > > > +
> > > > > > > > +	if (!connector || connector->base.status !=
> > > > > > > > connector_status_connected)
> > > > > > > > +		return 0;
> > > > > > > > +
> > > > > > > > +	ret = drm_modeset_lock(&dev_priv-
> > > > > > > > > drm.mode_config.connection_mutex,
> > > > > > > > 
> > > > > > > > ctx);
> > > > > > > > +	if (ret)
> > > > > > > > +		return ret;
> > > > > > > > +
> > > > > > > > +	conn_state = connector->base.state;
> > > > > > > > +
> > > > > > > > +	crtc = to_intel_crtc(conn_state->crtc);
> > > > > > > > +	if (!crtc)
> > > > > > > > +		return 0;
> > > > > > > > +
> > > > > > > > +	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
> > > > > > > > +	if (ret)
> > > > > > > > +		return ret;
> > > > > > > > +
> > > > > > > > +	crtc_state = to_intel_crtc_state(crtc->base.state);
> > > > > > > > +
> > > > > > > > +	WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
> > > > > > > > +
> > > > > > > > +	if (!crtc_state->base.active)
> > > > > > > > +		return 0;
> > > > > > > > +
> > > > > > > > +	if (conn_state->commit &&
> > > > > > > > +	    !try_wait_for_completion(&conn_state->commit-
> > > > > > > > > hw_done))
> > > > > > > > 
> > > > > > > > +		return 0;
> > > > > > > > +
> > > > > > > > +	if (!intel_dp_needs_link_retrain(intel_dp))
> > > > > > > > +		return 0;
> > > > > > > 
> > > > > > > NAK, this definitely won't work for implementing MST retraining.
> > > > > > > There's
> > > > > > > some
> > > > > > > pretty huge differences with how retraining needs to be handled
> > > > > > > on
> > > > > > > SST
> > > > > > > vs. MST.
> > > > > > > An example with some normal SST sink vs. what happens on my
> > > > > > > caldigit
> > > > > > > TS3
> > > > > > > 
> > > > > > > SST:
> > > > > > >     1. commit modeset, everything is OK
> > > > > > >     2. something happens, sink sends shortpulse and changes link
> > > > > > > status
> > > > > > > registers
> > > > > > >     in dpcd
> > > > > > >     3. Source receives short pulse, tries retraining five times
> > > > > > >     4. if this succeeds:
> > > > > > >         5. we're done here
> > > > > > >     6. if this fails:
> > > > > > >         7. mark link status as bad
> > > > > > >         8. get fallback parameters
> > > > > > >         9. hotplug event
> > > > > > > 
> > > > > > > MST (i915 doesn't do this yet, but this is generally how it
> > > > > > > needs to
> > > > > > > be
> > > > > > > handled):
> > > > > > >     1. commit modeset, everything is OK
> > > > > > >     2. something happens (in my case, the MST hub discovers it
> > > > > > > had
> > > > > > > the
> > > > > > > wrong max
> > > > > > >     link rate/lane count), sink sends ESI indicating channel EQ
> > > > > > > has
> > > > > > > failed
> > > > > > >     3. retraining commences with five retries.
> > > > > > >     4. if this succeeds:
> > > > > > >        5. continue
> > > > > > >     6. if this fails (I actually haven't seen this once yet)
> > > > > > >         7. mark link status as bad on all downstream connectors
> > > > > > >         8. get fallback parameters
> > > > > > >         9. hotplug event
> > > > > > >     10. the retrain didn't actually work (despite what the SST
> > > > > > > link
> > > > > > > status
> > > > > > >     registers told us). go back to step 3 five more times
> > > > > > >     11. if this fails:
> > > > > > >         12. mark link status as bad on all downstream connectors
> > > > > > >         13. get fallback parameters
> > > > > > >         14. hotplug event
> > > > > > > 
> > > > > > > simply put: we really should keep the "do we need to retrain?"
> > > > > > > logic
> > > > > > > out
> > > > > > > of the
> > > > > > > actual retraining helpers so that SST/MST codepaths can do their
> > > > > > > own
> > > > > > > checks to
> > > > > > > figure this out.
> > > > > > 
> > > > > > No, we need it since we want to check it *after* any modeset has
> > > > > > finished. With MST I think what we'll want to do is find all the
> > > > > > pipes
> > > > > > affected by the link failure, lock them, and wait until they're
> > > > > > done
> > > > > > with their modesets, then we check the link state. If it's bad we
> > > > > > proceed to retrain the link.
> > > > > > 
> > > > > > So basically just walking over the MST encoders in addition to the
> > > > > > SST encoder, and repeating most of the steps in this code for
> > > > > > each.
> > > > > > Hence the the MST FIXME I left in there ;)
> > > > > > 
> > > > > 
> > > > > Lyude,
> > > > > 
> > > > > I agree with Ville here, can we add the MST retrain required check
> > > > > from
> > > > > within the intel_dp_retrain_link()? So for now the FIXME should be
> > > > > left
> > > > > there
> > > > > and MST retraining check can be added from your patches.
> > > > > 
> > > > > Manasi
> > > > 
> > > > Yep! Sorry I probably should have reiterated this part over email
> > > > since I
> > > > only
> > > > mentioned it to ville directly: this part should definitely work fine,
> > > > and
> > > > intel_dp_retrain_link() is actually where we handle MST retraining in
> > > > the
> > > > latest version of the retraining series:
> > > > 
> > > > jfyi, you can find that here:
> > > > https://github.com/Lyude/linux/tree/wip/i915-mst-fallback-a4
> > > > It's almost ready for the ML, just want to get the other patches this
> > > > is
> > > > going
> > > > to rely on in first and fix some small concerns I've got about that
> > > > series'
> > > > current implementation of handling modesets after a failed retrain
> > > > sequence
> > > > > 
> > > 
> > > Great!
> > > After the failed retrain sequence, it will keep on retrying until has
> > > tried
> > > all
> > > the link rate/lane count combinations until RBR 1 lane and then fail
> > > with a
> > > ERROR message.
> > > What was the concern on the current implementation of modeste after
> > > failed
> > > retrain?
> > 
> > I actually take that back. Was worried that not freeing existing VCPI
> > allocations during the first atomic check phase for the first modeset
> > after a
> > retrain failure might cause atomic checks to fail from not having enough
> > VCPI 
> > space, but then I realized that wouldn't matter since if we're not able to
> > fit
> > one display into the VCPI with a reduced pbn_div, that just means fitting
> > both
> > displays with a reduced pbn_div would also be impossible :P.
> > 
> 
> But then in that case, in oredr to retry at lower link rates, both these
> monitors will
> have to drop to the next lower resolutions to fit the reduced pbn_div.

Yep, that's the idea! In which case the atomic check should fail, which should
cause userspace to try at a reduced resolution or take some other reparative
action
> 
> Manasi
>  
> > > 
> > > Manasi
> > >  
> > > > > > > 
> > > > > > > >  
> > > > > > > >  	/* Suppress underruns caused by re-training */
> > > > > > > >  	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc-
> > > > > > > > > pipe,
> > > > > > > > 
> > > > > > > > false);
> > > > > > > > @@ -4298,51 +4369,49 @@ intel_dp_retrain_link(struct intel_dp
> > > > > > > > *intel_dp)
> > > > > > > >  	if (crtc->config->has_pch_encoder)
> > > > > > > >  		intel_set_pch_fifo_underrun_reporting(dev_pri
> > > > > > > > v,
> > > > > > > >  						      intel_c
> > > > > > > > rtc_
> > > > > > > > pch_
> > > > > > > > transcod
> > > > > > > > er(crtc), true);
> > > > > > > > +
> > > > > > > > +	return 0;
> > > > > > > >  }
> > > > > > > >  
> > > > > > > > -static void
> > > > > > > > -intel_dp_check_link_status(struct intel_dp *intel_dp)
> > > > > > > > +/*
> > > > > > > > + * If display is now connected check links status,
> > > > > > > > + * there has been known issues of link loss triggering
> > > > > > > > + * long pulse.
> > > > > > > > + *
> > > > > > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > > > > > + * end up with HPD going low during a modeset, and then
> > > > > > > > + * going back up soon after. And once that happens we must
> > > > > > > > + * retrain the link to get a picture. That's in case no
> > > > > > > > + * userspace component reacted to intermittent HPD dip.
> > > > > > > > + */
> > > > > > > > +static bool intel_dp_hotplug(struct intel_encoder *encoder,
> > > > > > > > +			     struct intel_connector
> > > > > > > > *connector)
> > > > > > > >  {
> > > > > > > > -	struct drm_i915_private *dev_priv =
> > > > > > > > to_i915(intel_dp_to_dev(intel_dp));
> > > > > > > > -	struct intel_encoder *intel_encoder =
> > > > > > > > &dp_to_dig_port(intel_dp)-
> > > > > > > > > base;
> > > > > > > > 
> > > > > > > > -	struct drm_connector_state *conn_state =
> > > > > > > > -		intel_dp->attached_connector->base.state;
> > > > > > > > -	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > > > > > -
> > > > > > > > -	WARN_ON(!drm_modeset_is_locked(&dev_priv-
> > > > > > > > > drm.mode_config.connection_mutex));
> > > > > > > > 
> > > > > > > > -
> > > > > > > > -	if (!intel_dp_get_link_status(intel_dp, link_status))
> > > > > > > > {
> > > > > > > > -		DRM_ERROR("Failed to get link status\n");
> > > > > > > > -		return;
> > > > > > > > -	}
> > > > > > > > +	struct drm_modeset_acquire_ctx ctx;
> > > > > > > > +	bool changed;
> > > > > > > > +	int ret;
> > > > > > > >  
> > > > > > > > -	if (!conn_state->crtc)
> > > > > > > > -		return;
> > > > > > > > +	changed = intel_encoder_hotplug(encoder, connector);
> > > > > > > >  
> > > > > > > > -	WARN_ON(!drm_modeset_is_locked(&conn_state->crtc-
> > > > > > > > > mutex));
> > > > > > > > 
> > > > > > > > +	drm_modeset_acquire_init(&ctx, 0);
> > > > > > > >  
> > > > > > > > -	if (!conn_state->crtc->state->active)
> > > > > > > > -		return;
> > > > > > > > +	for (;;) {
> > > > > 
> > > > > Here if this is getting executed due to hpd ping pong during the
> > > > > modeset
> > > > > and that modeset is already happening at a link fallback parameter
> > > > > then
> > > > > while we call retrain link, we should also validate the link
> > > > > parameters
> > > > > so that it doesnt try to retrain with stale values.
> > > > > 
> > > > > I think we need to call intel_dp_link_params_valid() before retrain.
> > > > > 
> > > > > > > > +		ret = intel_dp_retrain_link(encoder, &ctx);
> > > > > > > >  
> > > > > > > > -	if (conn_state->commit &&
> > > > > > > > -	    !try_wait_for_completion(&conn_state->commit-
> > > > > > > > > hw_done))
> > > > > > > > 
> > > > > > > > -		return;
> > > > > > > > +		if (ret == -EDEADLK) {
> > > > > > > > +			drm_modeset_backoff(&ctx);
> > > > > > > > +			continue;
> > > > > > > > +		}
> > > > > > > >  
> > > > > > > > -	/*
> > > > > > > > -	 * Validate the cached values of intel_dp->link_rate
> > > > > > > > and
> > > > > > > > -	 * intel_dp->lane_count before attempting to retrain.
> > > > > > > > -	 */
> > > > > > > > -	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > > > > > > link_rate,
> > > > > > > > 
> > > > > > > > -					intel_dp-
> > > > > > > > >lane_count))
> > > > > > > > -		return;
> > > > > > > > +		break;
> > > > > > > > +	}
> > > > > > > >  
> > > > > > > > -	/* Retrain if Channel EQ or CR not ok */
> > > > > > > > -	if (!drm_dp_channel_eq_ok(link_status, intel_dp-
> > > > > > > > > lane_count)) 
> > > > > > > > 
> > > > > > > > {
> > > > > > > > -		DRM_DEBUG_KMS("%s: channel EQ not ok,
> > > > > > > > retraining\n",
> > > > > > > > -			      intel_encoder->base.name);
> > > > > > > > +	drm_modeset_drop_locks(&ctx);
> > > > > > > > +	drm_modeset_acquire_fini(&ctx);
> > > > > > > > +	WARN(ret, "Acquiring modeset locks failed with %i\n",
> > > > > > > > ret);
> > > > > > > >  
> > > > > > > > -		intel_dp_retrain_link(intel_dp);
> > > > > > > > -	}
> > > > > > > > +	return changed;
> > > > > > > >  }
> > > > > > > >  
> > > > > > > >  /*
> > > > > > > > @@ -4400,7 +4469,9 @@ intel_dp_short_pulse(struct intel_dp
> > > > > > > > *intel_dp)
> > > > > > > >  			DRM_DEBUG_DRIVER("CP or sink specific
> > > > > > > > irq
> > > > > > > > unhandled\n");
> > > > > > > >  	}
> > > > > > > >  
> > > > > > > > -	intel_dp_check_link_status(intel_dp);
> > > > > > > > +	/* defer to the hotplug work for link retraining if
> > > > > > > > needed */
> > > > > > > > +	if (intel_dp_needs_link_retrain(intel_dp))
> > > > > > > > +		return false;
> > > > > > > >  
> > > > > > > >  	if (intel_dp->compliance.test_type ==
> > > > > > > > DP_TEST_LINK_TRAINING)
> > > > > > > > {
> > > > > > > >  		DRM_DEBUG_KMS("Link Training Compliance Test
> > > > > > > > requested\n");
> > > > > > > > @@ -4785,20 +4856,6 @@ intel_dp_long_pulse(struct
> > > > > > > > intel_connector
> > > > > > > > *connector)
> > > > > > > >  		 */
> > > > > > > >  		status = connector_status_disconnected;
> > > > > > > >  		goto out;
> > > > > > > > -	} else {
> > > > > > > > -		/*
> > > > > > > > -		 * If display is now connected check links
> > > > > > > > status,
> > > > > > > > -		 * there has been known issues of link loss
> > > > > > > > triggerring
> > > > > > > > -		 * long pulse.
> > > > > > > > -		 *
> > > > > > > > -		 * Some sinks (eg. ASUS PB287Q) seem to
> > > > > > > > perform
> > > > > > > > some
> > > > > > > > -		 * weird HPD ping pong during modesets. So we
> > > > > > > > can
> > > > > > > > apparently
> > > > > > > > -		 * end up with HPD going low during a
> > > > > > > > modeset,
> > > > > > > > and
> > > > > > > > then
> > > > > > > > -		 * going back up soon after. And once that
> > > > > > > > happens we
> > > > > > > > must
> > > > > > > > -		 * retrain the link to get a picture. That's
> > > > > > > > in
> > > > > > > > case
> > > > > > > > no
> > > > > > > > -		 * userspace component reacted to
> > > > > > > > intermittent
> > > > > > > > HPD
> > > > > > > > dip.
> > > > > > > > -		 */
> > > > > > > > -		intel_dp_check_link_status(intel_dp);
> > > > > > > >  	}
> > > > > > > >  
> > > > > > > >  	/*
> > > > > > > > @@ -5340,37 +5397,10 @@ intel_dp_hpd_pulse(struct
> > > > > > > > intel_digital_port
> > > > > > > > *intel_dig_port, bool long_hpd)
> > > > > > > >  	}
> > > > > > > >  
> > > > > > > >  	if (!intel_dp->is_mst) {
> > > > > > > > -		struct drm_modeset_acquire_ctx ctx;
> > > > > > > > -		struct drm_connector *connector = &intel_dp-
> > > > > > > > > attached_connector->base;
> > > > > > > > 
> > > > > > > > -		struct drm_crtc *crtc;
> > > > > > > > -		int iret;
> > > > > > > > -		bool handled = false;
> > > > > > > > -
> > > > > > > > -		drm_modeset_acquire_init(&ctx, 0);
> > > > > > > > -retry:
> > > > > > > > -		iret = drm_modeset_lock(&dev_priv-
> > > > > > > > > drm.mode_config.connection_mutex, &ctx);
> > > > > > > > 
> > > > > > > > -		if (iret)
> > > > > > > > -			goto err;
> > > > > > > > -
> > > > > > > > -		crtc = connector->state->crtc;
> > > > > > > > -		if (crtc) {
> > > > > > > > -			iret = drm_modeset_lock(&crtc->mutex,
> > > > > > > > &ctx);
> > > > > > > > -			if (iret)
> > > > > > > > -				goto err;
> > > > > > > > -		}
> > > > > > > > +		bool handled;
> > > > > > > >  
> > > > > > > >  		handled = intel_dp_short_pulse(intel_dp);
> > > > > > > >  
> > > > > > > > -err:
> > > > > > > > -		if (iret == -EDEADLK) {
> > > > > > > > -			drm_modeset_backoff(&ctx);
> > > > > > > > -			goto retry;
> > > > > > > > -		}
> > > > > > > > -
> > > > > > > > -		drm_modeset_drop_locks(&ctx);
> > > > > > > > -		drm_modeset_acquire_fini(&ctx);
> > > > > > > > -		WARN(iret, "Acquiring modeset locks failed
> > > > > > > > with
> > > > > > > > %i\n", iret);
> > > > > > > > -
> > > > > > > >  		/* Short pulse can signify loss of hdcp
> > > > > > > > authentication */
> > > > > > > >  		intel_hdcp_check_link(intel_dp-
> > > > > > > > > attached_connector);
> > > > > > > > 
> > > > > > > >  
> > > > > > > > @@ -6400,7 +6430,7 @@ bool intel_dp_init(struct
> > > > > > > > drm_i915_private
> > > > > > > > *dev_priv,
> > > > > > > >  			     "DP %c", port_name(port)))
> > > > > > > >  		goto err_encoder_init;
> > > > > > > >  
> > > > > > > > -	intel_encoder->hotplug = intel_encoder_hotplug;
> > > > > > > > +	intel_encoder->hotplug = intel_dp_hotplug;
> > > > > > > >  	intel_encoder->compute_config =
> > > > > > > > intel_dp_compute_config;
> > > > > > > >  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
> > > > > > > >  	intel_encoder->get_config = intel_dp_get_config;
> > > > > > > > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > > b/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > > index 5ea1dc3f63bf..ddf28a442cd7 100644
> > > > > > > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > > @@ -1611,6 +1611,8 @@ int
> > > > > > > > intel_dp_get_link_train_fallback_values(struct
> > > > > > > > intel_dp *intel_dp,
> > > > > > > >  					    int link_rate,
> > > > > > > > uint8_t
> > > > > > > > lane_count);
> > > > > > > >  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > > > > > > >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> > > > > > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > > > > > +			  struct drm_modeset_acquire_ctx
> > > > > > > > *ctx);
> > > > > > > >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> > > > > > > >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > > > > > > >  void intel_dp_encoder_suspend(struct intel_encoder
> > > > > > > > *intel_encoder);
> > > > > > 
> > > > > > -- 
> > > > > > Ville Syrjälä
> > > > > > Intel OTC
> > > > > > _______________________________________________
> > > > > > Intel-gfx mailing list
> > > > > > Intel-gfx@lists.freedesktop.org
> > > > > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > > > 
> > > > -- 
> > > > Cheers,
> > > > 	Lyude Paul
> > 
> > -- 
> > Cheers,
> > 	Lyude Paul
-- 
Cheers,
	Lyude Paul
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH 4/5] drm/i915: Nuke intel_dp->channel_eq_status
  2018-01-19  6:59   ` Rodrigo Vivi
@ 2018-02-28 20:12     ` Manasi Navare
  0 siblings, 0 replies; 23+ messages in thread
From: Manasi Navare @ 2018-02-28 20:12 UTC (permalink / raw)
  To: Rodrigo Vivi; +Cc: intel-gfx

On Thu, Jan 18, 2018 at 10:59:04PM -0800, Rodrigo Vivi wrote:
> On Wed, Jan 17, 2018 at 07:21:48PM +0000, Ville Syrjala wrote:
> > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > 
> > intel_dp->channel_eq_status is used in exactly one function, and we
> > don't need it to persist between calls. So just go back to using a
> > local variable instead.
> > 
> > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>

Reviewed-by: Manasi Navare <manasi.d.navare@intel.com>

> 
> Reviewed-by: Rodrigo Vivi <rodrigo.vivi@intel.com>
> 
> > ---
> >  drivers/gpu/drm/i915/intel_dp_link_training.c | 6 +++---
> >  drivers/gpu/drm/i915/intel_drv.h              | 1 -
> >  2 files changed, 3 insertions(+), 4 deletions(-)
> > 
> > diff --git a/drivers/gpu/drm/i915/intel_dp_link_training.c b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > index 05907fa8a553..1314f5d87d7d 100644
> > --- a/drivers/gpu/drm/i915/intel_dp_link_training.c
> > +++ b/drivers/gpu/drm/i915/intel_dp_link_training.c
> > @@ -248,6 +248,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> >  	int tries;
> >  	u32 training_pattern;
> >  	uint8_t link_status[DP_LINK_STATUS_SIZE];
> > +	bool channel_eq = false;
> >  
> >  	training_pattern = intel_dp_training_pattern(intel_dp);
> >  
> > @@ -259,7 +260,6 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> >  		return false;
> >  	}
> >  
> > -	intel_dp->channel_eq_status = false;
> >  	for (tries = 0; tries < 5; tries++) {
> >  
> >  		drm_dp_link_train_channel_eq_delay(intel_dp->dpcd);
> > @@ -279,7 +279,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> >  
> >  		if (drm_dp_channel_eq_ok(link_status,
> >  					 intel_dp->lane_count)) {
> > -			intel_dp->channel_eq_status = true;
> > +			channel_eq = true;
> >  			DRM_DEBUG_KMS("Channel EQ done. DP Training "
> >  				      "successful\n");
> >  			break;
> > @@ -301,7 +301,7 @@ intel_dp_link_training_channel_equalization(struct intel_dp *intel_dp)
> >  
> >  	intel_dp_set_idle_link_train(intel_dp);
> >  
> > -	return intel_dp->channel_eq_status;
> > +	return channel_eq;
> >  
> >  }
> >  
> > diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h
> > index ddf28a442cd7..1d018869ad02 100644
> > --- a/drivers/gpu/drm/i915/intel_drv.h
> > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > @@ -1045,7 +1045,6 @@ struct intel_dp {
> >  	bool link_mst;
> >  	bool has_audio;
> >  	bool detect_done;
> > -	bool channel_eq_status;
> >  	bool reset_link_params;
> >  	uint8_t dpcd[DP_RECEIVER_CAP_SIZE];
> >  	uint8_t psr_dpcd[EDP_PSR_RECEIVER_CAP_SIZE];
> > -- 
> > 2.13.6
> > 
> > _______________________________________________
> > Intel-gfx mailing list
> > Intel-gfx@lists.freedesktop.org
> > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> _______________________________________________
> Intel-gfx mailing list
> Intel-gfx@lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/intel-gfx
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
  2018-02-28 20:10                 ` Lyude Paul
@ 2018-03-05 23:41                   ` Manasi Navare
  0 siblings, 0 replies; 23+ messages in thread
From: Manasi Navare @ 2018-03-05 23:41 UTC (permalink / raw)
  To: Lyude Paul; +Cc: intel-gfx

On Wed, Feb 28, 2018 at 03:10:24PM -0500, Lyude Paul wrote:
> On Wed, 2018-02-28 at 11:57 -0800, Manasi Navare wrote:
> > On Wed, Feb 28, 2018 at 02:41:06PM -0500, Lyude Paul wrote:
> > > On Wed, 2018-02-28 at 11:27 -0800, Manasi Navare wrote:
> > > > On Wed, Feb 28, 2018 at 02:07:34PM -0500, Lyude Paul wrote:
> > > > > 
> > > > > On Tue, 2018-02-27 at 23:17 -0800, Manasi Navare wrote:
> > > > > > Ville,  thanks for the patch and
> > > > > > Sorry for not being able to review this earlier.
> > > > > > Please find some comments below:
> > > > > > 
> > > > > > On Wed, Jan 31, 2018 at 03:27:10PM +0200, Ville Syrjälä wrote:
> > > > > > > On Tue, Jan 30, 2018 at 06:16:59PM -0500, Lyude Paul wrote:
> > > > > > > > On Wed, 2018-01-17 at 21:21 +0200, Ville Syrjala wrote:
> > > > > > > > > From: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > > > > 
> > > > > > > > > Doing link retraining from the short pulse handler is
> > > > > > > > > problematic
> > > > > > > > > since
> > > > > > > > > that might introduce deadlocks with MST sideband processing.
> > > > > > > > > Currently
> > > > > > > > > we don't retrain MST links from this code, but we want to
> > > > > > > > > change
> > > > > > > > > that.
> > > > > > > > > So better to move the entire thing to the hotplug work. We can
> > > > > > > > > utilize
> > > > > > > > > the new encoder->hotplug() hook for this.
> > > > > > > > > 
> > > > > > > > > The only thing we leave in the short pulse handler is the link
> > > > > > > > > status
> > > > > > > > > check. That one still depends on the link parameters stored
> > > > > > > > > under
> > > > > > > > > intel_dp, so no locking around that but races should be mostly
> > > > > > > > > harmless
> > > > > > > > > as the actual retraining code will recheck the link state if
> > > > > > > > > we
> > > > > > > > > end up there by mistake.
> > > > > > > > > 
> > > > > > > > > v2: Rebase due to ->post_hotplug() now being just ->hotplug()
> > > > > > > > >     Check the connector type to figure out if we should do
> > > > > > > > >     the HDMI thing or the DP think for DDI
> > > > > > > > > 
> > > > > > > > > Cc: Manasi Navare <manasi.d.navare@intel.com>
> > > > > > > > > Cc: Maarten Lankhorst <maarten.lankhorst@linux.intel.com>
> > > > > > > > > Signed-off-by: Ville Syrjälä <ville.syrjala@linux.intel.com>
> > > > > > > > > ---
> > > > > > > > >  drivers/gpu/drm/i915/intel_ddi.c |  10 +-
> > > > > > > > >  drivers/gpu/drm/i915/intel_dp.c  | 196
> > > > > > > > > ++++++++++++++++++++++--
> > > > > > > > > ----
> > > > > > > > > --------
> > > > > > > > > ---
> > > > > > > > >  drivers/gpu/drm/i915/intel_drv.h |   2 +
> > > > > > > > >  3 files changed, 120 insertions(+), 88 deletions(-)
> > > > > > > > > 
> > > > > > > > > diff --git a/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > > > b/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > > > index 25793bdc692f..5f3d58f1ae6e 100644
> > > > > > > > > --- a/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > > > +++ b/drivers/gpu/drm/i915/intel_ddi.c
> > > > > > > > > @@ -2880,7 +2880,10 @@ static bool intel_ddi_hotplug(struct
> > > > > > > > > intel_encoder
> > > > > > > > > *encoder,
> > > > > > > > >  	drm_modeset_acquire_init(&ctx, 0);
> > > > > > > > >  
> > > > > > > > >  	for (;;) {
> > > > > > > > > -		ret = intel_hdmi_reset_link(encoder, &ctx);
> > > > > > > > > +		if (connector->base.connector_type ==
> > > > > > > > > DRM_MODE_CONNECTOR_HDMIA)
> > > > > > > > > +			ret = intel_hdmi_reset_link(encoder,
> > > > > > > > > &ctx);
> > > > > > > > > +		else
> > > > > > > > > +			ret = intel_dp_retrain_link(encoder,
> > > > > > > > > &ctx);
> > > > > > > > >  
> > > > > > > > >  		if (ret == -EDEADLK) {
> > > > > > > > >  			drm_modeset_backoff(&ctx);
> > > > > > > > > @@ -3007,10 +3010,7 @@ void intel_ddi_init(struct
> > > > > > > > > drm_i915_private
> > > > > > > > > *dev_priv,
> > > > > > > > > enum port port)
> > > > > > > > >  	drm_encoder_init(&dev_priv->drm, encoder,
> > > > > > > > > &intel_ddi_funcs,
> > > > > > > > >  			 DRM_MODE_ENCODER_TMDS, "DDI %c",
> > > > > > > > > port_name(port));
> > > > > > > > >  
> > > > > > > > > -	if (init_hdmi)
> > > > > > > > > -		intel_encoder->hotplug = intel_ddi_hotplug;
> > > > > > > > > -	else
> > > > > > > > > -		intel_encoder->hotplug =
> > > > > > > > > intel_encoder_hotplug;
> > > > > > > > > +	intel_encoder->hotplug = intel_ddi_hotplug;
> > > > > > > > >  	intel_encoder->compute_output_type =
> > > > > > > > > intel_ddi_compute_output_type;
> > > > > > > > >  	intel_encoder->compute_config =
> > > > > > > > > intel_ddi_compute_config;
> > > > > > > > >  	intel_encoder->enable = intel_enable_ddi;
> > > > > > > > > diff --git a/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > > > b/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > > > index 6bbf14410c2a..152016e09a11 100644
> > > > > > > > > --- a/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > > > +++ b/drivers/gpu/drm/i915/intel_dp.c
> > > > > > > > > @@ -4275,12 +4275,83 @@ intel_dp_check_mst_status(struct
> > > > > > > > > intel_dp
> > > > > > > > > *intel_dp)
> > > > > > > > >  	return -EINVAL;
> > > > > > > > >  }
> > > > > > > > >  
> > > > > > > > > -static void
> > > > > > > > > -intel_dp_retrain_link(struct intel_dp *intel_dp)
> > > > > > > > > +static bool
> > > > > > > > > +intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
> > > > > > > > > +{
> > > > > > > > > +	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > > > > > > +
> > > > > > > > > +	if (!intel_dp_get_link_status(intel_dp, link_status))
> > > > > > > > > {
> > > > > > > > > +		DRM_ERROR("Failed to get link status\n");
> > > > > > > > > +		return false;
> > > > > > > > > +	}
> > > > > > > > > +
> > > > > > > > > +	/*
> > > > > > > > > +	 * Validate the cached values of intel_dp->link_rate
> > > > > > > > > and
> > > > > > > > > +	 * intel_dp->lane_count before attempting to retrain.
> > > > > > > > > +	 */
> > > > > > > > > +	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > > > > > > > link_rate,
> > > > > > > > > 
> > > > > > > > > +					intel_dp-
> > > > > > > > > >lane_count))
> > > > > > > > > +		return false;
> > > > > > > > > +
> > > > > > > > > +	/* Retrain if Channel EQ or CR not ok */
> > > > > > > > > +	return !drm_dp_channel_eq_ok(link_status, intel_dp-
> > > > > > > > > > lane_count);
> > > > > > > > > 
> > > > > > > > > +}
> > > > > > > > > +
> > > > > > > > > +/*
> > > > > > > > > + * If display is now connected check links status,
> > > > > > > > > + * there has been known issues of link loss triggering
> > > > > > > > > + * long pulse.
> > > > > > > > > + *
> > > > > > > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > > > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > > > > > > + * end up with HPD going low during a modeset, and then
> > > > > > > > > + * going back up soon after. And once that happens we must
> > > > > > > > > + * retrain the link to get a picture. That's in case no
> > > > > > > > > + * userspace component reacted to intermittent HPD dip.
> > > > > > > > > + */
> > > > > > > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > > > > > > +			  struct drm_modeset_acquire_ctx
> > > > > > > > > *ctx)
> > > > > > > > >  {
> > > > > > > > > -	struct intel_encoder *encoder =
> > > > > > > > > &dp_to_dig_port(intel_dp)-
> > > > > > > > > > base;
> > > > > > > > > 
> > > > > > > > >  	struct drm_i915_private *dev_priv = to_i915(encoder-
> > > > > > > > > > base.dev);
> > > > > > > > > 
> > > > > > > > > -	struct intel_crtc *crtc = to_intel_crtc(encoder-
> > > > > > > > > > base.crtc);
> > > > > > > > > 
> > > > > > > > > +	struct intel_dp *intel_dp = enc_to_intel_dp(&encoder-
> > > > > > > > > > base);
> > > > > > > > > 
> > > > > > > > > +	struct intel_connector *connector = intel_dp-
> > > > > > > > > > attached_connector;
> > > > > > > > > 
> > > > > > > > > +	struct drm_connector_state *conn_state;
> > > > > > > > > +	struct intel_crtc_state *crtc_state;
> > > > > > > > > +	struct intel_crtc *crtc;
> > > > > > > > > +	int ret;
> > > > > > > > > +
> > > > > > > > > +	/* FIXME handle the MST connectors as well */
> > > > > > > > > +
> > > > > > > > > +	if (!connector || connector->base.status !=
> > > > > > > > > connector_status_connected)
> > > > > > > > > +		return 0;
> > > > > > > > > +
> > > > > > > > > +	ret = drm_modeset_lock(&dev_priv-
> > > > > > > > > > drm.mode_config.connection_mutex,
> > > > > > > > > 
> > > > > > > > > ctx);
> > > > > > > > > +	if (ret)
> > > > > > > > > +		return ret;
> > > > > > > > > +
> > > > > > > > > +	conn_state = connector->base.state;
> > > > > > > > > +
> > > > > > > > > +	crtc = to_intel_crtc(conn_state->crtc);
> > > > > > > > > +	if (!crtc)
> > > > > > > > > +		return 0;
> > > > > > > > > +
> > > > > > > > > +	ret = drm_modeset_lock(&crtc->base.mutex, ctx);
> > > > > > > > > +	if (ret)
> > > > > > > > > +		return ret;
> > > > > > > > > +
> > > > > > > > > +	crtc_state = to_intel_crtc_state(crtc->base.state);
> > > > > > > > > +
> > > > > > > > > +	WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
> > > > > > > > > +
> > > > > > > > > +	if (!crtc_state->base.active)
> > > > > > > > > +		return 0;
> > > > > > > > > +
> > > > > > > > > +	if (conn_state->commit &&
> > > > > > > > > +	    !try_wait_for_completion(&conn_state->commit-
> > > > > > > > > > hw_done))
> > > > > > > > > 
> > > > > > > > > +		return 0;
> > > > > > > > > +
> > > > > > > > > +	if (!intel_dp_needs_link_retrain(intel_dp))
> > > > > > > > > +		return 0;
> > > > > > > > 
> > > > > > > > NAK, this definitely won't work for implementing MST retraining.
> > > > > > > > There's
> > > > > > > > some
> > > > > > > > pretty huge differences with how retraining needs to be handled
> > > > > > > > on
> > > > > > > > SST
> > > > > > > > vs. MST.
> > > > > > > > An example with some normal SST sink vs. what happens on my
> > > > > > > > caldigit
> > > > > > > > TS3
> > > > > > > > 
> > > > > > > > SST:
> > > > > > > >     1. commit modeset, everything is OK
> > > > > > > >     2. something happens, sink sends shortpulse and changes link
> > > > > > > > status
> > > > > > > > registers
> > > > > > > >     in dpcd
> > > > > > > >     3. Source receives short pulse, tries retraining five times
> > > > > > > >     4. if this succeeds:
> > > > > > > >         5. we're done here
> > > > > > > >     6. if this fails:
> > > > > > > >         7. mark link status as bad
> > > > > > > >         8. get fallback parameters
> > > > > > > >         9. hotplug event
> > > > > > > > 
> > > > > > > > MST (i915 doesn't do this yet, but this is generally how it
> > > > > > > > needs to
> > > > > > > > be
> > > > > > > > handled):
> > > > > > > >     1. commit modeset, everything is OK
> > > > > > > >     2. something happens (in my case, the MST hub discovers it
> > > > > > > > had
> > > > > > > > the
> > > > > > > > wrong max
> > > > > > > >     link rate/lane count), sink sends ESI indicating channel EQ
> > > > > > > > has
> > > > > > > > failed
> > > > > > > >     3. retraining commences with five retries.
> > > > > > > >     4. if this succeeds:
> > > > > > > >        5. continue
> > > > > > > >     6. if this fails (I actually haven't seen this once yet)
> > > > > > > >         7. mark link status as bad on all downstream connectors
> > > > > > > >         8. get fallback parameters
> > > > > > > >         9. hotplug event
> > > > > > > >     10. the retrain didn't actually work (despite what the SST
> > > > > > > > link
> > > > > > > > status
> > > > > > > >     registers told us). go back to step 3 five more times
> > > > > > > >     11. if this fails:
> > > > > > > >         12. mark link status as bad on all downstream connectors
> > > > > > > >         13. get fallback parameters
> > > > > > > >         14. hotplug event
> > > > > > > > 
> > > > > > > > simply put: we really should keep the "do we need to retrain?"
> > > > > > > > logic
> > > > > > > > out
> > > > > > > > of the
> > > > > > > > actual retraining helpers so that SST/MST codepaths can do their
> > > > > > > > own
> > > > > > > > checks to
> > > > > > > > figure this out.
> > > > > > > 
> > > > > > > No, we need it since we want to check it *after* any modeset has
> > > > > > > finished. With MST I think what we'll want to do is find all the
> > > > > > > pipes
> > > > > > > affected by the link failure, lock them, and wait until they're
> > > > > > > done
> > > > > > > with their modesets, then we check the link state. If it's bad we
> > > > > > > proceed to retrain the link.
> > > > > > > 
> > > > > > > So basically just walking over the MST encoders in addition to the
> > > > > > > SST encoder, and repeating most of the steps in this code for
> > > > > > > each.
> > > > > > > Hence the the MST FIXME I left in there ;)
> > > > > > > 
> > > > > > 
> > > > > > Lyude,
> > > > > > 
> > > > > > I agree with Ville here, can we add the MST retrain required check
> > > > > > from
> > > > > > within the intel_dp_retrain_link()? So for now the FIXME should be
> > > > > > left
> > > > > > there
> > > > > > and MST retraining check can be added from your patches.
> > > > > > 
> > > > > > Manasi
> > > > > 
> > > > > Yep! Sorry I probably should have reiterated this part over email
> > > > > since I
> > > > > only
> > > > > mentioned it to ville directly: this part should definitely work fine,
> > > > > and
> > > > > intel_dp_retrain_link() is actually where we handle MST retraining in
> > > > > the
> > > > > latest version of the retraining series:
> > > > > 
> > > > > jfyi, you can find that here:
> > > > > https://github.com/Lyude/linux/tree/wip/i915-mst-fallback-a4
> > > > > It's almost ready for the ML, just want to get the other patches this
> > > > > is
> > > > > going
> > > > > to rely on in first and fix some small concerns I've got about that
> > > > > series'
> > > > > current implementation of handling modesets after a failed retrain
> > > > > sequence
> > > > > > 
> > > > 
> > > > Great!
> > > > After the failed retrain sequence, it will keep on retrying until has
> > > > tried
> > > > all
> > > > the link rate/lane count combinations until RBR 1 lane and then fail
> > > > with a
> > > > ERROR message.
> > > > What was the concern on the current implementation of modeste after
> > > > failed
> > > > retrain?
> > > 
> > > I actually take that back. Was worried that not freeing existing VCPI
> > > allocations during the first atomic check phase for the first modeset
> > > after a
> > > retrain failure might cause atomic checks to fail from not having enough
> > > VCPI 
> > > space, but then I realized that wouldn't matter since if we're not able to
> > > fit
> > > one display into the VCPI with a reduced pbn_div, that just means fitting
> > > both
> > > displays with a reduced pbn_div would also be impossible :P.
> > > 
> > 
> > But then in that case, in oredr to retry at lower link rates, both these
> > monitors will
> > have to drop to the next lower resolutions to fit the reduced pbn_div.
> 
> Yep, that's the idea! In which case the atomic check should fail, which should
> cause userspace to try at a reduced resolution or take some other reparative
> action
> > 
> > Manasi
> >  
> > > > 
> > > > Manasi
> > > >  
> > > > > > > > 
> > > > > > > > >  
> > > > > > > > >  	/* Suppress underruns caused by re-training */
> > > > > > > > >  	intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc-
> > > > > > > > > > pipe,
> > > > > > > > > 
> > > > > > > > > false);
> > > > > > > > > @@ -4298,51 +4369,49 @@ intel_dp_retrain_link(struct intel_dp
> > > > > > > > > *intel_dp)
> > > > > > > > >  	if (crtc->config->has_pch_encoder)
> > > > > > > > >  		intel_set_pch_fifo_underrun_reporting(dev_pri
> > > > > > > > > v,
> > > > > > > > >  						      intel_c
> > > > > > > > > rtc_
> > > > > > > > > pch_
> > > > > > > > > transcod
> > > > > > > > > er(crtc), true);
> > > > > > > > > +
> > > > > > > > > +	return 0;
> > > > > > > > >  }
> > > > > > > > >  
> > > > > > > > > -static void
> > > > > > > > > -intel_dp_check_link_status(struct intel_dp *intel_dp)
> > > > > > > > > +/*
> > > > > > > > > + * If display is now connected check links status,
> > > > > > > > > + * there has been known issues of link loss triggering
> > > > > > > > > + * long pulse.
> > > > > > > > > + *
> > > > > > > > > + * Some sinks (eg. ASUS PB287Q) seem to perform some
> > > > > > > > > + * weird HPD ping pong during modesets. So we can apparently
> > > > > > > > > + * end up with HPD going low during a modeset, and then
> > > > > > > > > + * going back up soon after. And once that happens we must
> > > > > > > > > + * retrain the link to get a picture. That's in case no
> > > > > > > > > + * userspace component reacted to intermittent HPD dip.
> > > > > > > > > + */
> > > > > > > > > +static bool intel_dp_hotplug(struct intel_encoder *encoder,
> > > > > > > > > +			     struct intel_connector
> > > > > > > > > *connector)
> > > > > > > > >  {
> > > > > > > > > -	struct drm_i915_private *dev_priv =
> > > > > > > > > to_i915(intel_dp_to_dev(intel_dp));
> > > > > > > > > -	struct intel_encoder *intel_encoder =
> > > > > > > > > &dp_to_dig_port(intel_dp)-
> > > > > > > > > > base;
> > > > > > > > > 
> > > > > > > > > -	struct drm_connector_state *conn_state =
> > > > > > > > > -		intel_dp->attached_connector->base.state;
> > > > > > > > > -	u8 link_status[DP_LINK_STATUS_SIZE];
> > > > > > > > > -
> > > > > > > > > -	WARN_ON(!drm_modeset_is_locked(&dev_priv-
> > > > > > > > > > drm.mode_config.connection_mutex));
> > > > > > > > > 
> > > > > > > > > -
> > > > > > > > > -	if (!intel_dp_get_link_status(intel_dp, link_status))
> > > > > > > > > {
> > > > > > > > > -		DRM_ERROR("Failed to get link status\n");
> > > > > > > > > -		return;
> > > > > > > > > -	}
> > > > > > > > > +	struct drm_modeset_acquire_ctx ctx;
> > > > > > > > > +	bool changed;
> > > > > > > > > +	int ret;
> > > > > > > > >  
> > > > > > > > > -	if (!conn_state->crtc)
> > > > > > > > > -		return;
> > > > > > > > > +	changed = intel_encoder_hotplug(encoder, connector);
> > > > > > > > >  
> > > > > > > > > -	WARN_ON(!drm_modeset_is_locked(&conn_state->crtc-
> > > > > > > > > > mutex));
> > > > > > > > > 
> > > > > > > > > +	drm_modeset_acquire_init(&ctx, 0);
> > > > > > > > >  
> > > > > > > > > -	if (!conn_state->crtc->state->active)
> > > > > > > > > -		return;
> > > > > > > > > +	for (;;) {
> > > > > > 
> > > > > > Here if this is getting executed due to hpd ping pong during the
> > > > > > modeset
> > > > > > and that modeset is already happening at a link fallback parameter
> > > > > > then
> > > > > > while we call retrain link, we should also validate the link
> > > > > > parameters
> > > > > > so that it doesnt try to retrain with stale values.
> > > > > > 
> > > > > > I think we need to call intel_dp_link_params_valid() before retrain.

I missed that intel_dp_retrain_link() does call intel_dp_link_params_valid() through
intel_dp_needs_retrain(). So ignore my concern above.
With that,

Acked-by: Manasi Navare <manasi.d.navare@intel.com>

Manasi
> > > > > > 
> > > > > > > > > +		ret = intel_dp_retrain_link(encoder, &ctx);
> > > > > > > > >  
> > > > > > > > > -	if (conn_state->commit &&
> > > > > > > > > -	    !try_wait_for_completion(&conn_state->commit-
> > > > > > > > > > hw_done))
> > > > > > > > > 
> > > > > > > > > -		return;
> > > > > > > > > +		if (ret == -EDEADLK) {
> > > > > > > > > +			drm_modeset_backoff(&ctx);
> > > > > > > > > +			continue;
> > > > > > > > > +		}
> > > > > > > > >  
> > > > > > > > > -	/*
> > > > > > > > > -	 * Validate the cached values of intel_dp->link_rate
> > > > > > > > > and
> > > > > > > > > -	 * intel_dp->lane_count before attempting to retrain.
> > > > > > > > > -	 */
> > > > > > > > > -	if (!intel_dp_link_params_valid(intel_dp, intel_dp-
> > > > > > > > > > link_rate,
> > > > > > > > > 
> > > > > > > > > -					intel_dp-
> > > > > > > > > >lane_count))
> > > > > > > > > -		return;
> > > > > > > > > +		break;
> > > > > > > > > +	}
> > > > > > > > >  
> > > > > > > > > -	/* Retrain if Channel EQ or CR not ok */
> > > > > > > > > -	if (!drm_dp_channel_eq_ok(link_status, intel_dp-
> > > > > > > > > > lane_count)) 
> > > > > > > > > 
> > > > > > > > > {
> > > > > > > > > -		DRM_DEBUG_KMS("%s: channel EQ not ok,
> > > > > > > > > retraining\n",
> > > > > > > > > -			      intel_encoder->base.name);
> > > > > > > > > +	drm_modeset_drop_locks(&ctx);
> > > > > > > > > +	drm_modeset_acquire_fini(&ctx);
> > > > > > > > > +	WARN(ret, "Acquiring modeset locks failed with %i\n",
> > > > > > > > > ret);
> > > > > > > > >  
> > > > > > > > > -		intel_dp_retrain_link(intel_dp);
> > > > > > > > > -	}
> > > > > > > > > +	return changed;
> > > > > > > > >  }
> > > > > > > > >  
> > > > > > > > >  /*
> > > > > > > > > @@ -4400,7 +4469,9 @@ intel_dp_short_pulse(struct intel_dp
> > > > > > > > > *intel_dp)
> > > > > > > > >  			DRM_DEBUG_DRIVER("CP or sink specific
> > > > > > > > > irq
> > > > > > > > > unhandled\n");
> > > > > > > > >  	}
> > > > > > > > >  
> > > > > > > > > -	intel_dp_check_link_status(intel_dp);
> > > > > > > > > +	/* defer to the hotplug work for link retraining if
> > > > > > > > > needed */
> > > > > > > > > +	if (intel_dp_needs_link_retrain(intel_dp))
> > > > > > > > > +		return false;
> > > > > > > > >  
> > > > > > > > >  	if (intel_dp->compliance.test_type ==
> > > > > > > > > DP_TEST_LINK_TRAINING)
> > > > > > > > > {
> > > > > > > > >  		DRM_DEBUG_KMS("Link Training Compliance Test
> > > > > > > > > requested\n");
> > > > > > > > > @@ -4785,20 +4856,6 @@ intel_dp_long_pulse(struct
> > > > > > > > > intel_connector
> > > > > > > > > *connector)
> > > > > > > > >  		 */
> > > > > > > > >  		status = connector_status_disconnected;
> > > > > > > > >  		goto out;
> > > > > > > > > -	} else {
> > > > > > > > > -		/*
> > > > > > > > > -		 * If display is now connected check links
> > > > > > > > > status,
> > > > > > > > > -		 * there has been known issues of link loss
> > > > > > > > > triggerring
> > > > > > > > > -		 * long pulse.
> > > > > > > > > -		 *
> > > > > > > > > -		 * Some sinks (eg. ASUS PB287Q) seem to
> > > > > > > > > perform
> > > > > > > > > some
> > > > > > > > > -		 * weird HPD ping pong during modesets. So we
> > > > > > > > > can
> > > > > > > > > apparently
> > > > > > > > > -		 * end up with HPD going low during a
> > > > > > > > > modeset,
> > > > > > > > > and
> > > > > > > > > then
> > > > > > > > > -		 * going back up soon after. And once that
> > > > > > > > > happens we
> > > > > > > > > must
> > > > > > > > > -		 * retrain the link to get a picture. That's
> > > > > > > > > in
> > > > > > > > > case
> > > > > > > > > no
> > > > > > > > > -		 * userspace component reacted to
> > > > > > > > > intermittent
> > > > > > > > > HPD
> > > > > > > > > dip.
> > > > > > > > > -		 */
> > > > > > > > > -		intel_dp_check_link_status(intel_dp);
> > > > > > > > >  	}
> > > > > > > > >  
> > > > > > > > >  	/*
> > > > > > > > > @@ -5340,37 +5397,10 @@ intel_dp_hpd_pulse(struct
> > > > > > > > > intel_digital_port
> > > > > > > > > *intel_dig_port, bool long_hpd)
> > > > > > > > >  	}
> > > > > > > > >  
> > > > > > > > >  	if (!intel_dp->is_mst) {
> > > > > > > > > -		struct drm_modeset_acquire_ctx ctx;
> > > > > > > > > -		struct drm_connector *connector = &intel_dp-
> > > > > > > > > > attached_connector->base;
> > > > > > > > > 
> > > > > > > > > -		struct drm_crtc *crtc;
> > > > > > > > > -		int iret;
> > > > > > > > > -		bool handled = false;
> > > > > > > > > -
> > > > > > > > > -		drm_modeset_acquire_init(&ctx, 0);
> > > > > > > > > -retry:
> > > > > > > > > -		iret = drm_modeset_lock(&dev_priv-
> > > > > > > > > > drm.mode_config.connection_mutex, &ctx);
> > > > > > > > > 
> > > > > > > > > -		if (iret)
> > > > > > > > > -			goto err;
> > > > > > > > > -
> > > > > > > > > -		crtc = connector->state->crtc;
> > > > > > > > > -		if (crtc) {
> > > > > > > > > -			iret = drm_modeset_lock(&crtc->mutex,
> > > > > > > > > &ctx);
> > > > > > > > > -			if (iret)
> > > > > > > > > -				goto err;
> > > > > > > > > -		}
> > > > > > > > > +		bool handled;
> > > > > > > > >  
> > > > > > > > >  		handled = intel_dp_short_pulse(intel_dp);
> > > > > > > > >  
> > > > > > > > > -err:
> > > > > > > > > -		if (iret == -EDEADLK) {
> > > > > > > > > -			drm_modeset_backoff(&ctx);
> > > > > > > > > -			goto retry;
> > > > > > > > > -		}
> > > > > > > > > -
> > > > > > > > > -		drm_modeset_drop_locks(&ctx);
> > > > > > > > > -		drm_modeset_acquire_fini(&ctx);
> > > > > > > > > -		WARN(iret, "Acquiring modeset locks failed
> > > > > > > > > with
> > > > > > > > > %i\n", iret);
> > > > > > > > > -
> > > > > > > > >  		/* Short pulse can signify loss of hdcp
> > > > > > > > > authentication */
> > > > > > > > >  		intel_hdcp_check_link(intel_dp-
> > > > > > > > > > attached_connector);
> > > > > > > > > 
> > > > > > > > >  
> > > > > > > > > @@ -6400,7 +6430,7 @@ bool intel_dp_init(struct
> > > > > > > > > drm_i915_private
> > > > > > > > > *dev_priv,
> > > > > > > > >  			     "DP %c", port_name(port)))
> > > > > > > > >  		goto err_encoder_init;
> > > > > > > > >  
> > > > > > > > > -	intel_encoder->hotplug = intel_encoder_hotplug;
> > > > > > > > > +	intel_encoder->hotplug = intel_dp_hotplug;
> > > > > > > > >  	intel_encoder->compute_config =
> > > > > > > > > intel_dp_compute_config;
> > > > > > > > >  	intel_encoder->get_hw_state = intel_dp_get_hw_state;
> > > > > > > > >  	intel_encoder->get_config = intel_dp_get_config;
> > > > > > > > > diff --git a/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > > > b/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > > > index 5ea1dc3f63bf..ddf28a442cd7 100644
> > > > > > > > > --- a/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > > > +++ b/drivers/gpu/drm/i915/intel_drv.h
> > > > > > > > > @@ -1611,6 +1611,8 @@ int
> > > > > > > > > intel_dp_get_link_train_fallback_values(struct
> > > > > > > > > intel_dp *intel_dp,
> > > > > > > > >  					    int link_rate,
> > > > > > > > > uint8_t
> > > > > > > > > lane_count);
> > > > > > > > >  void intel_dp_start_link_train(struct intel_dp *intel_dp);
> > > > > > > > >  void intel_dp_stop_link_train(struct intel_dp *intel_dp);
> > > > > > > > > +int intel_dp_retrain_link(struct intel_encoder *encoder,
> > > > > > > > > +			  struct drm_modeset_acquire_ctx
> > > > > > > > > *ctx);
> > > > > > > > >  void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
> > > > > > > > >  void intel_dp_encoder_reset(struct drm_encoder *encoder);
> > > > > > > > >  void intel_dp_encoder_suspend(struct intel_encoder
> > > > > > > > > *intel_encoder);
> > > > > > > 
> > > > > > > -- 
> > > > > > > Ville Syrjälä
> > > > > > > Intel OTC
> > > > > > > _______________________________________________
> > > > > > > Intel-gfx mailing list
> > > > > > > Intel-gfx@lists.freedesktop.org
> > > > > > > https://lists.freedesktop.org/mailman/listinfo/intel-gfx
> > > > > 
> > > > > -- 
> > > > > Cheers,
> > > > > 	Lyude Paul
> > > 
> > > -- 
> > > Cheers,
> > > 	Lyude Paul
> -- 
> Cheers,
> 	Lyude Paul
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx

^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2018-03-05 23:38 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2018-01-17 19:21 [PATCH 1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Ville Syrjala
2018-01-17 19:21 ` [PATCH v2 2/5] drm/i915: Reinitialize sink scrambling/TMDS clock ratio on HPD Ville Syrjala
2018-01-30 22:45   ` Lyude Paul
2018-01-17 19:21 ` [PATCH v2 3/5] drm/i915: Move SST DP link retraining into the ->post_hotplug() hook Ville Syrjala
2018-01-30 23:16   ` Lyude Paul
2018-01-31 13:27     ` Ville Syrjälä
2018-02-28  7:17       ` Manasi Navare
2018-02-28 19:07         ` Lyude Paul
2018-02-28 19:27           ` Manasi Navare
2018-02-28 19:41             ` Lyude Paul
2018-02-28 19:57               ` Manasi Navare
2018-02-28 20:10                 ` Lyude Paul
2018-03-05 23:41                   ` Manasi Navare
2018-01-17 19:21 ` [PATCH 4/5] drm/i915: Nuke intel_dp->channel_eq_status Ville Syrjala
2018-01-19  6:59   ` Rodrigo Vivi
2018-02-28 20:12     ` Manasi Navare
2018-01-30 23:17   ` Lyude Paul
2018-01-17 19:21 ` [PATCH 5/5] drm/i915: Track whether the DP link is trained or not Ville Syrjala
2018-01-30 23:19   ` Lyude Paul
2018-02-28 20:08   ` Manasi Navare
2018-01-18 11:21 ` ✓ Fi.CI.BAT: success for series starting with [1/5] drm/i915: Convert intel_hpd_irq_event() into an encoder hotplug hook Patchwork
2018-01-18 13:04 ` ✓ Fi.CI.IGT: " Patchwork
2018-01-30 23:22 ` [PATCH 1/5] " Lyude Paul

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.