Hi Harry, Thanks for the feedback — that's a fair point. Userspace does control enablement, and the driver force-disabling a CRTC from early_unregister() is the wrong layer.
The symptom I'm chasing: with a Thunderbolt 3 dock driving an LG Ultrawide, unplugging the dock unregisters the MST connector, but the CRTC that was driving it keeps its MST encoder assignment. On re-plug a new connector is created and the re-commit fails in drm_atomic_helper_check_modeset() with an encoder conflict (handle_conflicting_encoders), so the display stays dark until a full modeset (e.g. a session restart) tears everything down. So my real question is where this is supposed to be handled: is there something the driver should do during connector unregister to release the stale CRTC/encoder assignment, or is this expected to be resolved by userspace on the hotplug uevent? If the latter, is the compositor at fault for leaving the CRTC active? I only proposed the early_unregister() approach because it was the minimal thing that fixed the failure in testing — not because I'm confident it's correct. Happy to dig in whichever direction you point me. Thanks, David On Thu, Oct 1, 2026 at 9:54 AM Harry Wentland <[email protected]> wrote: > > > > On 2026-09-30 22:13, David Medina via B4 Relay wrote: > > From: David Medina <[email protected]> > > > > amdgpu_dm_mst_connector_early_unregister() releases the connector's > > sink but leaves the CRTC it was driving active and its MST encoder > > assigned. Because the connector is unregistered in the same step, > > userspace has no chance to disable the CRTC before it is gone. When the > > Why does userspace have no chance to disable the CRTC? It's the connector > that goes away, not the CRTC. > > Userspace controls enablement. The kernel driver shouldn't disable something > proactively based on a hotplug. > > Harry > > > same display is re-plugged a new MST connector is created, and the > > re-commit fails in drm_atomic_helper_check_modeset() because the stale > > connector still owns the encoder (handle_conflicting_encoders), leaving > > the display dark until a full modeset (e.g. a session restart) tears > > everything down. > > > > Disable the CRTC from the driver when the connector is torn down, so the > > MST encoder is released and the DC stream dropped. Reuse the > > drm_atomic_helper_disable_all() pattern: deactivate the CRTC, clear the > > mode, and disconnect the connector. > > > > Reproduced 100% of the time by unplugging and re-plugging the Thunderbolt > > dock driving the LG ULTRAWIDE: on re-plug the display stays dark and > > dmesg shows drm_atomic_helper_check_modeset() failing with an encoder > > conflict (handle_conflicting_encoders). Verified over four unplug/replug > > cycles with this patch applied. > > > > I am not certain that forcing a modeset from early_unregister() is the > > right approach, and the disable here is intentionally minimal: it > > deactivates the CRTC and disconnects the connector but does not > > add/detach the CRTC's affected planes the way > > drm_atomic_helper_disable_all() does. The minimal version resolves the > > failure in testing; I would welcome guidance on whether the full > > affected-planes teardown (or a different location) is required. > > > > Fixes: a1b27e99229a ("drm/amd/display: Implement MST Aux device > > registration") > > Signed-off-by: David Medina <[email protected]> > > --- > > .../amd/display/amdgpu_dm/amdgpu_dm_mst_types.c | 53 > > ++++++++++++++++++++++ > > 1 file changed, 53 insertions(+) > > > > diff --git a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c > > b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c > > index 045a7f88b754..24b146068739 100644 > > --- a/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c > > +++ b/drivers/gpu/drm/amd/display/amdgpu_dm/amdgpu_dm_mst_types.c > > @@ -29,6 +29,7 @@ > > #include <drm/display/drm_dp_mst_helper.h> > > #include <drm/drm_atomic.h> > > #include <drm/drm_atomic_helper.h> > > +#include <drm/drm_atomic_uapi.h> > > #include <drm/drm_fixed.h> > > #include <drm/drm_edid.h> > > #include "dm_services.h" > > @@ -227,6 +228,7 @@ amdgpu_dm_mst_connector_early_unregister(struct > > drm_connector *connector) > > struct amdgpu_dm_connector *root = aconnector->mst_root; > > struct dc_link *dc_link = aconnector->dc_link; > > struct dc_sink *dc_sink = aconnector->dc_sink; > > + struct drm_crtc *crtc = connector->state ? connector->state->crtc : > > NULL; > > > > drm_dp_mst_connector_early_unregister(connector, port); > > > > @@ -250,6 +252,57 @@ amdgpu_dm_mst_connector_early_unregister(struct > > drm_connector *connector) > > > > aconnector->mst_status = MST_STATUS_DEFAULT; > > drm_modeset_unlock(&root->mst_mgr.base.lock); > > + > > + /* > > + * The connector is being removed from the MST topology. If a CRTC is > > + * still driving it, force a modeset that disables the CRTC so that > > the > > + * MST encoder is released and the DC stream dropped. Otherwise, on a > > + * subsequent re-plug the stale CRTC/encoder assignment triggers an > > + * encoder conflict in drm_atomic_helper_check_modeset() and the > > display > > + * stays dark. > > + */ > > + if (crtc) { > > + struct drm_atomic_commit *state; > > + struct drm_connector_state *conn_state; > > + struct drm_crtc_state *crtc_state; > > + struct drm_modeset_acquire_ctx ctx; > > + int ret; > > + > > + drm_modeset_acquire_init(&ctx, 0); > > +retry: > > + state = drm_atomic_commit_alloc(connector->dev); > > + if (!state) > > + goto out; > > + state->acquire_ctx = &ctx; > > + > > + crtc_state = drm_atomic_get_crtc_state(state, crtc); > > + ret = PTR_ERR_OR_ZERO(crtc_state); > > + if (!ret) > > + crtc_state->active = false; > > + if (!ret) > > + ret = drm_atomic_set_mode_prop_for_crtc(crtc_state, > > NULL); > > + if (!ret) { > > + conn_state = drm_atomic_get_connector_state(state, > > connector); > > + ret = PTR_ERR_OR_ZERO(conn_state); > > + } > > + if (!ret) > > + ret = drm_atomic_set_crtc_for_connector(conn_state, > > NULL); > > + if (!ret) > > + ret = drm_atomic_commit(state); > > + > > + drm_atomic_commit_put(state); > > + if (ret == -EDEADLK) { > > + drm_modeset_backoff(&ctx); > > + goto retry; > > + } > > + if (ret) > > + drm_err(connector->dev, > > + "DM_MST: failed to disable CRTC for removed > > connector %s (%d)\n", > > + connector->name, ret); > > +out: > > + drm_modeset_drop_locks(&ctx); > > + drm_modeset_acquire_fini(&ctx); > > + } > > } > > > > static const struct drm_connector_funcs dm_dp_mst_connector_funcs = { > > > > --- > > base-commit: 551c722f40809618230001baccf219193e22fc5a > > change-id: 20260930-amd-mst-teardown-cab8a3731596 > > > > Best regards, > > -- > > David Medina <[email protected]> > -- David Medina 14901 SW 87th Ave Palmetto Bay, FL 33176 786-280-0880
