diff options
-rw-r--r-- | drivers/gpu/drm/drm_dp_mst_topology.c | 91 |
1 files changed, 83 insertions, 8 deletions
diff --git a/drivers/gpu/drm/drm_dp_mst_topology.c b/drivers/gpu/drm/drm_dp_mst_topology.c index 7e5d98c7b908..8ae13de272c4 100644 --- a/drivers/gpu/drm/drm_dp_mst_topology.c +++ b/drivers/gpu/drm/drm_dp_mst_topology.c | |||
@@ -803,6 +803,18 @@ static struct drm_dp_mst_branch *drm_dp_add_mst_branch_device(u8 lct, u8 *rad) | |||
803 | return mstb; | 803 | return mstb; |
804 | } | 804 | } |
805 | 805 | ||
806 | static void drm_dp_free_mst_port(struct kref *kref); | ||
807 | |||
808 | static void drm_dp_free_mst_branch_device(struct kref *kref) | ||
809 | { | ||
810 | struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); | ||
811 | if (mstb->port_parent) { | ||
812 | if (list_empty(&mstb->port_parent->next)) | ||
813 | kref_put(&mstb->port_parent->kref, drm_dp_free_mst_port); | ||
814 | } | ||
815 | kfree(mstb); | ||
816 | } | ||
817 | |||
806 | static void drm_dp_destroy_mst_branch_device(struct kref *kref) | 818 | static void drm_dp_destroy_mst_branch_device(struct kref *kref) |
807 | { | 819 | { |
808 | struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); | 820 | struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref); |
@@ -810,6 +822,15 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) | |||
810 | bool wake_tx = false; | 822 | bool wake_tx = false; |
811 | 823 | ||
812 | /* | 824 | /* |
825 | * init kref again to be used by ports to remove mst branch when it is | ||
826 | * not needed anymore | ||
827 | */ | ||
828 | kref_init(kref); | ||
829 | |||
830 | if (mstb->port_parent && list_empty(&mstb->port_parent->next)) | ||
831 | kref_get(&mstb->port_parent->kref); | ||
832 | |||
833 | /* | ||
813 | * destroy all ports - don't need lock | 834 | * destroy all ports - don't need lock |
814 | * as there are no more references to the mst branch | 835 | * as there are no more references to the mst branch |
815 | * device at this point. | 836 | * device at this point. |
@@ -835,7 +856,8 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref) | |||
835 | 856 | ||
836 | if (wake_tx) | 857 | if (wake_tx) |
837 | wake_up(&mstb->mgr->tx_waitq); | 858 | wake_up(&mstb->mgr->tx_waitq); |
838 | kfree(mstb); | 859 | |
860 | kref_put(kref, drm_dp_free_mst_branch_device); | ||
839 | } | 861 | } |
840 | 862 | ||
841 | static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb) | 863 | static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb) |
@@ -883,6 +905,7 @@ static void drm_dp_destroy_port(struct kref *kref) | |||
883 | * from an EDID retrieval */ | 905 | * from an EDID retrieval */ |
884 | 906 | ||
885 | mutex_lock(&mgr->destroy_connector_lock); | 907 | mutex_lock(&mgr->destroy_connector_lock); |
908 | kref_get(&port->parent->kref); | ||
886 | list_add(&port->next, &mgr->destroy_connector_list); | 909 | list_add(&port->next, &mgr->destroy_connector_list); |
887 | mutex_unlock(&mgr->destroy_connector_lock); | 910 | mutex_unlock(&mgr->destroy_connector_lock); |
888 | schedule_work(&mgr->destroy_connector_work); | 911 | schedule_work(&mgr->destroy_connector_work); |
@@ -1617,6 +1640,37 @@ static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr, | |||
1617 | return 0; | 1640 | return 0; |
1618 | } | 1641 | } |
1619 | 1642 | ||
1643 | static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm_dp_mst_branch *mstb) | ||
1644 | { | ||
1645 | if (!mstb->port_parent) | ||
1646 | return NULL; | ||
1647 | |||
1648 | if (mstb->port_parent->mstb != mstb) | ||
1649 | return mstb->port_parent; | ||
1650 | |||
1651 | return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent); | ||
1652 | } | ||
1653 | |||
1654 | static struct drm_dp_mst_branch *drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr, | ||
1655 | struct drm_dp_mst_branch *mstb, | ||
1656 | int *port_num) | ||
1657 | { | ||
1658 | struct drm_dp_mst_branch *rmstb = NULL; | ||
1659 | struct drm_dp_mst_port *found_port; | ||
1660 | mutex_lock(&mgr->lock); | ||
1661 | if (mgr->mst_primary) { | ||
1662 | found_port = drm_dp_get_last_connected_port_to_mstb(mstb); | ||
1663 | |||
1664 | if (found_port) { | ||
1665 | rmstb = found_port->parent; | ||
1666 | kref_get(&rmstb->kref); | ||
1667 | *port_num = found_port->port_num; | ||
1668 | } | ||
1669 | } | ||
1670 | mutex_unlock(&mgr->lock); | ||
1671 | return rmstb; | ||
1672 | } | ||
1673 | |||
1620 | static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, | 1674 | static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, |
1621 | struct drm_dp_mst_port *port, | 1675 | struct drm_dp_mst_port *port, |
1622 | int id, | 1676 | int id, |
@@ -1624,13 +1678,18 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, | |||
1624 | { | 1678 | { |
1625 | struct drm_dp_sideband_msg_tx *txmsg; | 1679 | struct drm_dp_sideband_msg_tx *txmsg; |
1626 | struct drm_dp_mst_branch *mstb; | 1680 | struct drm_dp_mst_branch *mstb; |
1627 | int len, ret; | 1681 | int len, ret, port_num; |
1628 | u8 sinks[DRM_DP_MAX_SDP_STREAMS]; | 1682 | u8 sinks[DRM_DP_MAX_SDP_STREAMS]; |
1629 | int i; | 1683 | int i; |
1630 | 1684 | ||
1685 | port_num = port->port_num; | ||
1631 | mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); | 1686 | mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent); |
1632 | if (!mstb) | 1687 | if (!mstb) { |
1633 | return -EINVAL; | 1688 | mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num); |
1689 | |||
1690 | if (!mstb) | ||
1691 | return -EINVAL; | ||
1692 | } | ||
1634 | 1693 | ||
1635 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); | 1694 | txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL); |
1636 | if (!txmsg) { | 1695 | if (!txmsg) { |
@@ -1642,7 +1701,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr, | |||
1642 | sinks[i] = i; | 1701 | sinks[i] = i; |
1643 | 1702 | ||
1644 | txmsg->dst = mstb; | 1703 | txmsg->dst = mstb; |
1645 | len = build_allocate_payload(txmsg, port->port_num, | 1704 | len = build_allocate_payload(txmsg, port_num, |
1646 | id, | 1705 | id, |
1647 | pbn, port->num_sdp_streams, sinks); | 1706 | pbn, port->num_sdp_streams, sinks); |
1648 | 1707 | ||
@@ -2788,6 +2847,13 @@ static void drm_dp_tx_work(struct work_struct *work) | |||
2788 | mutex_unlock(&mgr->qlock); | 2847 | mutex_unlock(&mgr->qlock); |
2789 | } | 2848 | } |
2790 | 2849 | ||
2850 | static void drm_dp_free_mst_port(struct kref *kref) | ||
2851 | { | ||
2852 | struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref); | ||
2853 | kref_put(&port->parent->kref, drm_dp_free_mst_branch_device); | ||
2854 | kfree(port); | ||
2855 | } | ||
2856 | |||
2791 | static void drm_dp_destroy_connector_work(struct work_struct *work) | 2857 | static void drm_dp_destroy_connector_work(struct work_struct *work) |
2792 | { | 2858 | { |
2793 | struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); | 2859 | struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work); |
@@ -2808,13 +2874,22 @@ static void drm_dp_destroy_connector_work(struct work_struct *work) | |||
2808 | list_del(&port->next); | 2874 | list_del(&port->next); |
2809 | mutex_unlock(&mgr->destroy_connector_lock); | 2875 | mutex_unlock(&mgr->destroy_connector_lock); |
2810 | 2876 | ||
2877 | kref_init(&port->kref); | ||
2878 | INIT_LIST_HEAD(&port->next); | ||
2879 | |||
2811 | mgr->cbs->destroy_connector(mgr, port->connector); | 2880 | mgr->cbs->destroy_connector(mgr, port->connector); |
2812 | 2881 | ||
2813 | drm_dp_port_teardown_pdt(port, port->pdt); | 2882 | drm_dp_port_teardown_pdt(port, port->pdt); |
2814 | 2883 | ||
2815 | if (!port->input && port->vcpi.vcpi > 0) | 2884 | if (!port->input && port->vcpi.vcpi > 0) { |
2816 | drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); | 2885 | if (mgr->mst_state) { |
2817 | kfree(port); | 2886 | drm_dp_mst_reset_vcpi_slots(mgr, port); |
2887 | drm_dp_update_payload_part1(mgr); | ||
2888 | drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi); | ||
2889 | } | ||
2890 | } | ||
2891 | |||
2892 | kref_put(&port->kref, drm_dp_free_mst_port); | ||
2818 | send_hotplug = true; | 2893 | send_hotplug = true; |
2819 | } | 2894 | } |
2820 | if (send_hotplug) | 2895 | if (send_hotplug) |