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

Commit cf79fd81 authored by Ingrid Gallardo's avatar Ingrid Gallardo Committed by Gerrit - the friendly Code Review server
Browse files

msm: mdss: fix race conditions when enabling mdp clocks



During the early wakeup event for command mode panels
the enable of power, clocks and restore of the
controllers status happen in a different thread
context. This can cause a race condition with
multiple threads that also try to enable the power
resources and assume that the status of the
controllers has been restored.
Prevent race condition for multiple threads trying
to enable the resources, by making sure that the
complete power on, clocks and restore of the
controllers happen before return from the first
call to enable the clocks. This fixes random ping pong
timeouts observed due above described race conditions.

Change-Id: Ie3607797994a5d4f533c4d4838718b0229e32dc6
Signed-off-by: default avatarIngrid Gallardo <ingridg@codeaurora.org>
parent 735b4a9b
Loading
Loading
Loading
Loading
+24 −13
Original line number Diff line number Diff line
@@ -631,15 +631,20 @@ static int mdss_mdp_clk_update(u32 clk_idx, u32 enable)
	return ret;
}

int mdss_mdp_vsync_clk_enable(int enable)
int mdss_mdp_vsync_clk_enable(int enable, bool locked)
{
	int ret = 0;
	pr_debug("clk enable=%d\n", enable);

	if (!locked)
		mutex_lock(&mdp_clk_lock);

	if (mdss_res->vsync_ena != enable) {
		mdss_res->vsync_ena = enable;
		ret = mdss_mdp_clk_update(MDSS_CLK_MDP_VSYNC, enable);
	}

	if (!locked)
		mutex_unlock(&mdp_clk_lock);
	return ret;
}
@@ -673,14 +678,20 @@ void mdss_mdp_set_clk_rate(unsigned long rate)
	}
}

unsigned long mdss_mdp_get_clk_rate(u32 clk_idx)
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx, bool locked)
{
	unsigned long clk_rate = 0;
	struct clk *clk = mdss_mdp_get_clk(clk_idx);

	if (clk) {
		if (!locked)
			mutex_lock(&mdp_clk_lock);
	if (clk)

		clk_rate = clk_get_rate(clk);

		if (!locked)
			mutex_unlock(&mdp_clk_lock);
	}

	return clk_rate;
}
@@ -827,7 +838,7 @@ static int mdss_mdp_idle_pc_restore(void)
	}
	mdss_hw_init(mdata);
	mdss_iommu_ctrl(0);
	mdss_mdp_ctl_restore();
	mdss_mdp_ctl_restore(true);
	mdata->idle_pc = false;

end:
@@ -956,10 +967,10 @@ void mdss_mdp_clk_ctrl(int enable)
		}
	}

	mutex_unlock(&mdp_clk_lock);

	if (enable && changed)
		mdss_mdp_idle_pc_restore();

	mutex_unlock(&mdp_clk_lock);
}

static inline int mdss_mdp_irq_clk_register(struct mdss_data_type *mdata,
@@ -1093,7 +1104,7 @@ static int mdss_mdp_irq_clk_setup(struct mdss_data_type *mdata)
	/* Setting the default clock rate to the max supported.*/
	mdss_mdp_set_clk_rate(mdata->max_mdp_clk_rate);
	pr_debug("mdp clk rate=%ld\n",
		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_CORE));
		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_CORE, false));

	return 0;
}
@@ -1226,10 +1237,8 @@ static void mdss_hw_rev_init(struct mdss_data_type *mdata)
	if (mdata->mdp_rev)
		return;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	mdata->mdp_rev = MDSS_REG_READ(mdata, MDSS_REG_HW_VERSION);
	mdss_mdp_hw_rev_caps_init(mdata);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
}

