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

Commit 1612783f authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: fix new and used pipe config in layer validation"

parents 6b548276 fe453b14
Loading
Loading
Loading
Loading
+69 −38
Original line number Diff line number Diff line
@@ -49,6 +49,12 @@ enum {
	MDSS_MDP_RETIRE_FENCE,
};

enum layer_pipe_q {
	LAYER_USES_NEW_PIPE_Q = 0,
	LAYER_USES_USED_PIPE_Q,
	LAYER_USES_DESTROY_PIPE_Q,
};

static inline bool is_layer_right_blend(struct mdp_rect *left_blend,
	struct mdp_rect *right_blend, u32 left_lm_w)
{
@@ -950,50 +956,65 @@ static bool __find_pipe_in_list(struct list_head *head,
	return false;
}

static struct mdss_mdp_pipe *__find_used_pipe(struct msm_fb_data_type *mfd,
		u32 pipe_ndx)
/*
 * Search pipe from destroy and cleanup list to avoid validation failure.
 * It is caller responsibility to hold the list lock before calling this API.
 */
static struct mdss_mdp_pipe *__find_and_move_cleanup_pipe(
	struct mdss_overlay_private *mdp5_data, u32 pipe_ndx)
{
	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
	struct mdss_mdp_pipe *pipe = NULL;
	bool found;

	mutex_lock(&mdp5_data->list_lock);

	found = __find_pipe_in_list(&mdp5_data->pipes_used, pipe_ndx, &pipe);

	/* check if the pipe is in the cleanup or destroy list */
	if (!found &&
	   (__find_pipe_in_list(&mdp5_data->pipes_destroy, pipe_ndx, &pipe) ||
	    __find_pipe_in_list(&mdp5_data->pipes_cleanup, pipe_ndx, &pipe))) {
		pr_debug("reuse pipe%d ndx:%d\n", pipe->num, pipe->ndx);
	if (__find_pipe_in_list(&mdp5_data->pipes_destroy, pipe_ndx, &pipe)) {
		pr_debug("reuse destroy pipe id:%d ndx:%d\n", pipe->num,
			pipe_ndx);
		list_move(&pipe->list, &mdp5_data->pipes_used);
	} else if (__find_pipe_in_list(&mdp5_data->pipes_cleanup, pipe_ndx,
			&pipe)) {
		pr_debug("reuse cleanup pipe id:%d ndx:%d\n", pipe->num,
			pipe_ndx);
		mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_left);
		mdss_mdp_mixer_pipe_unstage(pipe, pipe->mixer_right);
		pipe->mixer_stage = MDSS_MDP_STAGE_UNUSED;
		list_move(&pipe->list, &mdp5_data->pipes_used);
	}

	mutex_unlock(&mdp5_data->list_lock);
	return pipe;
}

/*
 * __assign_pipe_for_layer() - get a pipe for layer
 *
 * This function first searches the pipe from used list. On successful search,
 * it returns the same pipe for current layer. If pipe is switching mixer then
 * it will unstage it from current mixer. On failure search, it increments the
 * pipe refcount to allocate it for current cycle.
 * This function first searches the pipe from used list, cleanup list and
 * destroy list. On successful search, it returns the same pipe for current
 * layer. It also un-stage the pipe from current mixer for used, cleanup,
 * destroy pipes if they switches the mixer. On failure search, it returns
 * the null pipe.
 */
static struct mdss_mdp_pipe *__assign_pipe_for_layer(
	struct msm_fb_data_type *mfd,
	struct mdss_mdp_mixer *mixer, u32 pipe_ndx,
	bool *new_pipe)
	enum layer_pipe_q *pipe_q_type)
{
	struct mdss_mdp_pipe *pipe;
	struct mdss_mdp_pipe *pipe = NULL;
	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
	struct mdss_data_type *mdata = mfd_to_mdata(mfd);

	pipe = __find_used_pipe(mfd, pipe_ndx);
	*new_pipe = pipe ? false : true;
	mutex_lock(&mdp5_data->list_lock);
	__find_pipe_in_list(&mdp5_data->pipes_used, pipe_ndx, &pipe);
	if (IS_ERR_OR_NULL(pipe)) {
		pipe = __find_and_move_cleanup_pipe(mdp5_data, pipe_ndx);
		if (IS_ERR_OR_NULL(pipe))
			*pipe_q_type = LAYER_USES_NEW_PIPE_Q;
		else
			*pipe_q_type = LAYER_USES_DESTROY_PIPE_Q;
	} else {
		*pipe_q_type = LAYER_USES_USED_PIPE_Q;
	}
	mutex_unlock(&mdp5_data->list_lock);

