Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 80b2c937 authored by Sankeerth Billakanti's avatar Sankeerth Billakanti
Browse files

disp: msm: dp: add private state to dp_mst_bridge



Current dp_mst_bridge has variables that are accessed by both
check phase and commit phase, which causes racing issues. This
change will add private state to dp_mst_bridge to separate check
phase and commit phase.

Change-Id: I8ac05cf5f1755375e4e9f34e42dbaea1d23bac64
Signed-off-by: default avatarXiaowen Wu <wxiaowen@codeaurora.org>
Signed-off-by: default avatarSankeerth Billakanti <sbillaka@codeaurora.org>
parent 8a54f29a
Loading
Loading
Loading
Loading
+189 −123
Original line number Diff line number Diff line
// SPDX-License-Identifier: GPL-2.0-only
/*
 * Copyright (c) 2018-2019, The Linux Foundation. All rights reserved.
 * Copyright (c) 2018-2020, The Linux Foundation. All rights reserved.
 */

/*
@@ -78,6 +78,7 @@ struct dp_drm_mst_fw_helper_ops {
			struct drm_dp_mst_port *port);
	void (*deallocate_vcpi)(struct drm_dp_mst_topology_mgr *mgr,
			struct drm_dp_mst_port *port);
	int (*get_avail_slots)(struct drm_dp_mst_topology_mgr *mgr);
};

struct dp_mst_sim_port_data {
@@ -110,20 +111,18 @@ struct dp_mst_sim_mode {

struct dp_mst_bridge {
	struct drm_bridge base;
	struct drm_private_obj obj;
	u32 id;

	bool in_use;

	struct dp_display *display;
	struct drm_encoder *encoder;
	bool encoder_active_sts;

	struct drm_display_mode drm_mode;
	struct dp_display_mode dp_mode;
	struct drm_connector *connector;
	struct drm_connector *old_connector;
	void *dp_panel;
	void *old_dp_panel;

	int vcpi;
	int pbn;
@@ -135,6 +134,13 @@ struct dp_mst_bridge {
	struct drm_connector *fixed_connector;
};

struct dp_mst_bridge_state {
	struct drm_private_state base;
	struct drm_connector *connector;
	void *dp_panel;
	int num_slots;
};

struct dp_mst_private {
	bool mst_initialized;
	struct dp_mst_caps caps;
@@ -154,10 +160,55 @@ struct dp_mst_encoder_info_cache {
};

#define to_dp_mst_bridge(x)     container_of((x), struct dp_mst_bridge, base)
#define to_dp_mst_bridge_priv(x) \
		container_of((x), struct dp_mst_bridge, obj)
#define to_dp_mst_bridge_priv_state(x) \
		container_of((x), struct dp_mst_bridge_state, base)
#define to_dp_mst_bridge_state(x) \
		to_dp_mst_bridge_priv_state((x)->obj.state)

struct dp_mst_private dp_mst;
struct dp_mst_encoder_info_cache dp_mst_enc_cache;

static struct drm_private_state *dp_mst_duplicate_bridge_state(
		struct drm_private_obj *obj)
{
	struct dp_mst_bridge_state *state;

	state = kmemdup(obj->state, sizeof(*state), GFP_KERNEL);
	if (!state)
		return NULL;

	__drm_atomic_helper_private_obj_duplicate_state(obj, &state->base);

	return &state->base;
}

static void dp_mst_destroy_bridge_state(struct drm_private_obj *obj,
		struct drm_private_state *state)
{
	struct dp_mst_bridge_state *priv_state =
		to_dp_mst_bridge_priv_state(state);

	kfree(priv_state);
}

static const struct drm_private_state_funcs dp_mst_bridge_state_funcs = {
	.atomic_duplicate_state = dp_mst_duplicate_bridge_state,
	.atomic_destroy_state = dp_mst_destroy_bridge_state,
};

static struct dp_mst_bridge_state *dp_mst_get_bridge_atomic_state(
		struct drm_atomic_state *state, struct dp_mst_bridge *bridge)
{
	struct drm_device *dev = bridge->base.dev;

	WARN_ON(!drm_modeset_is_locked(&dev->mode_config.connection_mutex));

	return to_dp_mst_bridge_priv_state(
			drm_atomic_get_private_obj_state(state, &bridge->obj));
}

static void dp_mst_sim_destroy_port(struct kref *ref)
{
	struct drm_dp_mst_port *port = container_of(ref,
@@ -497,6 +548,11 @@ static void dp_mst_sim_handle_hpd_irq(void *dp_display,
	}
}

static int _dp_mst_get_avail_slots(struct drm_dp_mst_topology_mgr *mgr)
{
	return to_dp_mst_topology_state(mgr->base.state)->avail_slots;
}

static void _dp_mst_get_vcpi_info(
		struct drm_dp_mst_topology_mgr *mgr,
		int vcpi, int *start_slot, int *num_slots)
@@ -562,6 +618,7 @@ static const struct dp_drm_mst_fw_helper_ops drm_dp_mst_fw_helper_ops = {
	.atomic_release_vcpi_slots = drm_dp_atomic_release_vcpi_slots,
	.reset_vcpi_slots          = drm_dp_mst_reset_vcpi_slots,
	.deallocate_vcpi           = drm_dp_mst_deallocate_vcpi,
	.get_avail_slots           = _dp_mst_get_avail_slots,
};

static const struct dp_drm_mst_fw_helper_ops drm_dp_sim_mst_fw_helper_ops = {
@@ -579,6 +636,7 @@ static const struct dp_drm_mst_fw_helper_ops drm_dp_sim_mst_fw_helper_ops = {
	.atomic_release_vcpi_slots = drm_dp_atomic_release_vcpi_slots,
	.reset_vcpi_slots          = drm_dp_mst_reset_vcpi_slots,
	.deallocate_vcpi           = drm_dp_mst_deallocate_vcpi,
	.get_avail_slots           = _dp_mst_get_avail_slots,
};

/* DP MST Bridge OPs */
@@ -609,6 +667,8 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge,
	struct dp_display_mode dp_mode;
	struct dp_mst_bridge *bridge;
	struct dp_display *dp;
	struct drm_crtc_state *crtc_state;
	struct dp_mst_bridge_state *bridge_state;

	DP_MST_DEBUG("enter\n");

