From 9d16da65bfda54dea0b9b10ec49a0e1d23b631eb Mon Sep 17 00:00:00 2001 From: Ander Conselvan de Oliveira Date: Tue, 8 Mar 2016 17:46:26 +0200 Subject: drm/i915: Manage HSW/BDW LCPLLs with the shared dpll interface Manage the LCPLLs used with DisplayPort, so that all the HSW/BDW DPLLs are managed by the shared dpll code. v2: Introduce INTEL_DPLL_ALWAYS_ON flag to please state checker. (Ander) v3: Initialize pll->flags in intel_shared_dpll_init(). (Ander) Signed-off-by: Ander Conselvan de Oliveira Reviewed-by: Maarten Lankhorst Link: http://patchwork.freedesktop.org/patch/msgid/1457451987-17466-13-git-send-email-ander.conselvan.de.oliveira@intel.com --- drivers/gpu/drm/i915/intel_dp_mst.c | 4 ---- 1 file changed, 4 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_dp_mst.c') diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index a2bd698fe2f7..8d1b7033aaba 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -33,7 +33,6 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, struct intel_crtc_state *pipe_config) { - struct drm_device *dev = encoder->base.dev; struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); struct intel_digital_port *intel_dig_port = intel_mst->primary; struct intel_dp *intel_dp = &intel_dig_port->dp; @@ -92,9 +91,6 @@ static bool intel_dp_mst_compute_config(struct intel_encoder *encoder, pipe_config->dp_m_n.tu = slots; - if (IS_HASWELL(dev) || IS_BROADWELL(dev)) - hsw_dp_set_ddi_pll_sel(pipe_config); - return true; } -- cgit v1.2.3 From 1f7717552ef1306be3b7ed28c66c6eff550e3a23 Mon Sep 17 00:00:00 2001 From: Lyude Date: Wed, 16 Mar 2016 15:18:04 -0400 Subject: drm/i915: Fix race condition in intel_dp_destroy_mst_connector() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After unplugging a DP MST display from the system, we have to go through and destroy all of the DRM connectors associated with it since none of them are valid anymore. Unfortunately, intel_dp_destroy_mst_connector() doesn't do a good enough job of ensuring that throughout the destruction process that no modesettings can be done with the connectors. As it is right now, intel_dp_destroy_mst_connector() works like this: * Take all modeset locks * Clear the configuration of the crtc on the connector, if there is one * Drop all modeset locks, this is required because of circular dependency issues that arise with trying to remove the connector from sysfs with modeset locks held * Unregister the connector * Take all modeset locks, again * Do the rest of the required cleaning for destroying the connector * Finally drop all modeset locks for good This only works sometimes. During the destruction process, it's very possible that a userspace application will attempt to do a modesetting using the connector. When we drop the modeset locks, an ioctl handler such as drm_mode_setcrtc has the oppurtunity to take all of the modeset locks from us. When this happens, one thing leads to another and eventually we end up committing a mode with the non-existent connector: [drm:intel_dp_link_training_clock_recovery [i915]] *ERROR* failed to enable link training [drm:intel_dp_aux_ch] dp_aux_ch timeout status 0x7cf0001f [drm:intel_dp_start_link_train [i915]] *ERROR* failed to start channel equalization [drm:intel_dp_aux_ch] dp_aux_ch timeout status 0x7cf0001f [drm:intel_mst_pre_enable_dp [i915]] *ERROR* failed to allocate vcpi And in some cases, such as with the T460s using an MST dock, this results in breaking modesetting and/or panicking the system. To work around this, we now unregister the connector at the very beginning of intel_dp_destroy_mst_connector(), grab all the modesetting locks, and then hold them until we finish the rest of the function. CC: stable@vger.kernel.org Signed-off-by: Lyude Signed-off-by: Rob Clark Reviewed-by: Ville Syrjälä Signed-off-by: Daniel Vetter Link: http://patchwork.freedesktop.org/patch/msgid/1458155884-13877-1-git-send-email-cpaul@redhat.com --- drivers/gpu/drm/i915/intel_dp_mst.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_dp_mst.c') diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 8d1b7033aaba..94b4e833dadd 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -502,6 +502,8 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, struct intel_connector *intel_connector = to_intel_connector(connector); struct drm_device *dev = connector->dev; + intel_connector->unregister(intel_connector); + /* need to nuke the connector */ drm_modeset_lock_all(dev); if (connector->state->crtc) { @@ -515,11 +517,7 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, WARN(ret, "Disabling mst crtc failed with %i\n", ret); } - drm_modeset_unlock_all(dev); - intel_connector->unregister(intel_connector); - - drm_modeset_lock_all(dev); intel_connector_remove_from_fbdev(intel_connector); drm_connector_cleanup(connector); drm_modeset_unlock_all(dev); -- cgit v1.2.3 From 0552f7651bc233e5407ab06ba97a9d7c25e19580 Mon Sep 17 00:00:00 2001 From: Dave Airlie Date: Wed, 9 Mar 2016 11:14:38 +1000 Subject: drm/i915/mst: use reference counted connectors. (v3) Don't just free the connector when we get the destroy callback. Drop a reference to it, and set it's mst_port to NULL so no more mst work is done on it. v2: core mst accepts NULLs fine. Cleanup EDID code properly. v3: drop the extra reference we were taking. Reviewed-by: Daniel Vetter Signed-off-by: Dave Airlie --- drivers/gpu/drm/i915/intel_dp_mst.c | 43 +++++++++++++++++-------------------- drivers/gpu/drm/i915/intel_drv.h | 2 +- 2 files changed, 21 insertions(+), 24 deletions(-) (limited to 'drivers/gpu/drm/i915/intel_dp_mst.c') diff --git a/drivers/gpu/drm/i915/intel_dp_mst.c b/drivers/gpu/drm/i915/intel_dp_mst.c index 94b4e833dadd..b6bf7fd0b806 100644 --- a/drivers/gpu/drm/i915/intel_dp_mst.c +++ b/drivers/gpu/drm/i915/intel_dp_mst.c @@ -109,7 +109,7 @@ static void intel_mst_disable_dp(struct intel_encoder *encoder) DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links); - drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, intel_mst->port); + drm_dp_mst_reset_vcpi_slots(&intel_dp->mst_mgr, intel_mst->connector->port); ret = drm_dp_update_payload_part1(&intel_dp->mst_mgr); if (ret) { @@ -134,10 +134,11 @@ static void intel_mst_post_disable_dp(struct intel_encoder *encoder) /* and this can also fail */ drm_dp_update_payload_part2(&intel_dp->mst_mgr); - drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, intel_mst->port); + drm_dp_mst_deallocate_vcpi(&intel_dp->mst_mgr, intel_mst->connector->port); intel_dp->active_mst_links--; - intel_mst->port = NULL; + + intel_mst->connector = NULL; if (intel_dp->active_mst_links == 0) { intel_dig_port->base.post_disable(&intel_dig_port->base); intel_dp_sink_dpms(intel_dp, DRM_MODE_DPMS_OFF); @@ -177,7 +178,8 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder) found->encoder = encoder; DRM_DEBUG_KMS("%d\n", intel_dp->active_mst_links); - intel_mst->port = found->port; + + intel_mst->connector = found; if (intel_dp->active_mst_links == 0) { intel_prepare_ddi_buffer(&intel_dig_port->base); @@ -195,7 +197,7 @@ static void intel_mst_pre_enable_dp(struct intel_encoder *encoder) } ret = drm_dp_mst_allocate_vcpi(&intel_dp->mst_mgr, - intel_mst->port, + intel_mst->connector->port, intel_crtc->config->pbn, &slots); if (ret == false) { DRM_ERROR("failed to allocate vcpi\n"); @@ -244,7 +246,7 @@ static bool intel_dp_mst_enc_get_hw_state(struct intel_encoder *encoder, { struct intel_dp_mst_encoder *intel_mst = enc_to_mst(&encoder->base); *pipe = intel_mst->pipe; - if (intel_mst->port) + if (intel_mst->connector) return true; return false; } @@ -308,10 +310,11 @@ static int intel_dp_mst_get_ddc_modes(struct drm_connector *connector) struct edid *edid; int ret; - edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port); - if (!edid) - return 0; + if (!intel_dp) { + return intel_connector_update_modes(connector, NULL); + } + edid = drm_dp_mst_get_edid(connector, &intel_dp->mst_mgr, intel_connector->port); ret = intel_connector_update_modes(connector, edid); kfree(edid); @@ -324,6 +327,8 @@ intel_dp_mst_detect(struct drm_connector *connector, bool force) struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_dp *intel_dp = intel_connector->mst_port; + if (!intel_dp) + return connector_status_disconnected; return drm_dp_mst_detect_port(connector, &intel_dp->mst_mgr, intel_connector->port); } @@ -389,6 +394,8 @@ static struct drm_encoder *intel_mst_atomic_best_encoder(struct drm_connector *c struct intel_dp *intel_dp = intel_connector->mst_port; struct intel_crtc *crtc = to_intel_crtc(state->crtc); + if (!intel_dp) + return NULL; return &intel_dp->mst_encoders[crtc->pipe]->base.base; } @@ -396,6 +403,8 @@ static struct drm_encoder *intel_mst_best_encoder(struct drm_connector *connecto { struct intel_connector *intel_connector = to_intel_connector(connector); struct intel_dp *intel_dp = intel_connector->mst_port; + if (!intel_dp) + return NULL; return &intel_dp->mst_encoders[0]->base.base; } @@ -506,23 +515,11 @@ static void intel_dp_destroy_mst_connector(struct drm_dp_mst_topology_mgr *mgr, /* need to nuke the connector */ drm_modeset_lock_all(dev); - if (connector->state->crtc) { - struct drm_mode_set set; - int ret; - - memset(&set, 0, sizeof(set)); - set.crtc = connector->state->crtc, - - ret = drm_atomic_helper_set_config(&set); - - WARN(ret, "Disabling mst crtc failed with %i\n", ret); - } - intel_connector_remove_from_fbdev(intel_connector); - drm_connector_cleanup(connector); + intel_connector->mst_port = NULL; drm_modeset_unlock_all(dev); - kfree(intel_connector); + drm_connector_unreference(&intel_connector->base); DRM_DEBUG_KMS("\n"); } diff --git a/drivers/gpu/drm/i915/intel_drv.h b/drivers/gpu/drm/i915/intel_drv.h index b9f1304439e2..315c971b5b31 100644 --- a/drivers/gpu/drm/i915/intel_drv.h +++ b/drivers/gpu/drm/i915/intel_drv.h @@ -883,7 +883,7 @@ struct intel_dp_mst_encoder { struct intel_encoder base; enum pipe pipe; struct intel_digital_port *primary; - void *port; /* store this opaque as its illegal to dereference it */ + struct intel_connector *connector; }; static inline enum dpio_channel -- cgit v1.2.3