	if (!*new_pipe) {
	/* found the pipe from used, destroy or cleanup list */
	if (!IS_ERR_OR_NULL(pipe)) {
		if (pipe->mixer_left != mixer) {
			if (!mixer->ctl || (mixer->ctl->mfd != mfd)) {
				pr_err("Can't switch mixer %d->%d pnum %d!\n",
@@ -1115,7 +1136,7 @@ static void __handle_free_list(struct mdss_overlay_private *mdp5_data,
static int __validate_layers(struct msm_fb_data_type *mfd,
	struct file *file, struct mdp_layer_commit_v1 *commit)
{
	int ret, i, release_ndx = 0, inputndx = 0;
	int ret, i, release_ndx = 0, inputndx = 0, destroy_ndx = 0;
	u32 left_lm_layers = 0, right_lm_layers = 0;
	u32 left_cnt = 0, right_cnt = 0;
	u32 left_lm_w = left_lm_w_from_mfd(mfd);
@@ -1130,7 +1151,7 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
	struct mdss_mdp_mixer *mixer = NULL;
	struct mdp_input_layer *layer, *prev_layer, *layer_list;
	bool is_single_layer = false;
	bool new_pipe = false;
	enum layer_pipe_q pipe_q_type;

	ret = mutex_lock_interruptible(&mdp5_data->ov_lock);
	if (ret)
@@ -1240,7 +1261,7 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
		}

		pipe = __assign_pipe_for_layer(mfd, mixer, layer->pipe_ndx,
			&new_pipe);
			&pipe_q_type);
		if (IS_ERR_OR_NULL(pipe)) {
			pr_err("error assigning pipe id=0x%x rc:%ld\n",
				layer->pipe_ndx, PTR_ERR(pipe));
@@ -1249,22 +1270,19 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
			goto validate_exit;
		}

		if (pipe_q_type == LAYER_USES_NEW_PIPE_Q)
			release_ndx |= pipe->ndx;
		if (pipe_q_type == LAYER_USES_DESTROY_PIPE_Q)
			destroy_ndx |= pipe->ndx;

		ret = mdss_mdp_pipe_map(pipe);
		if (IS_ERR_VALUE(ret)) {
			pr_err("Unable to map used pipe%d ndx=%x\n",
				pipe->num, pipe->ndx);
			if (new_pipe) {
				if (!list_empty(&pipe->list))
					list_del_init(&pipe->list);
				mdss_mdp_pipe_destroy(pipe);
			}
			layer->error_code = ret;
			goto validate_exit;
		}

		if (new_pipe)
			release_ndx |= pipe->ndx;

		ret = __configure_pipe_params(mfd, layer, pipe,
			left_blend_pipe, is_single_layer, mixer_mux);
		if (ret) {
@@ -1302,11 +1320,11 @@ static int __validate_layers(struct msm_fb_data_type *mfd,
	ret = __validate_secure_display(mdp5_data);

validate_exit:
	pr_debug("err=%d total_layer:%d left:%d right:%d release_ndx=0x%x processed=%d\n",
	pr_debug("err=%d total_layer:%d left:%d right:%d release_ndx=0x%x destroy_ndx=0x%x processed=%d\n",
		ret, layer_count, left_lm_layers, right_lm_layers,
		release_ndx, i);
		release_ndx, destroy_ndx, i);
	MDSS_XLOG(inputndx, layer_count, left_lm_layers, right_lm_layers,
		release_ndx, ret);
		release_ndx, destroy_ndx, ret);
	mutex_lock(&mdp5_data->list_lock);
	list_for_each_entry_safe(pipe, tmp, &mdp5_data->pipes_used, list) {
		if (IS_ERR_VALUE(ret)) {
@@ -1317,6 +1335,15 @@ validate_exit:
				if (!list_empty(&pipe->list))
					list_del_init(&pipe->list);
				mdss_mdp_pipe_destroy(pipe);
			} else if (pipe->ndx & destroy_ndx) {
				/*
				 * cleanup/destroy list pipes should move back
				 * to destroy list. Next/current kickoff cycle
				 * will release the pipe because validate also
				 * acquires ov_lock.
				 */
				list_move(&pipe->list,
					&mdp5_data->pipes_destroy);
			}
		} else {
			pipe->file = file;
@@ -1591,13 +1618,17 @@ int mdss_mdp_async_position_update(struct msm_fb_data_type *mfd,
	struct mdss_mdp_pipe *pipe = NULL;
	struct mdp_async_layer *layer;
	struct mdss_rect dst, src;
	struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd);
	u32 flush_bits = 0, inputndx = 0;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);

	for (i = 0; i < update_pos->input_layer_cnt; i++) {
		layer = &update_pos->input_layers[i];
		pipe = __find_used_pipe(mfd, layer->pipe_ndx);
		mutex_lock(&mdp5_data->list_lock);
		__find_pipe_in_list(&mdp5_data->pipes_used, layer->pipe_ndx,
			&pipe);
		mutex_unlock(&mdp5_data->list_lock);
		if (!pipe) {
			pr_err("invalid pipe ndx=0x%x for async update\n",
					layer->pipe_ndx);