drm_dp_remove_payload_part1() doesn't send the removal of a payload to the branch devices if the port of the payload is not in the topology anymore. The caller can't tell, so it generates the ACT and waits for it afterwards, polling DPCD 0x2c0 for up to 3 seconds, although the payload table of the branch devices wasn't changed and the ACT will never be handled.
Return whether the removal was sent, so that drivers can skip the ACT in the other case. The existing callers ignore the return value and are not affected. Signed-off-by: Xiao Lu <[email protected]> --- Notes: v2: also require the payload to have been allocated to the DFP or the remote end for the return value to be true, not only that the port is in the topology (Sashiko). drivers/gpu/drm/display/drm_dp_mst_topology.c | 17 ++++++++++++++++- include/drm/display/drm_dp_mst_helper.h | 2 +- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/drivers/gpu/drm/display/drm_dp_mst_topology.c b/drivers/gpu/drm/display/drm_dp_mst_topology.c index 7ce9e2127..1763dd0ae 100644 --- a/drivers/gpu/drm/display/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/display/drm_dp_mst_topology.c @@ -3369,18 +3369,31 @@ EXPORT_SYMBOL(drm_dp_add_payload_part1); * Removes a payload along the virtual channel if it was successfully allocated. * After calling this, the driver should set HW to generate ACT and then switch to new * payload allocation state. + * + * Returns: + * %true if the payload was removed from the branch devices, so the driver + * should generate the ACT and wait for it. %false if nothing was sent to the + * branch devices, because the port of the payload is not in the topology + * anymore or the payload was never allocated to the DFP, so there is no ACT + * to generate or wait for. */ -void drm_dp_remove_payload_part1(struct drm_dp_mst_topology_mgr *mgr, +bool drm_dp_remove_payload_part1(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_topology_state *mst_state, struct drm_dp_mst_atomic_payload *payload) { /* Remove remote payload allocation */ bool send_remove = false; + bool removed; mutex_lock(&mgr->lock); send_remove = drm_dp_mst_port_downstream_of_branch(payload->port, mgr->mst_primary); mutex_unlock(&mgr->lock); + /* Only a payload allocated to the DFP or the remote end is removed from the branches */ + removed = send_remove && + (payload->payload_allocation_status == DRM_DP_MST_PAYLOAD_ALLOCATION_DFP || + payload->payload_allocation_status == DRM_DP_MST_PAYLOAD_ALLOCATION_REMOTE); + if (send_remove) drm_dp_destroy_payload_at_remote_and_dfp(mgr, mst_state, payload); else @@ -3388,6 +3401,8 @@ void drm_dp_remove_payload_part1(struct drm_dp_mst_topology_mgr *mgr, payload->vcpi); payload->payload_allocation_status = DRM_DP_MST_PAYLOAD_ALLOCATION_LOCAL; + + return removed; } EXPORT_SYMBOL(drm_dp_remove_payload_part1); diff --git a/include/drm/display/drm_dp_mst_helper.h b/include/drm/display/drm_dp_mst_helper.h index 27658bfb5..d5a3bbb28 100644 --- a/include/drm/display/drm_dp_mst_helper.h +++ b/include/drm/display/drm_dp_mst_helper.h @@ -885,7 +885,7 @@ int drm_dp_add_payload_part1(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_atomic_payload *payload); int drm_dp_add_payload_part2(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_atomic_payload *payload); -void drm_dp_remove_payload_part1(struct drm_dp_mst_topology_mgr *mgr, +bool drm_dp_remove_payload_part1(struct drm_dp_mst_topology_mgr *mgr, struct drm_dp_mst_topology_state *mst_state, struct drm_dp_mst_atomic_payload *payload); void drm_dp_remove_payload_part2(struct drm_dp_mst_topology_mgr *mgr, -- 2.43.0
