msm: mdss: fix race condition between vsync handler and ctl_stop

The ctl_stop and vsync_handler both can run in two different
threads. That can lead to race condition in vsync handler.
   -> Core 0: vsync handler thread checks the ctl power status
      and get preempted by other priority task.
   -> Core 1: processes the ctl_stop and power off the display
      device.
   -> Core 0: Vsync handler task gets chance to run again and
      tries to access the ctl->op members.

The third step leads to invalid structure member access because
display is already powered off. This race condition should be
fixed by moving all power state checks inside mutex lock.

Change-Id: I452c9026074acda2d00954e530fc491d395f106b
Signed-off-by: Dhaval Patel <pdhaval@codeaurora.org>
This commit is contained in:
Dhaval Patel 2016-01-29 15:07:38 -08:00 committed by David Keitel
parent 6b236392b5
commit 7dc5ab2669

View file

@ -2620,27 +2620,35 @@ int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en)
if (!ctl)
return -ENODEV;
if (!ctl->ops.add_vsync_handler || !ctl->ops.remove_vsync_handler)
return -EOPNOTSUPP;
mutex_lock(&mdp5_data->ov_lock);
if (!ctl->ops.add_vsync_handler || !ctl->ops.remove_vsync_handler) {
rc = -EOPNOTSUPP;
pr_err_once("fb%d vsync handlers are not registered\n",
mfd->index);
goto end;
}
if (!ctl->panel_data->panel_info.cont_splash_enabled
&& (!mdss_mdp_ctl_is_power_on(ctl) ||
mdss_panel_is_power_on_ulp(ctl->power_state))) {
pr_debug("fb%d vsync pending first update en=%d\n",
mfd->index, en);
return -EPERM;
pr_debug("fb%d vsync pending first update en=%d, ctl power state:%d\n",
mfd->index, en, ctl->power_state);
rc = -EPERM;
goto end;
}
pr_debug("fb%d vsync en=%d\n", mfd->index, en);
mutex_lock(&mdp5_data->ov_lock);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON);
if (en)
rc = ctl->ops.add_vsync_handler(ctl, &ctl->vsync_handler);
else
rc = ctl->ops.remove_vsync_handler(ctl, &ctl->vsync_handler);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_OFF);
mutex_unlock(&mdp5_data->ov_lock);
end:
mutex_unlock(&mdp5_data->ov_lock);
return rc;
}