/**
@@ -1502,7 +1511,9 @@ static ssize_t mdss_mdp_show_capabilities(struct device *dev,
#define SPRINT(fmt, ...) \
		(cnt += scnprintf(buf + cnt, len - cnt, fmt, ##__VA_ARGS__))

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	mdss_hw_rev_init(mdata);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

	SPRINT("mdp_version=5\n");
	SPRINT("hw_rev=%d\n", mdata->mdp_rev);
+4 −4
Original line number Diff line number Diff line
@@ -235,7 +235,7 @@ struct mdss_mdp_ctl_intfs_ops {
					struct mdss_mdp_vsync_handler *);
	int (*config_fps_fnc)(struct mdss_mdp_ctl *ctl,
				struct mdss_mdp_ctl *sctl, int new_fps);
	int (*restore_fnc)(struct mdss_mdp_ctl *ctl);
	int (*restore_fnc)(struct mdss_mdp_ctl *ctl, bool locked);
	int (*early_wake_up_fnc)(struct mdss_mdp_ctl *ctl);

	/*
@@ -990,8 +990,8 @@ int mdss_mdp_set_intr_callback(u32 intr_type, u32 intf_num,
void mdss_mdp_footswitch_ctrl_splash(int on);
void mdss_mdp_batfet_ctrl(struct mdss_data_type *mdata, int enable);
void mdss_mdp_set_clk_rate(unsigned long min_clk_rate);
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx);
int mdss_mdp_vsync_clk_enable(int enable);
unsigned long mdss_mdp_get_clk_rate(u32 clk_idx, bool locked);
int mdss_mdp_vsync_clk_enable(int enable, bool locked);
void mdss_mdp_clk_ctrl(int enable);
struct mdss_data_type *mdss_mdp_get_mdata(void);
int mdss_mdp_secure_display_ctrl(unsigned int enable);
@@ -1265,7 +1265,7 @@ int mdss_mdp_wb_get_format(struct msm_fb_data_type *mfd,
void mdss_mdp_pipe_calc_pixel_extn(struct mdss_mdp_pipe *pipe);
int mdss_mdp_wb_set_secure(struct msm_fb_data_type *mfd, int enable);
int mdss_mdp_wb_get_secure(struct msm_fb_data_type *mfd, uint8_t *enable);
void mdss_mdp_ctl_restore(void);
void mdss_mdp_ctl_restore(bool locked);
int  mdss_mdp_ctl_reset(struct mdss_mdp_ctl *ctl);
int mdss_mdp_wait_for_xin_halt(u32 xin_id, bool is_vbif_nrt);
void mdss_mdp_set_ot_limit(struct mdss_mdp_set_ot_params *params);
+9 −4
Original line number Diff line number Diff line
@@ -3144,19 +3144,25 @@ static void mdss_mdp_ctl_restore_sub(struct mdss_mdp_ctl *ctl)

/*
 * mdss_mdp_ctl_restore() - restore mdp ctl path
 * @locked - boolean to signal that clock lock is already acquired
 *
 * This function is called whenever MDP comes out of a power collapse as
 * a result of a screen update. It restores the MDP controller's software
 * state to the hardware registers.
 * Function does not enable the clocks, so caller must make sure
 * clocks are enabled before calling.
 * The locked boolean in the parametrs signals that synchronization
 * with mdp clocks access is not required downstream.
 * Only call this function setting this value to true if the clocks access
 * synchronization is guaranteed by the caller.
 */
void mdss_mdp_ctl_restore(void)
void mdss_mdp_ctl_restore(bool locked)
{
	struct mdss_mdp_ctl *ctl = NULL;
	struct mdss_mdp_ctl *sctl;
	struct mdss_data_type *mdata = mdss_mdp_get_mdata();
	u32 cnum;

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	for (cnum = MDSS_MDP_CTL0; cnum < mdata->nctl; cnum++) {
		ctl = mdata->ctl_off + cnum;
		if (!mdss_mdp_ctl_is_power_on(ctl))
@@ -3172,9 +3178,8 @@ void mdss_mdp_ctl_restore(void)
			mdss_mdp_ctl_split_display_enable(1, ctl, sctl);
		}
		if (ctl->ops.restore_fnc)
			ctl->ops.restore_fnc(ctl);
			ctl->ops.restore_fnc(ctl, locked);
	}
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
}

static int mdss_mdp_ctl_start_sub(struct mdss_mdp_ctl *ctl, bool handoff)
+16 −14
Original line number Diff line number Diff line
@@ -179,7 +179,7 @@ static int mdss_mdp_tearcheck_enable(struct mdss_mdp_ctl *ctl, bool enable)
}

static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
		struct mdss_mdp_cmd_ctx *ctx)
		struct mdss_mdp_cmd_ctx *ctx, bool locked)
{
	struct mdss_mdp_pp_tear_check *te = NULL;
	struct mdss_panel_info *pinfo;
@@ -196,10 +196,10 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
	pinfo = &ctl->panel_data->panel_info;
	te = &ctl->panel_data->panel_info.te;

