aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_dp_mst_topology.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/gpu/drm/drm_dp_mst_topology.c')
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c68
1 files changed, 60 insertions, 8 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 132581ca4ad8..b0487c9f018c 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -867,8 +867,16 @@ static void drm_dp_destroy_port(struct kref *kref)
867 port->vcpi.num_slots = 0; 867 port->vcpi.num_slots = 0;
868 868
869 kfree(port->cached_edid); 869 kfree(port->cached_edid);
870 if (port->connector) 870
871 (*port->mgr->cbs->destroy_connector)(mgr, port->connector); 871 /* we can't destroy the connector here, as
872 we might be holding the mode_config.mutex
873 from an EDID retrieval */
874 if (port->connector) {
875 mutex_lock(&mgr->destroy_connector_lock);
876 list_add(&port->connector->destroy_list, &mgr->destroy_connector_list);
877 mutex_unlock(&mgr->destroy_connector_lock);
878 schedule_work(&mgr->destroy_connector_work);
879 }
872 drm_dp_port_teardown_pdt(port, port->pdt); 880 drm_dp_port_teardown_pdt(port, port->pdt);
873 881
874 if (!port->input && port->vcpi.vcpi > 0) 882 if (!port->input && port->vcpi.vcpi > 0)
@@ -1163,6 +1171,8 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_
1163 struct drm_dp_mst_port *port; 1171 struct drm_dp_mst_port *port;
1164 int i; 1172 int i;
1165 /* find the port by iterating down */ 1173 /* find the port by iterating down */
1174
1175 mutex_lock(&mgr->lock);
1166 mstb = mgr->mst_primary; 1176 mstb = mgr->mst_primary;
1167 1177
1168 for (i = 0; i < lct - 1; i++) { 1178 for (i = 0; i < lct - 1; i++) {
@@ -1182,6 +1192,7 @@ static struct drm_dp_mst_branch *drm_dp_get_mst_branch_device(struct drm_dp_mst_
1182 } 1192 }
1183 } 1193 }
1184 kref_get(&mstb->kref); 1194 kref_get(&mstb->kref);
1195 mutex_unlock(&mgr->lock);
1185 return mstb; 1196 return mstb;
1186} 1197}
1187 1198
@@ -1189,7 +1200,7 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m
1189 struct drm_dp_mst_branch *mstb) 1200 struct drm_dp_mst_branch *mstb)
1190{ 1201{
1191 struct drm_dp_mst_port *port; 1202 struct drm_dp_mst_port *port;
1192 1203 struct drm_dp_mst_branch *mstb_child;
1193 if (!mstb->link_address_sent) { 1204 if (!mstb->link_address_sent) {
1194 drm_dp_send_link_address(mgr, mstb); 1205 drm_dp_send_link_address(mgr, mstb);
1195 mstb->link_address_sent = true; 1206 mstb->link_address_sent = true;
@@ -1204,17 +1215,31 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m
1204 if (!port->available_pbn) 1215 if (!port->available_pbn)
1205 drm_dp_send_enum_path_resources(mgr, mstb, port); 1216 drm_dp_send_enum_path_resources(mgr, mstb, port);
1206 1217
1207 if (port->mstb) 1218 if (port->mstb) {
1208 drm_dp_check_and_send_link_address(mgr, port->mstb); 1219 mstb_child = drm_dp_get_validated_mstb_ref(mgr, port->mstb);
1220 if (mstb_child) {
1221 drm_dp_check_and_send_link_address(mgr, mstb_child);
1222 drm_dp_put_mst_branch_device(mstb_child);
1223 }
1224 }
1209 } 1225 }
1210} 1226}
1211 1227
1212static void drm_dp_mst_link_probe_work(struct work_struct *work) 1228static void drm_dp_mst_link_probe_work(struct work_struct *work)
1213{ 1229{
1214 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, work); 1230 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, work);
1231 struct drm_dp_mst_branch *mstb;
1215 1232
1216 drm_dp_check_and_send_link_address(mgr, mgr->mst_primary); 1233 mutex_lock(&mgr->lock);
1217 1234 mstb = mgr->mst_primary;
1235 if (mstb) {
1236 kref_get(&mstb->kref);
1237 }
1238 mutex_unlock(&mgr->lock);
1239 if (mstb) {
1240 drm_dp_check_and_send_link_address(mgr, mstb);
1241 drm_dp_put_mst_branch_device(mstb);
1242 }
1218} 1243}
1219 1244
1220static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr, 1245static bool drm_dp_validate_guid(struct drm_dp_mst_topology_mgr *mgr,
@@ -1269,7 +1294,6 @@ retry:
1269 goto retry; 1294 goto retry;
1270 } 1295 }
1271 DRM_DEBUG_KMS("failed to dpcd write %d %d\n", tosend, ret); 1296 DRM_DEBUG_KMS("failed to dpcd write %d %d\n", tosend, ret);
1272 WARN(1, "fail\n");
1273 1297
1274 return -EIO; 1298 return -EIO;
1275 } 1299 }
@@ -2632,6 +2656,30 @@ static void drm_dp_tx_work(struct work_struct *work)
2632 mutex_unlock(&mgr->qlock); 2656 mutex_unlock(&mgr->qlock);
2633} 2657}
2634 2658
2659static void drm_dp_destroy_connector_work(struct work_struct *work)
2660{
2661 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
2662 struct drm_connector *connector;
2663
2664 /*
2665 * Not a regular list traverse as we have to drop the destroy
2666 * connector lock before destroying the connector, to avoid AB->BA
2667 * ordering between this lock and the config mutex.
2668 */
2669 for (;;) {
2670 mutex_lock(&mgr->destroy_connector_lock);
2671 connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list);
2672 if (!connector) {
2673 mutex_unlock(&mgr->destroy_connector_lock);
2674 break;
2675 }
2676 list_del(&connector->destroy_list);
2677 mutex_unlock(&mgr->destroy_connector_lock);
2678
2679 mgr->cbs->destroy_connector(mgr, connector);
2680 }
2681}
2682
2635/** 2683/**
2636 * drm_dp_mst_topology_mgr_init - initialise a topology manager 2684 * drm_dp_mst_topology_mgr_init - initialise a topology manager
2637 * @mgr: manager struct to initialise 2685 * @mgr: manager struct to initialise
@@ -2651,10 +2699,13 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr,
2651 mutex_init(&mgr->lock); 2699 mutex_init(&mgr->lock);
2652 mutex_init(&mgr->qlock); 2700 mutex_init(&mgr->qlock);
2653 mutex_init(&mgr->payload_lock); 2701 mutex_init(&mgr->payload_lock);
2702 mutex_init(&mgr->destroy_connector_lock);
2654 INIT_LIST_HEAD(&mgr->tx_msg_upq); 2703 INIT_LIST_HEAD(&mgr->tx_msg_upq);
2655 INIT_LIST_HEAD(&mgr->tx_msg_downq); 2704 INIT_LIST_HEAD(&mgr->tx_msg_downq);
2705 INIT_LIST_HEAD(&mgr->destroy_connector_list);
2656 INIT_WORK(&mgr->work, drm_dp_mst_link_probe_work); 2706 INIT_WORK(&mgr->work, drm_dp_mst_link_probe_work);
2657 INIT_WORK(&mgr->tx_work, drm_dp_tx_work); 2707 INIT_WORK(&mgr->tx_work, drm_dp_tx_work);
2708 INIT_WORK(&mgr->destroy_connector_work, drm_dp_destroy_connector_work);
2658 init_waitqueue_head(&mgr->tx_waitq); 2709 init_waitqueue_head(&mgr->tx_waitq);
2659 mgr->dev = dev; 2710 mgr->dev = dev;
2660 mgr->aux = aux; 2711 mgr->aux = aux;
@@ -2679,6 +2730,7 @@ EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init);
2679 */ 2730 */
2680void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr) 2731void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr)
2681{ 2732{
2733 flush_work(&mgr->destroy_connector_work);
2682 mutex_lock(&mgr->payload_lock); 2734 mutex_lock(&mgr->payload_lock);
2683 kfree(mgr->payloads); 2735 kfree(mgr->payloads);
2684 mgr->payloads = NULL; 2736 mgr->payloads = NULL;