aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorVille Syrjälä <ville.syrjala@linux.intel.com>2018-01-17 14:21:47 -0500
committerLyude Paul <lyude@redhat.com>2018-03-06 17:57:44 -0500
commitc85d200e832197e23ceeadfda9745646a242fd46 (patch)
tree6bdd2c381213509eb51b2e2f86d2dc1b9ae9bf38
parentdba14b27dd3ca5ce5b3a1d538862e7dce556dba7 (diff)
drm/i915: Move SST DP link retraining into the ->post_hotplug() hook
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 [pushed with whitespace changes for sparse] 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> Acked-by: Manasi Navare <manasi.d.navare@intel.com> Signed-off-by: Lyude Paul <lyude@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20180117192149.17760-3-ville.syrjala@linux.intel.com
-rw-r--r--drivers/gpu/drm/i915/intel_ddi.c10
-rw-r--r--drivers/gpu/drm/i915/intel_dp.c197
-rw-r--r--drivers/gpu/drm/i915/intel_drv.h2
3 files changed, 121 insertions, 88 deletions
diff --git a/drivers/gpu/drm/i915/intel_ddi.c b/drivers/gpu/drm/i915/intel_ddi.c
index e5b5d21c3c09..d3cbea2c136c 100644
--- a/drivers/gpu/drm/i915/intel_ddi.c
+++ b/drivers/gpu/drm/i915/intel_ddi.c
@@ -2923,7 +2923,10 @@ static bool intel_ddi_hotplug(struct intel_encoder *encoder,
2923 drm_modeset_acquire_init(&ctx, 0); 2923 drm_modeset_acquire_init(&ctx, 0);
2924 2924
2925 for (;;) { 2925 for (;;) {
2926 ret = intel_hdmi_reset_link(encoder, &ctx); 2926 if (connector->base.connector_type == DRM_MODE_CONNECTOR_HDMIA)
2927 ret = intel_hdmi_reset_link(encoder, &ctx);
2928 else
2929 ret = intel_dp_retrain_link(encoder, &ctx);
2927 2930
2928 if (ret == -EDEADLK) { 2931 if (ret == -EDEADLK) {
2929 drm_modeset_backoff(&ctx); 2932 drm_modeset_backoff(&ctx);
@@ -3056,10 +3059,7 @@ void intel_ddi_init(struct drm_i915_private *dev_priv, enum port port)
3056 drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs, 3059 drm_encoder_init(&dev_priv->drm, encoder, &intel_ddi_funcs,
3057 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port)); 3060 DRM_MODE_ENCODER_TMDS, "DDI %c", port_name(port));
3058 3061
3059 if (init_hdmi) 3062 intel_encoder->hotplug = intel_ddi_hotplug;
3060 intel_encoder->hotplug = intel_ddi_hotplug;
3061 else
3062 intel_encoder->hotplug = intel_encoder_hotplug;
3063 intel_encoder->compute_output_type = intel_ddi_compute_output_type; 3063 intel_encoder->compute_output_type = intel_ddi_compute_output_type;
3064 intel_encoder->compute_config = intel_ddi_compute_config; 3064 intel_encoder->compute_config = intel_ddi_compute_config;
3065 intel_encoder->enable = intel_enable_ddi; 3065 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 7cc1720a437d..153342cf5898 100644
--- a/drivers/gpu/drm/i915/intel_dp.c
+++ b/drivers/gpu/drm/i915/intel_dp.c
@@ -4272,12 +4272,84 @@ go_again:
4272 return -EINVAL; 4272 return -EINVAL;
4273} 4273}
4274 4274
4275static void 4275static bool
4276intel_dp_retrain_link(struct intel_dp *intel_dp) 4276intel_dp_needs_link_retrain(struct intel_dp *intel_dp)
4277{
4278 u8 link_status[DP_LINK_STATUS_SIZE];
4279
4280 if (!intel_dp_get_link_status(intel_dp, link_status)) {
4281 DRM_ERROR("Failed to get link status\n");
4282 return false;
4283 }
4284
4285 /*
4286 * Validate the cached values of intel_dp->link_rate and
4287 * intel_dp->lane_count before attempting to retrain.
4288 */
4289 if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
4290 intel_dp->lane_count))
4291 return false;
4292
4293 /* Retrain if Channel EQ or CR not ok */
4294 return !drm_dp_channel_eq_ok(link_status, intel_dp->lane_count);
4295}
4296
4297/*
4298 * If display is now connected check links status,
4299 * there has been known issues of link loss triggering
4300 * long pulse.
4301 *
4302 * Some sinks (eg. ASUS PB287Q) seem to perform some
4303 * weird HPD ping pong during modesets. So we can apparently
4304 * end up with HPD going low during a modeset, and then
4305 * going back up soon after. And once that happens we must
4306 * retrain the link to get a picture. That's in case no
4307 * userspace component reacted to intermittent HPD dip.
4308 */
4309int intel_dp_retrain_link(struct intel_encoder *encoder,
4310 struct drm_modeset_acquire_ctx *ctx)
4277{ 4311{
4278 struct intel_encoder *encoder = &dp_to_dig_port(intel_dp)->base;
4279 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev); 4312 struct drm_i915_private *dev_priv = to_i915(encoder->base.dev);
4280 struct intel_crtc *crtc = to_intel_crtc(encoder->base.crtc); 4313 struct intel_dp *intel_dp = enc_to_intel_dp(&encoder->base);
4314 struct intel_connector *connector = intel_dp->attached_connector;
4315 struct drm_connector_state *conn_state;
4316 struct intel_crtc_state *crtc_state;
4317 struct intel_crtc *crtc;
4318 int ret;
4319
4320 /* FIXME handle the MST connectors as well */
4321
4322 if (!connector || connector->base.status != connector_status_connected)
4323 return 0;
4324
4325 ret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex,
4326 ctx);
4327 if (ret)
4328 return ret;
4329
4330 conn_state = connector->base.state;
4331
4332 crtc = to_intel_crtc(conn_state->crtc);
4333 if (!crtc)
4334 return 0;
4335
4336 ret = drm_modeset_lock(&crtc->base.mutex, ctx);
4337 if (ret)
4338 return ret;
4339
4340 crtc_state = to_intel_crtc_state(crtc->base.state);
4341
4342 WARN_ON(!intel_crtc_has_dp_encoder(crtc_state));
4343
4344 if (!crtc_state->base.active)
4345 return 0;
4346
4347 if (conn_state->commit &&
4348 !try_wait_for_completion(&conn_state->commit->hw_done))
4349 return 0;
4350
4351 if (!intel_dp_needs_link_retrain(intel_dp))
4352 return 0;
4281 4353
4282 /* Suppress underruns caused by re-training */ 4354 /* Suppress underruns caused by re-training */
4283 intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false); 4355 intel_set_cpu_fifo_underrun_reporting(dev_priv, crtc->pipe, false);
@@ -4295,51 +4367,49 @@ intel_dp_retrain_link(struct intel_dp *intel_dp)
4295 if (crtc->config->has_pch_encoder) 4367 if (crtc->config->has_pch_encoder)
4296 intel_set_pch_fifo_underrun_reporting(dev_priv, 4368 intel_set_pch_fifo_underrun_reporting(dev_priv,
4297 intel_crtc_pch_transcoder(crtc), true); 4369 intel_crtc_pch_transcoder(crtc), true);
4370
4371 return 0;
4298} 4372}
4299 4373
4300static void 4374/*
4301intel_dp_check_link_status(struct intel_dp *intel_dp) 4375 * If display is now connected check links status,
4376 * there has been known issues of link loss triggering
4377 * long pulse.
4378 *
4379 * Some sinks (eg. ASUS PB287Q) seem to perform some
4380 * weird HPD ping pong during modesets. So we can apparently
4381 * end up with HPD going low during a modeset, and then
4382 * going back up soon after. And once that happens we must
4383 * retrain the link to get a picture. That's in case no
4384 * userspace component reacted to intermittent HPD dip.
4385 */
4386static bool intel_dp_hotplug(struct intel_encoder *encoder,
4387 struct intel_connector *connector)
4302{ 4388{
4303 struct drm_i915_private *dev_priv = to_i915(intel_dp_to_dev(intel_dp)); 4389 struct drm_modeset_acquire_ctx ctx;
4304 struct intel_encoder *intel_encoder = &dp_to_dig_port(intel_dp)->base; 4390 bool changed;
4305 struct drm_connector_state *conn_state = 4391 int ret;
4306 intel_dp->attached_connector->base.state;
4307 u8 link_status[DP_LINK_STATUS_SIZE];
4308
4309 WARN_ON(!drm_modeset_is_locked(&dev_priv->drm.mode_config.connection_mutex));
4310
4311 if (!intel_dp_get_link_status(intel_dp, link_status)) {
4312 DRM_ERROR("Failed to get link status\n");
4313 return;
4314 }
4315 4392
4316 if (!conn_state->crtc) 4393 changed = intel_encoder_hotplug(encoder, connector);
4317 return;
4318 4394
4319 WARN_ON(!drm_modeset_is_locked(&conn_state->crtc->mutex)); 4395 drm_modeset_acquire_init(&ctx, 0);
4320 4396
4321 if (!conn_state->crtc->state->active) 4397 for (;;) {
4322 return; 4398 ret = intel_dp_retrain_link(encoder, &ctx);
4323 4399
4324 if (conn_state->commit && 4400 if (ret == -EDEADLK) {
4325 !try_wait_for_completion(&conn_state->commit->hw_done)) 4401 drm_modeset_backoff(&ctx);
4326 return; 4402 continue;
4403 }
4327 4404
4328 /* 4405 break;
4329 * Validate the cached values of intel_dp->link_rate and 4406 }
4330 * intel_dp->lane_count before attempting to retrain.
4331 */
4332 if (!intel_dp_link_params_valid(intel_dp, intel_dp->link_rate,
4333 intel_dp->lane_count))
4334 return;
4335 4407
4336 /* Retrain if Channel EQ or CR not ok */ 4408 drm_modeset_drop_locks(&ctx);
4337 if (!drm_dp_channel_eq_ok(link_status, intel_dp->lane_count)) { 4409 drm_modeset_acquire_fini(&ctx);
4338 DRM_DEBUG_KMS("%s: channel EQ not ok, retraining\n", 4410 WARN(ret, "Acquiring modeset locks failed with %i\n", ret);
4339 intel_encoder->base.name);
4340 4411
4341 intel_dp_retrain_link(intel_dp); 4412 return changed;
4342 }
4343} 4413}
4344 4414
4345/* 4415/*
@@ -4397,7 +4467,9 @@ intel_dp_short_pulse(struct intel_dp *intel_dp)
4397 DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n"); 4467 DRM_DEBUG_DRIVER("CP or sink specific irq unhandled\n");
4398 } 4468 }
4399 4469
4400 intel_dp_check_link_status(intel_dp); 4470 /* defer to the hotplug work for link retraining if needed */
4471 if (intel_dp_needs_link_retrain(intel_dp))
4472 return false;
4401 4473
4402 if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) { 4474 if (intel_dp->compliance.test_type == DP_TEST_LINK_TRAINING) {
4403 DRM_DEBUG_KMS("Link Training Compliance Test requested\n"); 4475 DRM_DEBUG_KMS("Link Training Compliance Test requested\n");
@@ -4782,20 +4854,6 @@ intel_dp_long_pulse(struct intel_connector *connector)
4782 */ 4854 */
4783 status = connector_status_disconnected; 4855 status = connector_status_disconnected;
4784 goto out; 4856 goto out;
4785 } else {
4786 /*
4787 * If display is now connected check links status,
4788 * there has been known issues of link loss triggerring
4789 * long pulse.
4790 *
4791 * Some sinks (eg. ASUS PB287Q) seem to perform some
4792 * weird HPD ping pong during modesets. So we can apparently
4793 * end up with HPD going low during a modeset, and then
4794 * going back up soon after. And once that happens we must
4795 * retrain the link to get a picture. That's in case no
4796 * userspace component reacted to intermittent HPD dip.
4797 */
4798 intel_dp_check_link_status(intel_dp);
4799 } 4857 }
4800 4858
4801 /* 4859 /*
@@ -5372,37 +5430,10 @@ intel_dp_hpd_pulse(struct intel_digital_port *intel_dig_port, bool long_hpd)
5372 } 5430 }
5373 5431
5374 if (!intel_dp->is_mst) { 5432 if (!intel_dp->is_mst) {
5375 struct drm_modeset_acquire_ctx ctx; 5433 bool handled;
5376 struct drm_connector *connector = &intel_dp->attached_connector->base;
5377 struct drm_crtc *crtc;
5378 int iret;
5379 bool handled = false;
5380
5381 drm_modeset_acquire_init(&ctx, 0);
5382retry:
5383 iret = drm_modeset_lock(&dev_priv->drm.mode_config.connection_mutex, &ctx);
5384 if (iret)
5385 goto err;
5386
5387 crtc = connector->state->crtc;
5388 if (crtc) {
5389 iret = drm_modeset_lock(&crtc->mutex, &ctx);
5390 if (iret)
5391 goto err;
5392 }
5393 5434
5394 handled = intel_dp_short_pulse(intel_dp); 5435 handled = intel_dp_short_pulse(intel_dp);
5395 5436
5396err:
5397 if (iret == -EDEADLK) {
5398 drm_modeset_backoff(&ctx);
5399 goto retry;
5400 }
5401
5402 drm_modeset_drop_locks(&ctx);
5403 drm_modeset_acquire_fini(&ctx);
5404 WARN(iret, "Acquiring modeset locks failed with %i\n", iret);
5405
5406 /* Short pulse can signify loss of hdcp authentication */ 5437 /* Short pulse can signify loss of hdcp authentication */
5407 intel_hdcp_check_link(intel_dp->attached_connector); 5438 intel_hdcp_check_link(intel_dp->attached_connector);
5408 5439
@@ -6393,7 +6424,7 @@ bool intel_dp_init(struct drm_i915_private *dev_priv,
6393 "DP %c", port_name(port))) 6424 "DP %c", port_name(port)))
6394 goto err_encoder_init; 6425 goto err_encoder_init;
6395 6426
6396 intel_encoder->hotplug = intel_encoder_hotplug; 6427 intel_encoder->hotplug = intel_dp_hotplug;
6397 intel_encoder->compute_config = intel_dp_compute_config; 6428 intel_encoder->compute_config = intel_dp_compute_config;
6398 intel_encoder->get_hw_state = intel_dp_get_hw_state; 6429 intel_encoder->get_hw_state = intel_dp_get_hw_state;
6399 intel_encoder->get_config = intel_dp_get_config; 6430 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 2ae6d5548171..5bc69ce1c1a5 100644
--- a/drivers/gpu/drm/i915/intel_drv.h
+++ b/drivers/gpu/drm/i915/intel_drv.h
@@ -1626,6 +1626,8 @@ int intel_dp_get_link_train_fallback_values(struct intel_dp *intel_dp,
1626 int link_rate, uint8_t lane_count); 1626 int link_rate, uint8_t lane_count);
1627void intel_dp_start_link_train(struct intel_dp *intel_dp); 1627void intel_dp_start_link_train(struct intel_dp *intel_dp);
1628void intel_dp_stop_link_train(struct intel_dp *intel_dp); 1628void intel_dp_stop_link_train(struct intel_dp *intel_dp);
1629int intel_dp_retrain_link(struct intel_encoder *encoder,
1630 struct drm_modeset_acquire_ctx *ctx);
1629void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode); 1631void intel_dp_sink_dpms(struct intel_dp *intel_dp, int mode);
1630void intel_dp_encoder_reset(struct drm_encoder *encoder); 1632void intel_dp_encoder_reset(struct drm_encoder *encoder);
1631void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder); 1633void intel_dp_encoder_suspend(struct intel_encoder *intel_encoder);