Merge "disp: msm: dp: fix refcount issues on mst port disconnect"

This commit is contained in:
qctecmdr 2020-07-11 12:37:42 -07:00 • committed by Gerrit - the friendly Code Review server
commit dab2d306d2

View file

@ -259,7 +259,20 @@ static void dp_mst_sim_topology_put_port(struct drm_dp_mst_port *port)
kref_put(&port->topology_kref, dp_mst_sim_destroy_port);
}
/* DRM DP MST Framework simulator OPs */
/*
* DRM DP MST Framework simulator OPs
*
* If simulation mode is enabled, on HPD connect, mst mode is enabled on the
* topology manager and 2 simulated ports are created using
* dp_mst_sim_add_port. These 2 ports are added to the MST branch device.
* Each node in the DP MST topology has 2 reference objects one for memory
* allocation and the other for its use on the topology tree. When the last
* topology reference is released on a port, the port gets destroyed and when
* the last malloc reference is released, then the port memory is freed.
* Each port also gets a reference on its parent branch object to make sure
* that the branch is not destroyed prematurely.
*/
static void dp_mst_sim_add_port(struct dp_mst_private *mst,
struct dp_mst_sim_port_data *port_msg)
{
@ -324,6 +337,31 @@ put_port:
dp_mst_sim_topology_put_port(port);
}
static void dp_mst_sim_remove_port(struct dp_mst_private *mst,
struct drm_dp_mst_port *port)
{
struct drm_dp_mst_branch *mstb;
int i;
mstb = mst->mst_mgr.mst_primary;
if (!mstb) {
DP_ERR("Unable to remove port. mst branch device is null\n");
return;
}
mutex_lock(&mstb->mgr->lock);
list_del(&port->next);
mutex_unlock(&mstb->mgr->lock);
dp_mst_sim_topology_put_port(port);
for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) {
if (mst->simulator.port_edids[i].port_number ==
port->port_num) {
mst->simulator.port_edids[i].valid = false;
}
}
}
static void dp_mst_sim_link_probe_work(struct work_struct *work)
{
struct dp_mst_sim_mode *sim;
@ -500,13 +538,8 @@ static int dp_mst_sim_topology_mgr_set_mst(
struct dp_mst_private *mst = container_of(mgr,
struct dp_mst_private, mst_mgr);
/*
* Setting mst off on the mgr initiates shutdown of the branch device.
* Moving the disable to bridge disable in order to make sure the
* connector is valid till the hpd notification is completed.
*/
if (!mst_state)
return 0;
DP_MST_DEBUG("enter: mst_state %d\n", mst_state);
SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY, mst_state);
rc = drm_dp_mst_topology_mgr_set_mst(mgr, mst_state);
if (rc < 0) {
@ -514,7 +547,8 @@ static int dp_mst_sim_topology_mgr_set_mst(
return rc;
}
queue_work(system_long_wq, &mst->simulator.probe_work);
if (mst_state)
queue_work(system_long_wq, &mst->simulator.probe_work);
mst->simulator.mst_state = mst_state;
return 0;
@ -574,7 +608,6 @@ static void dp_mst_sim_handle_hpd_irq(void *dp_display,
if (port->connector && port->connector->base.id ==
info->mst_sim_remove_con_id) {
in_list = true;
list_del(&port->next);
break;
}
}
@ -584,13 +617,8 @@ static void dp_mst_sim_handle_hpd_irq(void *dp_display,
DRM_ERROR("invalid connector id %d\n",
info->mst_sim_remove_con_id);
return;
}
for (i = 0; i < DP_MST_SIM_MAX_PORTS; i++) {
if (mst->simulator.port_edids[i].port_number ==
port->port_num) {
mst->simulator.port_edids[i].valid = false;
}
} else {
dp_mst_sim_remove_port(mst, port);
}
dp_mst_sim_topology_put_port(port);
@ -855,14 +883,6 @@ static void _dp_mst_bridge_pre_enable_part1(struct dp_mst_bridge *dp_bridge)
return;
}
/*
* Take a reference to the port topology to make sure the port object
* is available while waiting for the connector to be cleaned up after
* hpd low. This reference will be released in the disable path.
*/
if (mst->simulator.mst_state)
dp_mst_sim_topology_get_port(port);
pbn = mst->mst_fw_cbs->calc_pbn_mode(&dp_bridge->dp_mode);
slots = mst->mst_fw_cbs->find_vcpi_slots(&mst->mst_mgr, pbn);
@ -940,7 +960,6 @@ static void _dp_mst_bridge_pre_disable_part2(struct dp_mst_bridge *dp_bridge)
struct sde_connector *c_conn =
to_sde_connector(dp_bridge->connector);
struct drm_dp_mst_port *port = c_conn->mst_port;
int rc = 0;
DP_MST_DEBUG("enter\n");
SDE_EVT32_EXTERNAL(SDE_EVTLOG_FUNC_ENTRY);
@ -960,17 +979,8 @@ static void _dp_mst_bridge_pre_disable_part2(struct dp_mst_bridge *dp_bridge)
port->vcpi.vcpi = dp_bridge->vcpi;
mst->mst_fw_cbs->deallocate_vcpi(&mst->mst_mgr, port);
if (mst->simulator.mst_state) {
rc = drm_dp_mst_topology_mgr_set_mst(&mst->mst_mgr, false);
if (rc < 0)
DRM_WARN("unable to set mst topology mgr, rc: %d\n",
rc);
/* release the reference taken during pre_enable */
dp_mst_sim_topology_put_port(port);
mst->simulator.mst_state = false;
}
if (mst->simulator.mst_state)
dp_mst_sim_remove_port(mst, port);
dp_bridge->vcpi = 0;
dp_bridge->pbn = 0;