aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaarten Lankhorst <maarten.lankhorst@linux.intel.com>2015-08-11 03:54:29 -0400
committerJani Nikula <jani.nikula@intel.com>2015-08-11 05:30:38 -0400
commit4772ff03df8094fd99d28de5fcf5df3a3e9c68bb (patch)
tree2a4d3df228d96c5aac622bdcf1a7289a08bcc5bb
parent5677d67ae3949f09f57357241b88222d49b8c782 (diff)
drm/dp/mst: Remove port after removing connector.
The port is removed synchronously, but the connector delayed. This causes a use after free which can cause a kernel BUG with slug_debug=FPZU. This is fixed by freeing the port after the connector. This fixes a regression introduced with 6b8eeca65b18ae77e175cc2b6571731f0ee413bf "drm/dp/mst: close deadlock in connector destruction." Cc: stable@vger.kernel.org Cc: Dave Airlie <airlied@redhat.com> Signed-off-by: Maarten Lankhorst <maarten.lankhorst@linux.intel.com> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch> Signed-off-by: Jani Nikula <jani.nikula@intel.com>
-rw-r--r--drivers/gpu/drm/drm_dp_mst_topology.c19
-rw-r--r--include/drm/drm_crtc.h2
2 files changed, 13 insertions, 8 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c
index 778bbb6425b8..1325eecb0510 100644
--- a/drivers/gpu/drm/drm_dp_mst_topology.c
+++ b/drivers/gpu/drm/drm_dp_mst_topology.c
@@ -873,9 +873,10 @@ static void drm_dp_destroy_port(struct kref *kref)
873 from an EDID retrieval */ 873 from an EDID retrieval */
874 if (port->connector) { 874 if (port->connector) {
875 mutex_lock(&mgr->destroy_connector_lock); 875 mutex_lock(&mgr->destroy_connector_lock);
876 list_add(&port->connector->destroy_list, &mgr->destroy_connector_list); 876 list_add(&port->next, &mgr->destroy_connector_list);
877 mutex_unlock(&mgr->destroy_connector_lock); 877 mutex_unlock(&mgr->destroy_connector_lock);
878 schedule_work(&mgr->destroy_connector_work); 878 schedule_work(&mgr->destroy_connector_work);
879 return;
879 } 880 }
880 drm_dp_port_teardown_pdt(port, port->pdt); 881 drm_dp_port_teardown_pdt(port, port->pdt);
881 882
@@ -2660,7 +2661,7 @@ static void drm_dp_tx_work(struct work_struct *work)
2660static void drm_dp_destroy_connector_work(struct work_struct *work) 2661static void drm_dp_destroy_connector_work(struct work_struct *work)
2661{ 2662{
2662 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); 2663 struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
2663 struct drm_connector *connector; 2664 struct drm_dp_mst_port *port;
2664 2665
2665 /* 2666 /*
2666 * Not a regular list traverse as we have to drop the destroy 2667 * Not a regular list traverse as we have to drop the destroy
@@ -2669,15 +2670,21 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
2669 */ 2670 */
2670 for (;;) { 2671 for (;;) {
2671 mutex_lock(&mgr->destroy_connector_lock); 2672 mutex_lock(&mgr->destroy_connector_lock);
2672 connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list); 2673 port = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_dp_mst_port, next);
2673 if (!connector) { 2674 if (!port) {
2674 mutex_unlock(&mgr->destroy_connector_lock); 2675 mutex_unlock(&mgr->destroy_connector_lock);
2675 break; 2676 break;
2676 } 2677 }
2677 list_del(&connector->destroy_list); 2678 list_del(&port->next);
2678 mutex_unlock(&mgr->destroy_connector_lock); 2679 mutex_unlock(&mgr->destroy_connector_lock);
2679 2680
2680 mgr->cbs->destroy_connector(mgr, connector); 2681 mgr->cbs->destroy_connector(mgr, port->connector);
2682
2683 drm_dp_port_teardown_pdt(port, port->pdt);
2684
2685 if (!port->input && port->vcpi.vcpi > 0)
2686 drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
2687 kfree(port);
2681 } 2688 }
2682} 2689}
2683 2690
diff --git a/include/drm/drm_crtc.h b/include/drm/drm_crtc.h
index 57ca8cc383a6..3b4d8a4a23fb 100644
--- a/include/drm/drm_crtc.h
+++ b/include/drm/drm_crtc.h
@@ -743,8 +743,6 @@ struct drm_connector {
743 uint8_t num_h_tile, num_v_tile; 743 uint8_t num_h_tile, num_v_tile;
744 uint8_t tile_h_loc, tile_v_loc; 744 uint8_t tile_h_loc, tile_v_loc;
745 uint16_t tile_h_size, tile_v_size; 745 uint16_t tile_h_size, tile_v_size;
746
747 struct list_head destroy_list;
748}; 746};
749 747
750/** 748/**