	mdss_mdp_vsync_clk_enable(1);
	mdss_mdp_vsync_clk_enable(1, locked);

	vsync_clk_speed_hz =
		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC);
		mdss_mdp_get_clk_rate(MDSS_CLK_MDP_VSYNC, locked);

	total_lines = mdss_panel_get_vtotal(pinfo);

@@ -258,7 +258,8 @@ static int mdss_mdp_cmd_tearcheck_cfg(struct mdss_mdp_mixer *mixer,
	return 0;
}

static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx)
static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx,
		bool locked)
{
	int rc = 0;
	struct mdss_mdp_mixer *mixer;
@@ -267,7 +268,7 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx)

	mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_LEFT);
	if (mixer) {
		rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx);
		rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, locked);
		if (rc)
			goto err;
	}
@@ -276,7 +277,7 @@ static int mdss_mdp_cmd_tearcheck_setup(struct mdss_mdp_cmd_ctx *ctx)
	    !is_dsc_compression(pinfo)) {
		mixer = mdss_mdp_mixer_get(ctl, MDSS_MDP_MIXER_MUX_RIGHT);
		if (mixer)
			rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx);
			rc = mdss_mdp_cmd_tearcheck_cfg(mixer, ctx, locked);
	}
err:
	return rc;
@@ -1692,17 +1693,14 @@ int mdss_mdp_cmd_kickoff(struct mdss_mdp_ctl *ctl, void *arg)
	return 0;
}

int mdss_mdp_cmd_restore(struct mdss_mdp_ctl *ctl)
int mdss_mdp_cmd_restore(struct mdss_mdp_ctl *ctl, bool locked)
{
	pr_debug("%s: called for ctl%d\n", __func__, ctl->num);
	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
	if (mdss_mdp_cmd_tearcheck_setup(ctl->intf_ctx[MASTER_CTX]))
	if (mdss_mdp_cmd_tearcheck_setup(ctl->intf_ctx[MASTER_CTX], locked))
		pr_warn("%s: tearcheck setup failed\n", __func__);
	else
		mdss_mdp_tearcheck_enable(ctl, true);

	mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

	return 0;
}

@@ -2060,7 +2058,7 @@ static int mdss_mdp_cmd_ctx_setup(struct mdss_mdp_ctl *ctl,
	mdss_mdp_set_intr_callback(MDSS_MDP_IRQ_PING_PONG_COMP, ctx->pp_num,
				   mdss_mdp_cmd_pingpong_done, ctl);

	ret = mdss_mdp_cmd_tearcheck_setup(ctx);
	ret = mdss_mdp_cmd_tearcheck_setup(ctx, false);
	if (ret)
		pr_err("tearcheck setup failed\n");

@@ -2092,7 +2090,9 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
			 * explictly call the restore function to enable
			 * tearcheck logic.
			 */
			mdss_mdp_cmd_restore(ctl);
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
			mdss_mdp_cmd_restore(ctl, false);
			mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);

			/* Turn on panel so that it can exit low power mode */
			return mdss_mdp_cmd_panel_on(ctl, sctl);
@@ -2132,7 +2132,9 @@ static int mdss_mdp_cmd_intfs_setup(struct mdss_mdp_ctl *ctl,
			if (mdss_panel_is_power_on(ctx->panel_power_state)) {
				pr_debug("%s: cmd_start with panel always on\n",
						__func__);
				mdss_mdp_cmd_restore(ctl);
				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
				mdss_mdp_cmd_restore(ctl, false);
				mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
				return mdss_mdp_cmd_panel_on(ctl, sctl);
			} else {
				pr_err("Intf %d already in use\n", session);
+1 −1
Original line number Diff line number Diff line
@@ -4644,7 +4644,7 @@ static int mdss_mdp_overlay_handoff(struct msm_fb_data_type *mfd)
		goto error;
	}

	ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_CORE);
	ctl->clk_rate = mdss_mdp_get_clk_rate(MDSS_CLK_MDP_CORE, false);
	pr_debug("Set the ctl clock rate to %d Hz\n", ctl->clk_rate);

	rc = __mdss_mdp_ctl_handoff(ctl, mdata);