| @@ -867,8 +867,16 @@ static void drm_dp_destroy_port(struct kref *kref) · 866 unmodified lines |
| 867 | 867 | port->vcpi.num_slots = 0; |
| 868 | 868 | |
| 869 | 869 | kfree(port->cached_edid); |
| 870 | | − if (port->connector) |
| 871 | | − (*port->mgr->cbs->destroy_connector)(mgr, port->connector); |
| 870 | + |
| 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 | 880 | drm_dp_port_teardown_pdt(port, port->pdt); |
| 873 | 881 | |
| 874 | 882 | if (!port->input && port->vcpi.vcpi > 0) |
| @@ -2649,6 +2657,30 @@ static void drm_dp_tx_work(struct work_struct *work) · 1774 unmodified lines |
| 2649 | 2657 | mutex_unlock(&mgr->qlock); |
| 2650 | 2658 | } |
| 2651 | 2659 | |
| 2660 | +static void drm_dp_destroy_connector_work(struct work_struct *work) |
| 2661 | +{ |
| 2662 | + 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 | + |
| 2665 | + /* |
| 2666 | + * Not a regular list traverse as we have to drop the destroy |
| 2667 | + * connector lock before destroying the connector, to avoid AB->BA |
| 2668 | + * ordering between this lock and the config mutex. |
| 2669 | + */ |
| 2670 | + for (;;) { |
| 2671 | + mutex_lock(&mgr->destroy_connector_lock); |
| 2672 | + connector = list_first_entry_or_null(&mgr->destroy_connector_list, struct drm_connector, destroy_list); |
| 2673 | + if (!connector) { |
| 2674 | + mutex_unlock(&mgr->destroy_connector_lock); |
| 2675 | + break; |
| 2676 | + } |
| 2677 | + list_del(&connector->destroy_list); |
| 2678 | + mutex_unlock(&mgr->destroy_connector_lock); |
| 2679 | + |
| 2680 | + mgr->cbs->destroy_connector(mgr, connector); |
| 2681 | + } |
| 2682 | +} |
| 2683 | + |
| 2652 | 2684 | /** |
| 2653 | 2685 | * drm_dp_mst_topology_mgr_init - initialise a topology manager |
| 2654 | 2686 | * @mgr: manager struct to initialise |
| @@ -2668,10 +2700,13 @@ int drm_dp_mst_topology_mgr_init(struct drm_dp_mst_topology_mgr *mgr, · 13 unmodified lines |
| 2668 | 2700 | mutex_init(&mgr->lock); |
| 2669 | 2701 | mutex_init(&mgr->qlock); |
| 2670 | 2702 | mutex_init(&mgr->payload_lock); |
| 2703 | + mutex_init(&mgr->destroy_connector_lock); |
| 2671 | 2704 | INIT_LIST_HEAD(&mgr->tx_msg_upq); |
| 2672 | 2705 | INIT_LIST_HEAD(&mgr->tx_msg_downq); |
| 2706 | + INIT_LIST_HEAD(&mgr->destroy_connector_list); |
| 2673 | 2707 | INIT_WORK(&mgr->work, drm_dp_mst_link_probe_work); |
| 2674 | 2708 | INIT_WORK(&mgr->tx_work, drm_dp_tx_work); |
| 2709 | + INIT_WORK(&mgr->destroy_connector_work, drm_dp_destroy_connector_work); |
| 2675 | 2710 | init_waitqueue_head(&mgr->tx_waitq); |
| 2676 | 2711 | mgr->dev = dev; |
| 2677 | 2712 | mgr->aux = aux; |
| @@ -2696,6 +2731,7 @@ EXPORT_SYMBOL(drm_dp_mst_topology_mgr_init); · 18 unmodified lines |
| 2696 | 2731 | */ |
| 2697 | 2732 | void drm_dp_mst_topology_mgr_destroy(struct drm_dp_mst_topology_mgr *mgr) |
| 2698 | 2733 | { |
| 2734 | + flush_work(&mgr->destroy_connector_work); |
| 2699 | 2735 | mutex_lock(&mgr->payload_lock); |
| 2700 | 2736 | kfree(mgr->payloads); |
| 2701 | 2737 | mgr->payloads = NULL; |