aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDave Airlie <airlied@redhat.com>2015-09-15 20:37:28 -0400
committerDave Airlie <airlied@redhat.com>2015-10-02 01:34:40 -0400
commitdf4839fdc9b3c922586b945f062f38cbbda022bb (patch)
tree8ff48911fd93882d61dbaee4ee086e9300717972
parent1c960876be7cffd2798a9e2be090e0a5afaee895 (diff)
drm/dp/mst: fixup handling hotplug on port removal.
output ports should always have a connector, unless in the rare case connector allocation fails in the driver. In this case we only need to teardown the pdt, and free the struct, and there is no need to send a hotplug msg. In the case were we add the port to the destroy list we need to send a hotplug if we destroy any connectors, so userspace knows to reprobe stuff. this patch also handles port->connector allocation failing which should be a rare event, but makes the code consistent. Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Cc: stable@vger.kernel.org Signed-off-by: Dave Airlie <airlied@redhat.com>
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c36
1 files changed, 26 insertions, 10 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 87112d389fd4..d11052c2f84a 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -863,29 +863,33 @@ static void drm_dp_destroy_port(struct kref *kref)
863{ 863{
864 struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref); 864 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; 865 struct drm_dp_mst_topology_mgr *mgr = port->mgr;
866
866 if (!port->input) { 867 if (!port->input) {
867 port->vcpi.num_slots = 0; 868 port->vcpi.num_slots = 0;
868 869
869 kfree(port->cached_edid); 870 kfree(port->cached_edid);
870 871
871 /* we can't destroy the connector here, as 872 /*
872 we might be holding the mode_config.mutex 873 * The only time we don't have a connector
873 from an EDID retrieval */ 874 * on an output port is if the connector init
875 * fails.
876 */
874 if (port->connector) { 877 if (port->connector) {
878 /* we can't destroy the connector here, as
879 * we might be holding the mode_config.mutex
880 * from an EDID retrieval */
881
875 mutex_lock(&mgr->destroy_connector_lock); 882 mutex_lock(&mgr->destroy_connector_lock);
876 list_add(&port->next, &mgr->destroy_connector_list); 883 list_add(&port->next, &mgr->destroy_connector_list);
877 mutex_unlock(&mgr->destroy_connector_lock); 884 mutex_unlock(&mgr->destroy_connector_lock);
878 schedule_work(&mgr->destroy_connector_work); 885 schedule_work(&mgr->destroy_connector_work);
879 return; 886 return;
880 } 887 }
888 /* no need to clean up vcpi
889 * as if we have no connector we never setup a vcpi */
881 drm_dp_port_teardown_pdt(port, port->pdt); 890 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 } 891 }
886 kfree(port); 892 kfree(port);
887
888 (*mgr->cbs->hotplug)(mgr);
889} 893}
890 894
891static void drm_dp_put_port(struct drm_dp_mst_port *port) 895static void drm_dp_put_port(struct drm_dp_mst_port *port)
@@ -1116,12 +1120,21 @@ static void drm_dp_add_port(struct drm_dp_mst_branch *mstb,
1116 1120
1117 build_mst_prop_path(mstb, port->port_num, proppath, sizeof(proppath)); 1121 build_mst_prop_path(mstb, port->port_num, proppath, sizeof(proppath));
1118 port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath); 1122 port->connector = (*mstb->mgr->cbs->add_connector)(mstb->mgr, port, proppath);
1119 1123 if (!port->connector) {
1124 /* remove it from the port list */
1125 mutex_lock(&mstb->mgr->lock);
1126 list_del(&port->next);
1127 mutex_unlock(&mstb->mgr->lock);
1128 /* drop port list reference */
1129 drm_dp_put_port(port);
1130 goto out;
1131 }
1120 if (port->port_num >= 8) { 1132 if (port->port_num >= 8) {
1121 port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc); 1133 port->cached_edid = drm_get_edid(port->connector, &port->aux.ddc);
1122 } 1134 }
1123 } 1135 }
1124 1136
1137out:
1125 /* put reference to this port */ 1138 /* put reference to this port */
1126 drm_dp_put_port(port); 1139 drm_dp_put_port(port);
1127} 1140}
@@ -2672,7 +2685,7 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
2672{ 2685{
2673 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); 2686 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
2674 struct drm_dp_mst_port *port; 2687 struct drm_dp_mst_port *port;
2675 2688 bool send_hotplug = false;
2676 /* 2689 /*
2677 * Not a regular list traverse as we have to drop the destroy 2690 * Not a regular list traverse as we have to drop the destroy
2678 * connector lock before destroying the connector, to avoid AB->BA 2691 * connector lock before destroying the connector, to avoid AB->BA
@@ -2695,7 +2708,10 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
2695 if (!port->input && port->vcpi.vcpi > 0) 2708 if (!port->input && port->vcpi.vcpi > 0)
2696 drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); 2709 drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
2697 kfree(port); 2710 kfree(port);
2711 send_hotplug = true;
2698 } 2712 }
2713 if (send_hotplug)
2714 (*mgr->cbs->hotplug)(mgr);
2699} 2715}
2700 2716
2701/** 2717/**