OK so - this has become a bit of a larger rabbit hole. I've been putting quite a bit of work into this and I think I'm starting to make some progress - although on a different aspect of this issue. After talking with danvet they realized that we're also potentially not handling encoder stealing with MST correctly - which we need to do in order to know that we're correctly pulling in every related crtc/connector into the state - along with avoiding encoder conflicts if something tries to use a GPU's DP encoder in SST mode while it's driving other displays in MST mode. So - it seems this will likely need to be solved first before we can deal with ensuring that we perform the correct CRTC waits in atomic commits with the MST helpers. This has been pretty painful to figure out, but I think I'm starting to make some progress - but I'd really appreciate getting some feedback on this approach I've came up with so I maybe can skip having to rewrite it later. So: to clarify the problem, it boils down to something like this: State 1: * DP-1 (hosts MST topology, so is disconnected + no encoder) * MST topology * DP-2 (has display) * DP-3 (has display) (In hardware) * drm_encoder A drives: * DP-2 * DP-3 (In software) * drm_encoder A unused * Fake MST drm_encoder B -> DP-2 * Fake MST drm_encoder C -> DP-3 Problems: * DP-1 gets disconnected, MST topology disappears * We disable maybe 1 display * DP-1 is disconnected, suddenly replaced with SST display * Driver tries to assign drm_encoder A to new DP-1 display *** Error! drm_encoder A is still driving fake encoders B and C *** I'm not sure if the exact above example would actually happen - you might need to do some tricks to get it into such a state. But you get the general idea - there's missing coverage with how we handle encoder conflicts when it comes to encoders that aren't directly handling CRTCs. If we can fix this, I think we should be able to reliably figure out every CRTC involved in modesets like this - and ensure that nonblocking modesets come up with the right CRTC dependencies. My current idea for handling this is as follows: * Add the following fields to drm_connector_state: * reserved_encoder → an encoder that is "reserved" by the connector, but is not directly attached to a monitor. Note reserved connectors cannot have CRTCs attached to them. When a connector has no more CRTCs reserved, it should lose it's reserved encoder. * dependent_crtcs → a bitmask of CRTCs that depend on this connector's state, but are not directly attached to it. * Add the following fields to drm_crtc_state: * connector_dependency → a connector whose state this CRTC relies on, but is not directly attached to. This connector must be pulled into the atomic state whenever this CRTC requires a modeset. The reason for adding all of these fields to drm_connector_state and drm_crtc_state is because I don't think it's possible for us to rely on a particular private object being in all atomic states - so we need a way for the DRM core to be able to understand these object relationships on it's own and reference them from any type of atomic state change so that we can pull in dependent CRTCs as needed.