lkml.org 
[lkml]   [2016]   [Mar]   [7]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH 4.2.y-ckt 102/273] drm/dp/mst: deallocate payload on port destruction
    Date
    4.2.8-ckt5 -stable review patch.  If anyone has any objections, please let me know.

    ---8<------------------------------------------------------------

    From: Mykola Lysenko <Mykola.Lysenko@amd.com>

    commit 91a25e463130c8e19bdb42f2d827836c7937992e upstream.

    This is needed to properly deallocate port payload
    after downstream branch get unplugged.

    In order to do this unplugged MST topology should
    be preserved, to find first alive port on path to
    unplugged MST topology, and send payload deallocation
    request to branch device of found port.

    For this mstb and port kref's are used in reversed
    order to track when port and branch memory could be
    freed.

    Added additional functions to find appropriate mstb
    as described above.

    Signed-off-by: Mykola Lysenko <Mykola.Lysenko@amd.com>
    Reviewed-by: Harry Wentland <Harry.Wentland@amd.com>
    Signed-off-by: Dave Airlie <airlied@redhat.com>
    Signed-off-by: Kamal Mostafa <kamal@canonical.com>
    ---
    drivers/gpu/drm/drm_dp_mst_topology.c | 91 ++++++++++++++++++++++++++++++++---
    1 file 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 2c691b3..7abb966 100644
    --- a/drivers/gpu/drm/drm_dp_mst_topology.c
    +++ b/drivers/gpu/drm/drm_dp_mst_topology.c
    @@ -798,6 +798,18 @@ static struct drm_dp_mst_branch *drm_dp_add_mst_branch_device(u8 lct, u8 *rad)
    return mstb;
    }

    +static void drm_dp_free_mst_port(struct kref *kref);
    +
    +static void drm_dp_free_mst_branch_device(struct kref *kref)
    +{
    + struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref);
    + if (mstb->port_parent) {
    + if (list_empty(&mstb->port_parent->next))
    + kref_put(&mstb->port_parent->kref, drm_dp_free_mst_port);
    + }
    + kfree(mstb);
    +}
    +
    static void drm_dp_destroy_mst_branch_device(struct kref *kref)
    {
    struct drm_dp_mst_branch *mstb = container_of(kref, struct drm_dp_mst_branch, kref);
    @@ -805,6 +817,15 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref)
    bool wake_tx = false;

    /*
    + * init kref again to be used by ports to remove mst branch when it is
    + * not needed anymore
    + */
    + kref_init(kref);
    +
    + if (mstb->port_parent && list_empty(&mstb->port_parent->next))
    + kref_get(&mstb->port_parent->kref);
    +
    + /*
    * destroy all ports - don't need lock
    * as there are no more references to the mst branch
    * device at this point.
    @@ -830,7 +851,8 @@ static void drm_dp_destroy_mst_branch_device(struct kref *kref)

    if (wake_tx)
    wake_up(&mstb->mgr->tx_waitq);
    - kfree(mstb);
    +
    + kref_put(kref, drm_dp_free_mst_branch_device);
    }

    static void drm_dp_put_mst_branch_device(struct drm_dp_mst_branch *mstb)
    @@ -878,6 +900,7 @@ static void drm_dp_destroy_port(struct kref *kref)
    * from an EDID retrieval */

    mutex_lock(&mgr->destroy_connector_lock);
    + kref_get(&port->parent->kref);
    list_add(&port->next, &mgr->destroy_connector_list);
    mutex_unlock(&mgr->destroy_connector_lock);
    schedule_work(&mgr->destroy_connector_work);
    @@ -1595,6 +1618,37 @@ static int drm_dp_send_enum_path_resources(struct drm_dp_mst_topology_mgr *mgr,
    return 0;
    }

    +static struct drm_dp_mst_port *drm_dp_get_last_connected_port_to_mstb(struct drm_dp_mst_branch *mstb)
    +{
    + if (!mstb->port_parent)
    + return NULL;
    +
    + if (mstb->port_parent->mstb != mstb)
    + return mstb->port_parent;
    +
    + return drm_dp_get_last_connected_port_to_mstb(mstb->port_parent->parent);
    +}
    +
    +static struct drm_dp_mst_branch *drm_dp_get_last_connected_port_and_mstb(struct drm_dp_mst_topology_mgr *mgr,
    + struct drm_dp_mst_branch *mstb,
    + int *port_num)
    +{
    + struct drm_dp_mst_branch *rmstb = NULL;
    + struct drm_dp_mst_port *found_port;
    + mutex_lock(&mgr->lock);
    + if (mgr->mst_primary) {
    + found_port = drm_dp_get_last_connected_port_to_mstb(mstb);
    +
    + if (found_port) {
    + rmstb = found_port->parent;
    + kref_get(&rmstb->kref);
    + *port_num = found_port->port_num;
    + }
    + }
    + mutex_unlock(&mgr->lock);
    + return rmstb;
    +}
    +
    static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
    struct drm_dp_mst_port *port,
    int id,
    @@ -1602,11 +1656,16 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
    {
    struct drm_dp_sideband_msg_tx *txmsg;
    struct drm_dp_mst_branch *mstb;
    - int len, ret;
    + int len, ret, port_num;

    + port_num = port->port_num;
    mstb = drm_dp_get_validated_mstb_ref(mgr, port->parent);
    - if (!mstb)
    - return -EINVAL;
    + if (!mstb) {
    + mstb = drm_dp_get_last_connected_port_and_mstb(mgr, port->parent, &port_num);
    +
    + if (!mstb)
    + return -EINVAL;
    + }

    txmsg = kzalloc(sizeof(*txmsg), GFP_KERNEL);
    if (!txmsg) {
    @@ -1615,7 +1674,7 @@ static int drm_dp_payload_send_msg(struct drm_dp_mst_topology_mgr *mgr,
    }

    txmsg->dst = mstb;
    - len = build_allocate_payload(txmsg, port->port_num,
    + len = build_allocate_payload(txmsg, port_num,
    id,
    pbn);

    @@ -2749,6 +2808,13 @@ static void drm_dp_tx_work(struct work_struct *work)
    mutex_unlock(&mgr->qlock);
    }

    +static void drm_dp_free_mst_port(struct kref *kref)
    +{
    + struct drm_dp_mst_port *port = container_of(kref, struct drm_dp_mst_port, kref);
    + kref_put(&port->parent->kref, drm_dp_free_mst_branch_device);
    + kfree(port);
    +}
    +
    static void drm_dp_destroy_connector_work(struct work_struct *work)
    {
    struct drm_dp_mst_topology_mgr *mgr = container_of(work, struct drm_dp_mst_topology_mgr, destroy_connector_work);
    @@ -2769,13 +2835,22 @@ static void drm_dp_destroy_connector_work(struct work_struct *work)
    list_del(&port->next);
    mutex_unlock(&mgr->destroy_connector_lock);

    + kref_init(&port->kref);
    + INIT_LIST_HEAD(&port->next);
    +
    mgr->cbs->destroy_connector(mgr, port->connector);

    drm_dp_port_teardown_pdt(port, port->pdt);

    - if (!port->input && port->vcpi.vcpi > 0)
    - drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
    - kfree(port);
    + if (!port->input && port->vcpi.vcpi > 0) {
    + if (mgr->mst_state) {
    + drm_dp_mst_reset_vcpi_slots(mgr, port);
    + drm_dp_update_payload_part1(mgr);
    + drm_dp_mst_put_payload_id(mgr, port->vcpi.vcpi);
    + }
    + }
    +
    + kref_put(&port->kref, drm_dp_free_mst_port);
    send_hotplug = true;
    }
    if (send_hotplug)
    --
    2.7.0
    \
     
     \ /
      Last update: 2016-03-08 02:21    [W:2.226 / U:0.100 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site