Skip to content

Commit c54c737

Browse files
Lyudeatseanpaul
authored andcommitted
drm/dp_mst: Skip validating ports during destruction, just ref
Jerry Zuo pointed out a rather obscure hotplugging issue that it seems I accidentally introduced into DRM two years ago. Pretend we have a topology like this: |- DP-1: mst_primary |- DP-4: active display |- DP-5: disconnected |- DP-6: active hub |- DP-7: active display |- DP-8: disconnected |- DP-9: disconnected If we unplug DP-6, the topology starting at DP-7 will be destroyed but it's payloads will live on in DP-1's VCPI allocations and thus require removal. However, this removal currently fails because drm_dp_update_payload_part1() will (rightly so) try to validate the port before accessing it, fail then abort. If we keep going, eventually we run the MST hub out of bandwidth and all new allocations will start to fail (or in my case; all new displays just start flickering a ton). We could just teach drm_dp_update_payload_part1() not to drop the port ref in this case, but then we also need to teach drm_dp_destroy_payload_step1() to do the same thing, then hope no one ever adds anything to the that requires a validated port reference in drm_dp_destroy_connector_work(). Kind of sketchy. So let's go with a more clever solution: any port that drm_dp_destroy_connector_work() interacts with is guaranteed to still exist in memory until we say so. While said port might not be valid we don't really care: that's the whole reason we're destroying it in the first place! So, teach drm_dp_get_validated_port_ref() to use the all mighty current_work() function to avoid attempting to validate ports from the context of mgr->destroy_connector_work. I can't see any situation where this wouldn't be safe, and this avoids having to play whack-a-mole in the future of trying to work around port validation. Signed-off-by: Lyude Paul <lyude@redhat.com> Fixes: 263efde ("drm/dp/mst: Get validated port ref in drm_dp_update_payload_part1()") Reported-by: Jerry Zuo <Jerry.Zuo@amd.com> Cc: Jerry Zuo <Jerry.Zuo@amd.com> Cc: Harry Wentland <Harry.Wentland@amd.com> Cc: <stable@vger.kernel.org> # v4.6+ Reviewed-by: Dave Airlie <airlied@redhat.com> Link: https://patchwork.freedesktop.org/patch/msgid/20181113224613.28809-1-lyude@redhat.com Signed-off-by: Sean Paul <seanpaul@chromium.org>
1 parent 2e6e902 commit c54c737

File tree

1 file changed

+13
-2
lines changed

1 file changed

+13
-2
lines changed

drivers/gpu/drm/drm_dp_mst_topology.c

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,9 +1023,20 @@ static struct drm_dp_mst_port *drm_dp_mst_get_port_ref_locked(struct drm_dp_mst_
10231023
static struct drm_dp_mst_port *drm_dp_get_validated_port_ref(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_port *port)
10241024
{
10251025
struct drm_dp_mst_port *rport = NULL;
1026+
10261027
mutex_lock(&mgr->lock);
1027-
if (mgr->mst_primary)
1028-
rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary, port);
1028+
/*
1029+
* Port may or may not be 'valid' but we don't care about that when
1030+
* destroying the port and we are guaranteed that the port pointer
1031+
* will be valid until we've finished
1032+
*/
1033+
if (current_work() == &mgr->destroy_connector_work) {
1034+
kref_get(&port->kref);
1035+
rport = port;
1036+
} else if (mgr->mst_primary) {
1037+
rport = drm_dp_mst_get_port_ref_locked(mgr->mst_primary,
1038+
port);
1039+
}
10291040
mutex_unlock(&mgr->lock);
10301041
return rport;
10311042
}

0 commit comments

Comments
 (0)