| From 3769e4c0af5b82c8ea21d037013cb9564dfaa51f Mon Sep 17 00:00:00 2001 |
| From: Wayne Lin <Wayne.Lin@amd.com> |
| Date: Wed, 16 Jun 2021 11:55:01 +0800 |
| Subject: drm/dp_mst: Avoid to mess up payload table by ports in stale topology |
| |
| From: Wayne Lin <Wayne.Lin@amd.com> |
| |
| commit 3769e4c0af5b82c8ea21d037013cb9564dfaa51f upstream. |
| |
| [Why] |
| After unplug/hotplug hub from the system, userspace might start to |
| clear stale payloads gradually. If we call drm_dp_mst_deallocate_vcpi() |
| to release stale VCPI of those ports which are not relating to current |
| topology, we have chane to wrongly clear active payload table entry for |
| current topology. |
| |
| E.g. |
| We have allocated VCPI 1 in current payload table and we call |
| drm_dp_mst_deallocate_vcpi() to clean VCPI 1 in stale topology. In |
| drm_dp_mst_deallocate_vcpi(), it will call drm_dp_mst_put_payload_id() |
| tp put VCPI 1 and which means ID 1 is available again. Thereafter, if we |
| want to allocate a new payload stream, it will find ID 1 is available by |
| drm_dp_mst_assign_payload_id(). However, ID 1 is being used |
| |
| [How] |
| Check target sink is relating to current topology or not before doing |
| any payload table update. |
| Searching upward to find the target sink's relevant root branch device. |
| If the found root branch device is not the same root of current |
| topology, don't update payload table. |
| |
| Changes since v1: |
| * Change debug macro to use drm_dbg_kms() instead |
| * Amend the commit message to add Cc tag. |
| |
| Signed-off-by: Wayne Lin <Wayne.Lin@amd.com> |
| Cc: stable@vger.kernel.org |
| Signed-off-by: Lyude Paul <lyude@redhat.com> |
| Link: https://patchwork.freedesktop.org/patch/msgid/20210616035501.3776-3-Wayne.Lin@amd.com |
| Reviewed-by: Lyude Paul <lyude@redhat.com> |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| --- |
| drivers/gpu/drm/drm_dp_mst_topology.c | 29 +++++++++++++++++++++++++++++ |
| 1 file changed, 29 insertions(+) |
| |
| --- a/drivers/gpu/drm/drm_dp_mst_topology.c |
| +++ b/drivers/gpu/drm/drm_dp_mst_topology.c |
| @@ -94,6 +94,9 @@ static int drm_dp_mst_register_i2c_bus(s |
| static void drm_dp_mst_unregister_i2c_bus(struct drm_dp_mst_port *port); |
| static void drm_dp_mst_kick_tx(struct drm_dp_mst_topology_mgr *mgr); |
| |
| +static bool drm_dp_mst_port_downstream_of_branch(struct drm_dp_mst_port *port, |
| + struct drm_dp_mst_branch *branch); |
| + |
| #define DBG_PREFIX "[dp_mst]" |
| |
| #define DP_STR(x) [DP_ ## x] = #x |
| @@ -3362,6 +3365,7 @@ int drm_dp_update_payload_part1(struct d |
| struct drm_dp_mst_port *port; |
| int i, j; |
| int cur_slots = 1; |
| + bool skip; |
| |
| mutex_lock(&mgr->payload_lock); |
| for (i = 0; i < mgr->max_payloads; i++) { |
| @@ -3376,6 +3380,14 @@ int drm_dp_update_payload_part1(struct d |
| port = container_of(vcpi, struct drm_dp_mst_port, |
| vcpi); |
| |
| + mutex_lock(&mgr->lock); |
| + skip = !drm_dp_mst_port_downstream_of_branch(port, mgr->mst_primary); |
| + mutex_unlock(&mgr->lock); |
| + |
| + if (skip) { |
| + drm_dbg_kms("Virtual channel %d is not in current topology\n", i); |
| + continue; |
| + } |
| /* Validated ports don't matter if we're releasing |
| * VCPI |
| */ |
| @@ -3475,6 +3487,7 @@ int drm_dp_update_payload_part2(struct d |
| struct drm_dp_mst_port *port; |
| int i; |
| int ret = 0; |
| + bool skip; |
| |
| mutex_lock(&mgr->payload_lock); |
| for (i = 0; i < mgr->max_payloads; i++) { |
| @@ -3484,6 +3497,13 @@ int drm_dp_update_payload_part2(struct d |
| |
| port = container_of(mgr->proposed_vcpis[i], struct drm_dp_mst_port, vcpi); |
| |
| + mutex_lock(&mgr->lock); |
| + skip = !drm_dp_mst_port_downstream_of_branch(port, mgr->mst_primary); |
| + mutex_unlock(&mgr->lock); |
| + |
| + if (skip) |
| + continue; |
| + |
| DRM_DEBUG_KMS("payload %d %d\n", i, mgr->payloads[i].payload_state); |
| if (mgr->payloads[i].payload_state == DP_PAYLOAD_LOCAL) { |
| ret = drm_dp_create_payload_step2(mgr, port, mgr->proposed_vcpis[i]->vcpi, &mgr->payloads[i]); |
| @@ -4565,9 +4585,18 @@ EXPORT_SYMBOL(drm_dp_mst_reset_vcpi_slot |
| void drm_dp_mst_deallocate_vcpi(struct drm_dp_mst_topology_mgr *mgr, |
| struct drm_dp_mst_port *port) |
| { |
| + bool skip; |
| + |
| if (!port->vcpi.vcpi) |
| return; |
| |
| + mutex_lock(&mgr->lock); |
| + skip = !drm_dp_mst_port_downstream_of_branch(port, mgr->mst_primary); |
| + mutex_unlock(&mgr->lock); |
| + |
| + if (skip) |
| + return; |
| + |
| drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); |
| port->vcpi.num_slots = 0; |
| port->vcpi.pbn = 0; |