aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpu/drm/drm_dp_mst_topology.c
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-10-09 16:13:30 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2015-10-09 16:13:30 -0400
commit670aee3fc7ac37ae947f8b582d87b51d5fa36524 (patch)
tree9885998483d4506208e5aef9c13c8a86adea20bb /drivers/gpu/drm/drm_dp_mst_topology.c
parentd61e87ac53292a3138b4354b687558973686b6ca (diff)
parent55582bccdc1e89ecc973c260d46e247df675d4df (diff)
Merge branches 'pm-devfreq' and 'pm-cpufreq'
* pm-devfreq: PM / devfreq: fix double kfree PM / devfreq: Fix governor_store() * pm-cpufreq: cpufreq: prevent lockup on reading scaling_available_frequencies cpufreq: acpi_cpufreq: prevent crash on reading freqdomain_cpus
Diffstat (limited to 'drivers/gpu/drm/drm_dp_mst_topology.c')
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c85
1 files changed, 52 insertions, 33 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index e23df5fd3836..bf27a07dbce3 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -53,8 +53,8 @@ static int drm_dp_send_dpcd_write(struct drm_dp_mst_topology_mgr *mgr,
53 struct drm_dp_mst_port *port, 53 struct drm_dp_mst_port *port,
54 int offset, int size, u8 *bytes); 54 int offset, int size, u8 *bytes);
55 55
56static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, 56static void drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
57 struct drm_dp_mst_branch *mstb); 57 struct drm_dp_mst_branch *mstb);
58static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, 58static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
59 struct drm_dp_mst_branch *mstb, 59 struct drm_dp_mst_branch *mstb,
60 struct drm_dp_mst_port *port); 60 struct drm_dp_mst_port *port);
@@ -804,8 +804,6 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref)
804 struct drm_dp_mst_port *port, *tmp; 804 struct drm_dp_mst_port *port, *tmp;
805 bool wake_tx = false; 805 bool wake_tx = false;
806 806
807 cancel_work_sync(&mstb->mgr->work);
808
809 /* 807 /*
810 * destroy all ports - don't need lock 808 * destroy all ports - don't need lock
811 * as there are no more references to the mst branch 809 * as there are no more references to the mst branch
@@ -863,29 +861,33 @@ static void drm_dp_destroy_port(struct kref *kref)
863{ 861{
864 struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref); 862 struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref);
865 struct drm_dp_mst_topology_mgr *mgr = port->mgr; 863 struct drm_dp_mst_topology_mgr *mgr = port->mgr;
864
866 if (!port->input) { 865 if (!port->input) {
867 port->vcpi.num_slots = 0; 866 port->vcpi.num_slots = 0;
868 867
869 kfree(port->cached_edid); 868 kfree(port->cached_edid);
870 869
871 /* we can't destroy the connector here, as 870 /*
872 we might be holding the mode_config.mutex 871 * The only time we don't have a connector
873 from an EDID retrieval */ 872 * on an output port is if the connector init
873 * fails.
874 */
874 if (port->connector) { 875 if (port->connector) {
876 /* we can't destroy the connector here, as
877 * we might be holding the mode_config.mutex
878 * from an EDID retrieval */
879
875 mutex_lock(&mgr->destroy_connector_lock); 880 mutex_lock(&mgr->destroy_connector_lock);
876 list_add(&port->next, &mgr->destroy_connector_list); 881 list_add(&port->next, &mgr->destroy_connector_list);
877 mutex_unlock(&mgr->destroy_connector_lock); 882 mutex_unlock(&mgr->destroy_connector_lock);
878 schedule_work(&mgr->destroy_connector_work); 883 schedule_work(&mgr->destroy_connector_work);
879 return; 884 return;
880 } 885 }
886 /* no need to clean up vcpi
887 * as if we have no connector we never setup a vcpi */
881 drm_dp_port_teardown_pdt(port, port->pdt); 888 drm_dp_port_teardown_pdt(port, port->pdt);
882
883 if (!port->input && port->vcpi.vcpi > 0)
884 drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
885 } 889 }
886 kfree(port); 890 kfree(port);
887
888 (*mgr->cbs->hotplug)(mgr);
889} 891}
890 892
891static void drm_dp_put_port(struct drm_dp_mst_port *port) 893static void drm_dp_put_port(struct drm_dp_mst_port *port)
@@ -1027,8 +1029,8 @@ static void drm_dp_check_port_guid(struct drm_dp_mst_branch *mstb,
1027 } 1029 }
1028} 1030}
1029 1031
1030static void build_mst_prop_path(struct drm_dp_mst_port *port, 1032static void build_mst_prop_path(const struct drm_dp_mst_branch *mstb,
1031 struct drm_dp_mst_branch *mstb, 1033 int pnum,
1032 char *proppath, 1034 char *proppath,
1033 size_t proppath_size) 1035 size_t proppath_size)
1034{ 1036{
@@ -1041,7 +1043,7 @@ static void build_mst_prop_path(struct drm_dp_mst_port *port,
1041 snprintf(temp, sizeof(temp), "-%d", port_num); 1043 snprintf(temp, sizeof(temp), "-%d", port_num);
1042 strlcat(proppath, temp, proppath_size); 1044 strlcat(proppath, temp, proppath_size);
1043 } 1045 }
1044 snprintf(temp, sizeof(temp), "-%d", port->port_num); 1046 snprintf(temp, sizeof(temp), "-%d", pnum);
1045 strlcat(proppath, temp, proppath_size); 1047 strlcat(proppath, temp, proppath_size);
1046} 1048}
1047 1049
@@ -1105,22 +1107,32 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
1105 drm_dp_port_teardown_pdt(port, old_pdt); 1107 drm_dp_port_teardown_pdt(port, old_pdt);
1106 1108
1107 ret = drm_dp_port_setup_pdt(port); 1109 ret = drm_dp_port_setup_pdt(port);
1108 if (ret == true) { 1110 if (ret == true)
1109 drm_dp_send_link_address(mstb->mgr, port->mstb); 1111 drm_dp_send_link_address(mstb->mgr, port->mstb);
1110 port->mstb->link_address_sent = true;
1111 }
1112 } 1112 }
1113 1113
1114 if (created && !port->input) { 1114 if (created && !port->input) {
1115 char proppath[255]; 1115 char proppath[255];
1116 build_mst_prop_path(port, mstb, proppath, sizeof(proppath));
1117 port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath);
1118 1116
1119 if (port->port_num >= 8) { 1117 build_mst_prop_path(mstb, port->port_num, proppath, sizeof(proppath));
1118 port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath);
1119 if (!port->connector) {
1120 /* remove it from the port list */
1121 mutex_lock(&mstb->mgr->lock);
1122 list_del(&port->next);
1123 mutex_unlock(&mstb->mgr->lock);
1124 /* drop port list reference */
1125 drm_dp_put_port(port);
1126 goto out;
1127 }
1128 if (port->port_num >= DP_MST_LOGICAL_PORT_0) {
1120 port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); 1129 port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
1130 drm_mode_connector_set_tile_property(port->connector);
1121 } 1131 }
1132 (*mstb->mgr->cbs->register_connector)(port->connector);
1122 } 1133 }
1123 1134
1135out:
1124 /* put reference to this port */ 1136 /* put reference to this port */
1125 drm_dp_put_port(port); 1137 drm_dp_put_port(port);
1126} 1138}
@@ -1202,10 +1214,9 @@ static void drm_dp_check_and_send_link_address(struct drm_dp_mst_topology_mgr *m
1202{ 1214{
1203 struct drm_dp_mst_port *port; 1215 struct drm_dp_mst_port *port;
1204 struct drm_dp_mst_branch *mstb_child; 1216 struct drm_dp_mst_branch *mstb_child;
1205 if (!mstb->link_address_sent) { 1217 if (!mstb->link_address_sent)
1206 drm_dp_send_link_address(mgr, mstb); 1218 drm_dp_send_link_address(mgr, mstb);
1207 mstb->link_address_sent = true; 1219
1208 }
1209 list_for_each_entry(port, &mstb->ports, next) { 1220 list_for_each_entry(port, &mstb->ports, next) {
1210 if (port->input) 1221 if (port->input)
1211 continue; 1222 continue;
@@ -1458,8 +1469,8 @@ static void drm_dp_queue_down_tx(struct drm_dp_mst_topology_mgr *mgr,
1458 mutex_unlock(&mgr->qlock); 1469 mutex_unlock(&mgr->qlock);
1459} 1470}
1460 1471
1461static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr, 1472static void drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
1462 struct drm_dp_mst_branch *mstb) 1473 struct drm_dp_mst_branch *mstb)
1463{ 1474{
1464 int len; 1475 int len;
1465 struct drm_dp_sideband_msg_tx *txmsg; 1476 struct drm_dp_sideband_msg_tx *txmsg;
@@ -1467,11 +1478,12 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
1467 1478
1468 txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); 1479 txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
1469 if (!txmsg) 1480 if (!txmsg)
1470 return -ENOMEM; 1481 return;
1471 1482
1472 txmsg->dst = mstb; 1483 txmsg->dst = mstb;
1473 len = build_link_address(txmsg); 1484 len = build_link_address(txmsg);
1474 1485
1486 mstb->link_address_sent = true;
1475 drm_dp_queue_down_tx(mgr, txmsg); 1487 drm_dp_queue_down_tx(mgr, txmsg);
1476 1488
1477 ret = drm_dp_mst_wait_tx_reply(mstb, txmsg); 1489 ret = drm_dp_mst_wait_tx_reply(mstb, txmsg);
@@ -1499,11 +1511,12 @@ static int drm_dp_send_link_address(struct drm_dp_mst_topology_mgr *mgr,
1499 } 1511 }
1500 (*mgr->cbs->hotplug)(mgr); 1512 (*mgr->cbs->hotplug)(mgr);
1501 } 1513 }
1502 } else 1514 } else {
1515 mstb->link_address_sent = false;
1503 DRM_DEBUG_KMS("link address failed %d\n", ret); 1516 DRM_DEBUG_KMS("link address failed %d\n", ret);
1517 }
1504 1518
1505 kfree(txmsg); 1519 kfree(txmsg);
1506 return 0;
1507} 1520}
1508 1521
1509static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, 1522static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
@@ -1978,6 +1991,8 @@ void drm_dp_mst_topology_mgr_suspend(struct drm_dp_mst_topology_mgr *mgr)
1978 drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL, 1991 drm_dp_dpcd_writeb(mgr->aux, DP_MSTM_CTRL,
1979 DP_MST_EN | DP_UPSTREAM_IS_SRC); 1992 DP_MST_EN | DP_UPSTREAM_IS_SRC);
1980 mutex_unlock(&mgr->lock); 1993 mutex_unlock(&mgr->lock);
1994 flush_work(&mgr->work);
1995 flush_work(&mgr->destroy_connector_work);
1981} 1996}
1982EXPORT_SYMBOL(drm_dp_mst_topology_mgr_suspend); 1997EXPORT_SYMBOL(drm_dp_mst_topology_mgr_suspend);
1983 1998
@@ -2263,10 +2278,10 @@ struct edid *drm_dp_mst_get_edid(struct drm_connector *connector, struct drm_dp_
2263 2278
2264 if (port->cached_edid) 2279 if (port->cached_edid)
2265 edid = drm_edid_duplicate(port->cached_edid); 2280 edid = drm_edid_duplicate(port->cached_edid);
2266 else 2281 else {
2267 edid = drm_get_edid(connector, &port->aux.ddc); 2282 edid = drm_get_edid(connector, &port->aux.ddc);
2268 2283 drm_mode_connector_set_tile_property(connector);
2269 drm_mode_connector_set_tile_property(connector); 2284 }
2270 drm_dp_put_port(port); 2285 drm_dp_put_port(port);
2271 return edid; 2286 return edid;
2272} 2287}
@@ -2671,7 +2686,7 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
2671{ 2686{
2672 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); 2687 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
2673 struct drm_dp_mst_port *port; 2688 struct drm_dp_mst_port *port;
2674 2689 bool send_hotplug = false;
2675 /* 2690 /*
2676 * Not a regular list traverse as we have to drop the destroy 2691 * Not a regular list traverse as we have to drop the destroy
2677 * connector lock before destroying the connector, to avoid AB->BA 2692 * connector lock before destroying the connector, to avoid AB->BA
@@ -2694,7 +2709,10 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
2694 if (!port->input && port->vcpi.vcpi > 0) 2709 if (!port->input && port->vcpi.vcpi > 0)
2695 drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); 2710 drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
2696 kfree(port); 2711 kfree(port);
2712 send_hotplug = true;
2697 } 2713 }
2714 if (send_hotplug)
2715 (*mgr->cbs->hotplug)(mgr);
2698} 2716}
2699 2717
2700/** 2718/**
@@ -2747,6 +2765,7 @@ EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init);
2747 */ 2765 */
2748void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr) 2766void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr)
2749{ 2767{
2768 flush_work(&mgr->work);
2750 flush_work(&mgr->destroy_connector_work); 2769 flush_work(&mgr->destroy_connector_work);
2751 mutex_lock(&mgr->payload_lock); 2770 mutex_lock(&mgr->payload_lock);
2752 kfree(mgr->payloads); 2771 kfree(mgr->payloads);