@@ -619,13 +679,17 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge,
	}

	bridge = to_dp_mst_bridge(drm_bridge);
	if (!bridge->connector) {
		DP_ERR("Invalid connector\n");

	crtc_state = container_of(mode, struct drm_crtc_state, mode);
	bridge_state = dp_mst_get_bridge_atomic_state(crtc_state->state,
			bridge);
	if (IS_ERR(bridge_state)) {
		DP_ERR("invalid bridge state\n");
		ret = false;
		goto end;
	}

	if (!bridge->dp_panel) {
	if (!bridge_state->dp_panel) {
		DP_ERR("Invalid dp_panel\n");
		ret = false;
		goto end;
@@ -633,7 +697,7 @@ static bool dp_mst_bridge_mode_fixup(struct drm_bridge *drm_bridge,

	dp = bridge->display;

	dp->convert_to_dp_mode(dp, bridge->dp_panel, mode, &dp_mode);
	dp->convert_to_dp_mode(dp, bridge_state->dp_panel, mode, &dp_mode);
	convert_to_drm_mode(&dp_mode, adjusted_mode);

	DP_MST_DEBUG("mst bridge [%d] mode:%s fixup\n", bridge->id, mode->name);
@@ -647,7 +711,6 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state,
{
	int slots = 0, pbn;
	struct sde_connector *c_conn = to_sde_connector(connector);
	int rc = 0;

	DP_MST_DEBUG("enter\n");

@@ -663,7 +726,7 @@ static int _dp_mst_compute_config(struct drm_atomic_state *state,

	DP_MST_DEBUG("exit\n");

	return rc;
	return slots;
}

static void _dp_mst_update_timeslots(struct dp_mst_private *mst,
@@ -856,9 +919,6 @@ static void dp_mst_bridge_pre_enable(struct drm_bridge *drm_bridge)
	bridge = to_dp_mst_bridge(drm_bridge);
	dp = bridge->display;

	bridge->old_connector = NULL;
	bridge->old_dp_panel = NULL;

	if (!bridge->connector) {
		DP_ERR("Invalid connector\n");
		return;
@@ -1008,17 +1068,8 @@ static void dp_mst_bridge_post_disable(struct drm_bridge *drm_bridge)
		DP_INFO("[%d] DP display unprepare failed, rc=%d\n",
		       bridge->id, rc);

	/* maintain the connector to encoder link during suspend/resume */
	if (mst->state != PM_SUSPEND) {
		/* Disconnect the connector and panel info from bridge */
		mst->mst_bridge[bridge->id].old_connector =
				mst->mst_bridge[bridge->id].connector;
		mst->mst_bridge[bridge->id].old_dp_panel =
				mst->mst_bridge[bridge->id].dp_panel;
		mst->mst_bridge[bridge->id].connector = NULL;
		mst->mst_bridge[bridge->id].dp_panel = NULL;
		mst->mst_bridge[bridge->id].encoder_active_sts = false;
	}
	bridge->connector = NULL;
	bridge->dp_panel =  NULL;

	DP_MST_INFO_LOG("mst bridge [%d] post disable complete\n",
			bridge->id);
@@ -1029,6 +1080,7 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge,
				struct drm_display_mode *adjusted_mode)
{
	struct dp_mst_bridge *bridge;
	struct dp_mst_bridge_state *dp_bridge_state;
	struct dp_display *dp;

	DP_MST_DEBUG("enter\n");
@@ -1039,23 +1091,10 @@ static void dp_mst_bridge_mode_set(struct drm_bridge *drm_bridge,
	}

	bridge = to_dp_mst_bridge(drm_bridge);
	if (!bridge->connector) {
		if (!bridge->old_connector) {
			DP_ERR("Invalid connector\n");
			return;
		}
		bridge->connector = bridge->old_connector;
		bridge->old_connector = NULL;
	}

	if (!bridge->dp_panel) {
		if (!bridge->old_dp_panel) {
			DP_ERR("Invalid dp_panel\n");
			return;
		}
		bridge->dp_panel = bridge->old_dp_panel;
		bridge->old_dp_panel = NULL;
	}
	dp_bridge_state = to_dp_mst_bridge_state(bridge);
	bridge->connector = dp_bridge_state->connector;
	bridge->dp_panel = dp_bridge_state->dp_panel;

	dp = bridge->display;

@@ -1087,6 +1126,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder)
{
	int rc = 0;
	struct dp_mst_bridge *bridge = NULL;
	struct dp_mst_bridge_state *state;
	struct drm_device *dev;
	struct dp_display *display = data;
	struct msm_drm_private *priv = NULL;
@@ -1138,6 +1178,16 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder)
	encoder->bridge = &bridge->base;
	priv->bridges[priv->num_bridges++] = &bridge->base;

	state = kzalloc(sizeof(*state), GFP_KERNEL);
	if (state == NULL) {
		rc = -ENOMEM;
		goto end;
	}

	drm_atomic_private_obj_init(&bridge->obj,
				    &state->base,
				    &dp_mst_bridge_state_funcs);

	DP_MST_DEBUG("mst drm bridge init. bridge id:%d\n", i);

	/*
@@ -1152,6 +1202,7 @@ int dp_mst_drm_bridge_init(void *data, struct drm_encoder *encoder)
				bridge->encoder);
		if (bridge->fixed_connector == NULL) {
			DP_ERR("failed to create fixed connector\n");
			kfree(state);
			rc = -ENOMEM;
			goto end;
		}
@@ -1237,9 +1288,7 @@ enum drm_mode_status dp_mst_connector_mode_valid(
	struct drm_dp_mst_port *mst_port;
	struct dp_display_mode dp_mode;
	uint16_t available_pbn, required_pbn;
	int i, slots_in_use = 0, active_enc_cnt = 0;
	int available_slots, required_slots;
	const u32 tot_slots = 63;

	if (!connector || !mode || !display) {
		DP_ERR("invalid input\n");
@@ -1250,23 +1299,8 @@ enum drm_mode_status dp_mst_connector_mode_valid(
	c_conn = to_sde_connector(connector);
	mst_port = c_conn->mst_port;

	mutex_lock(&mst->mst_lock);
	available_pbn = mst_port->available_pbn;
	for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
		if (mst->mst_bridge[i].encoder_active_sts &&
			(mst->mst_bridge[i].connector != connector)) {
			active_enc_cnt++;
			slots_in_use += mst->mst_bridge[i].num_slots;
		}
	}
	mutex_unlock(&mst->mst_lock);

	if (active_enc_cnt < DP_STREAM_MAX)
		available_slots = tot_slots - slots_in_use;
	else {
		DP_DEBUG("all mst streams are active\n");
		return MODE_BAD;
	}
	available_slots = mst->mst_fw_cbs->get_avail_slots(&mst->mst_mgr);

	dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel,
			mode, &dp_mode);
@@ -1340,24 +1374,38 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector,
	struct dp_mst_private *mst = dp_display->dp_mst_prv_info;
	struct sde_connector *conn = to_sde_connector(connector);
	struct drm_encoder *enc = NULL;
	struct dp_mst_bridge_state *bridge_state;
	u32 i;

	if (state->best_encoder)
		return state->best_encoder;

	for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
		if (mst->mst_bridge[i].connector == connector) {
		bridge_state = dp_mst_get_bridge_atomic_state(
				state->state, &mst->mst_bridge[i]);
		if (IS_ERR(bridge_state))
			goto end;

		if (bridge_state->connector == connector) {
			enc = mst->mst_bridge[i].encoder;
			goto end;
		}
	}

	for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
		if (!mst->mst_bridge[i].encoder_active_sts &&
			!mst->mst_bridge[i].fixed_connector) {
			mst->mst_bridge[i].encoder_active_sts = true;
			mst->mst_bridge[i].connector = connector;
			mst->mst_bridge[i].dp_panel = conn->drv_panel;
		if (mst->mst_bridge[i].fixed_connector)
			continue;

		bridge_state = dp_mst_get_bridge_atomic_state(
				state->state, &mst->mst_bridge[i]);

		if (!bridge_state->connector) {
			bridge_state->connector = connector;
			bridge_state->dp_panel = conn->drv_panel;
			enc = mst->mst_bridge[i].encoder;
			break;
		}

	}

end:
@@ -1371,23 +1419,6 @@ dp_mst_atomic_best_encoder(struct drm_connector *connector,
	return enc;
}

static struct dp_mst_bridge *_dp_mst_get_bridge_from_encoder(
		struct dp_display *dp_display,
		struct drm_encoder *encoder)
{
	struct dp_mst_private *mst = dp_display->dp_mst_prv_info;
	int i;

	for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
		if (mst->mst_bridge[i].encoder == encoder)
			return &mst->mst_bridge[i];
	}

	DP_MST_DEBUG("mst bridge detect for encoder failed\n");

	return NULL;
}

static int dp_mst_connector_atomic_check(struct drm_connector *connector,
		void *display, struct drm_connector_state *new_conn_state)
{
@@ -1396,7 +1427,8 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector,
	struct drm_connector_state *old_conn_state;
	struct drm_crtc *old_crtc;
	struct drm_crtc_state *crtc_state;
	struct dp_mst_bridge *bridge = NULL;
	struct dp_mst_bridge *bridge;
	struct dp_mst_bridge_state *bridge_state;
	struct dp_display *dp_display = display;
	struct dp_mst_private *mst = dp_display->dp_mst_prv_info;
	struct sde_connector *c_conn;
@@ -1404,18 +1436,9 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector,

	DP_MST_DEBUG("enter:\n");

	/*
	 * Skip atomic check during mst suspend, to avoid mismanagement of
	 * available vcpi slots.
	 */
	if (mst->state == PM_SUSPEND)
		return rc;

	if (!new_conn_state)
		return rc;

	mutex_lock(&mst->mst_lock);

	state = new_conn_state->state;

	old_conn_state = drm_atomic_get_old_connector_state(state, connector);
@@ -1435,22 +1458,47 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector,
				bridge->num_slots);
	}

	bridge = _dp_mst_get_bridge_from_encoder(dp_display,
			old_conn_state->best_encoder);
	if (!bridge)
	if (drm_atomic_crtc_needs_modeset(crtc_state)) {
		if (WARN_ON(!old_conn_state->best_encoder)) {
			rc = -EINVAL;
			goto end;
		}

		bridge = to_dp_mst_bridge(
				old_conn_state->best_encoder->bridge);

		bridge_state = dp_mst_get_bridge_atomic_state(state, bridge);
		if (IS_ERR(bridge_state)) {
			rc = PTR_ERR(bridge_state);
			goto end;
		}

		if (WARN_ON(bridge_state->connector != connector)) {
			rc = -EINVAL;
			goto end;
		}

	slots = bridge->num_slots;
	if (drm_atomic_crtc_needs_modeset(crtc_state) && slots > 0) {
		slots = bridge_state->num_slots;
		if (slots > 0) {
			rc = mst->mst_fw_cbs->atomic_release_vcpi_slots(state,
					&mst->mst_mgr, slots);
			if (rc) {
			DP_ERR("failed releasing %d vcpi slots rc:%d\n",
				pr_err("failed releasing %d vcpi slots %d\n",
						slots, rc);
				goto end;
			}
		}

		bridge_state->num_slots = 0;

		if (!new_conn_state->crtc && mst->state != PM_SUSPEND) {
			bridge_state->connector = NULL;
			bridge_state->dp_panel = NULL;

			DP_MST_DEBUG("clear best encoder: %d\n", bridge->id);
		}
	}

mode_set:
	if (!new_conn_state->crtc)
		goto end;
@@ -1460,28 +1508,45 @@ static int dp_mst_connector_atomic_check(struct drm_connector *connector,
	if (drm_atomic_crtc_needs_modeset(crtc_state) && crtc_state->active) {
		c_conn = to_sde_connector(connector);

		if (WARN_ON(!new_conn_state->best_encoder)) {
			rc = -EINVAL;
			goto end;
		}

		bridge = to_dp_mst_bridge(
				new_conn_state->best_encoder->bridge);

		bridge_state = dp_mst_get_bridge_atomic_state(state, bridge);
		if (IS_ERR(bridge_state)) {
			rc = PTR_ERR(bridge_state);
			goto end;
		}

		if (WARN_ON(bridge_state->connector != connector)) {
			rc = -EINVAL;
			goto end;
		}

		if (WARN_ON(bridge_state->num_slots)) {
			rc = -EINVAL;
			goto end;
		}

		dp_display->convert_to_dp_mode(dp_display, c_conn->drv_panel,
				&crtc_state->mode, &dp_mode);

		slots = _dp_mst_compute_config(state, mst, connector, &dp_mode);
		if (slots < 0) {
			rc = slots;

			/* Disconnect the conn and panel info from bridge */
			bridge = _dp_mst_get_bridge_from_encoder(dp_display,
						new_conn_state->best_encoder);
			if (!bridge)
			goto end;

			bridge->connector = NULL;
			bridge->dp_panel = NULL;
			bridge->encoder_active_sts = false;
		}

		bridge_state->num_slots = slots;
	}

end:
	mutex_unlock(&mst->mst_lock);
	DP_MST_DEBUG("mst connector:%d atomic check\n", connector->base.id);
	DP_MST_DEBUG("mst connector:%d atomic check ret %d\n",
			connector->base.id, rc);
	return rc;
}

@@ -1645,20 +1710,21 @@ dp_mst_fixed_atomic_best_encoder(struct drm_connector *connector,
	struct dp_mst_private *mst = dp_display->dp_mst_prv_info;
	struct sde_connector *conn = to_sde_connector(connector);
	struct drm_encoder *enc = NULL;
	struct dp_mst_bridge_state *bridge_state;
	u32 i;

	for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
		if (mst->mst_bridge[i].connector == connector) {
			enc = mst->mst_bridge[i].encoder;
			goto end;
		}
	}
	if (state->best_encoder)
		return state->best_encoder;

	for (i = 0; i < MAX_DP_MST_DRM_BRIDGES; i++) {
		if (mst->mst_bridge[i].fixed_connector == connector) {
			mst->mst_bridge[i].encoder_active_sts = true;
			mst->mst_bridge[i].connector = connector;
			mst->mst_bridge[i].dp_panel = conn->drv_panel;
			bridge_state = dp_mst_get_bridge_atomic_state(
					state->state, &mst->mst_bridge[i]);
			if (IS_ERR(bridge_state))
				goto end;

			bridge_state->connector = connector;
			bridge_state->dp_panel = conn->drv_panel;
			enc = mst->mst_bridge[i].encoder;
			break;
		}