msm: mdss: fix race condition between commit thread and power off
There is a deadlock in use cases where the power off is called concurrently with the overlay kickoff from different threads. To avoid this condition, during power off sequence we first make sure to stop the fb display thread before the power off sequence is handled. Change-Id: I708143206b914f6f72c440c4dc3a1c73fceea6b2 Signed-off-by: Ingrid Gallardo <ingridg@codeaurora.org>
This commit is contained in:
parent
71c3d682f9
commit
3ee962653b
1 changed files with 47 additions and 25 deletions
|
@ -1152,6 +1152,38 @@ void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
|
||||||
mutex_unlock(&mfd->bl_lock);
|
mutex_unlock(&mfd->bl_lock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mdss_fb_start_disp_thread(struct msm_fb_data_type *mfd)
|
||||||
|
{
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
pr_debug("%pS: start display thread fb%d\n",
|
||||||
|
__builtin_return_address(0), mfd->index);
|
||||||
|
|
||||||
|
mdss_fb_get_split(mfd);
|
||||||
|
|
||||||
|
atomic_set(&mfd->commits_pending, 0);
|
||||||
|
mfd->disp_thread = kthread_run(__mdss_fb_display_thread,
|
||||||
|
mfd, "mdss_fb%d", mfd->index);
|
||||||
|
|
||||||
|
if (IS_ERR(mfd->disp_thread)) {
|
||||||
|
pr_err("ERROR: unable to start display thread %d\n",
|
||||||
|
mfd->index);
|
||||||
|
ret = PTR_ERR(mfd->disp_thread);
|
||||||
|
mfd->disp_thread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void mdss_fb_stop_disp_thread(struct msm_fb_data_type *mfd)
|
||||||
|
{
|
||||||
|
pr_debug("%pS: stop display thread fb%d\n",
|
||||||
|
__builtin_return_address(0), mfd->index);
|
||||||
|
|
||||||
|
kthread_stop(mfd->disp_thread);
|
||||||
|
mfd->disp_thread = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
|
static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
|
||||||
int op_enable)
|
int op_enable)
|
||||||
{
|
{
|
||||||
|
@ -1165,16 +1197,28 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
|
||||||
if (mfd->dcm_state == DCM_ENTER)
|
if (mfd->dcm_state == DCM_ENTER)
|
||||||
return -EPERM;
|
return -EPERM;
|
||||||
|
|
||||||
|
pr_debug("%pS mode:%d\n", __builtin_return_address(0),
|
||||||
|
blank_mode);
|
||||||
|
|
||||||
cur_power_state = mfd->panel_power_state;
|
cur_power_state = mfd->panel_power_state;
|
||||||
switch (blank_mode) {
|
switch (blank_mode) {
|
||||||
case FB_BLANK_UNBLANK:
|
case FB_BLANK_UNBLANK:
|
||||||
pr_debug("unblank called. cur pwr state=%d\n", cur_power_state);
|
pr_debug("unblank called. cur pwr state=%d\n", cur_power_state);
|
||||||
|
/* Start Display thread */
|
||||||
|
if (mfd->disp_thread == NULL) {
|
||||||
|
ret = mdss_fb_start_disp_thread(mfd);
|
||||||
|
if (ret < 0)
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
if (!mdss_panel_is_power_on_interactive(cur_power_state) &&
|
if (!mdss_panel_is_power_on_interactive(cur_power_state) &&
|
||||||
mfd->mdp.on_fnc) {
|
mfd->mdp.on_fnc) {
|
||||||
ret = mfd->mdp.on_fnc(mfd);
|
ret = mfd->mdp.on_fnc(mfd);
|
||||||
if (ret == 0) {
|
if (ret == 0) {
|
||||||
mfd->panel_power_state = MDSS_PANEL_POWER_ON;
|
mfd->panel_power_state = MDSS_PANEL_POWER_ON;
|
||||||
mfd->panel_info->panel_dead = false;
|
mfd->panel_info->panel_dead = false;
|
||||||
|
} else if (mfd->disp_thread) {
|
||||||
|
mdss_fb_stop_disp_thread(mfd);
|
||||||
}
|
}
|
||||||
mutex_lock(&mfd->update.lock);
|
mutex_lock(&mfd->update.lock);
|
||||||
mfd->update.type = NOTIFY_TYPE_UPDATE;
|
mfd->update.type = NOTIFY_TYPE_UPDATE;
|
||||||
|
@ -1233,6 +1277,9 @@ static int mdss_fb_blank_sub(int blank_mode, struct fb_info *info,
|
||||||
mfd->op_enable = false;
|
mfd->op_enable = false;
|
||||||
mutex_lock(&mfd->bl_lock);
|
mutex_lock(&mfd->bl_lock);
|
||||||
if (mdss_panel_is_power_off(req_power_state)) {
|
if (mdss_panel_is_power_off(req_power_state)) {
|
||||||
|
/* Stop Display thread */
|
||||||
|
if (mfd->disp_thread)
|
||||||
|
mdss_fb_stop_disp_thread(mfd);
|
||||||
mdss_fb_set_backlight(mfd, 0);
|
mdss_fb_set_backlight(mfd, 0);
|
||||||
mfd->bl_updated = 0;
|
mfd->bl_updated = 0;
|
||||||
}
|
}
|
||||||
|
@ -2037,17 +2084,6 @@ static int mdss_fb_open(struct fb_info *info, int user)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mfd->ref_cnt) {
|
if (!mfd->ref_cnt) {
|
||||||
mdss_fb_get_split(mfd);
|
|
||||||
mfd->disp_thread = kthread_run(__mdss_fb_display_thread, mfd,
|
|
||||||
"mdss_fb%d", mfd->index);
|
|
||||||
if (IS_ERR(mfd->disp_thread)) {
|
|
||||||
pr_err("unable to start display thread %d\n",
|
|
||||||
mfd->index);
|
|
||||||
result = PTR_ERR(mfd->disp_thread);
|
|
||||||
mfd->disp_thread = NULL;
|
|
||||||
goto thread_error;
|
|
||||||
}
|
|
||||||
|
|
||||||
result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
|
result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
|
||||||
mfd->op_enable);
|
mfd->op_enable);
|
||||||
if (result) {
|
if (result) {
|
||||||
|
@ -2063,10 +2099,6 @@ static int mdss_fb_open(struct fb_info *info, int user)
|
||||||
return 0;
|
return 0;
|
||||||
|
|
||||||
blank_error:
|
blank_error:
|
||||||
kthread_stop(mfd->disp_thread);
|
|
||||||
mfd->disp_thread = NULL;
|
|
||||||
|
|
||||||
thread_error:
|
|
||||||
pm_runtime_put(info->dev);
|
pm_runtime_put(info->dev);
|
||||||
|
|
||||||
pm_error:
|
pm_error:
|
||||||
|
@ -2137,11 +2169,6 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
|
||||||
pm_runtime_put(info->dev);
|
pm_runtime_put(info->dev);
|
||||||
} while (release_all && pinfo->ref_cnt);
|
} while (release_all && pinfo->ref_cnt);
|
||||||
|
|
||||||
if (release_all && mfd->disp_thread) {
|
|
||||||
kthread_stop(mfd->disp_thread);
|
|
||||||
mfd->disp_thread = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (pinfo->ref_cnt == 0) {
|
if (pinfo->ref_cnt == 0) {
|
||||||
list_del(&pinfo->list);
|
list_del(&pinfo->list);
|
||||||
kfree(pinfo);
|
kfree(pinfo);
|
||||||
|
@ -2187,11 +2214,6 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!mfd->ref_cnt) {
|
if (!mfd->ref_cnt) {
|
||||||
if (mfd->disp_thread) {
|
|
||||||
kthread_stop(mfd->disp_thread);
|
|
||||||
mfd->disp_thread = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (mfd->mdp.release_fnc) {
|
if (mfd->mdp.release_fnc) {
|
||||||
ret = mfd->mdp.release_fnc(mfd, true, pid);
|
ret = mfd->mdp.release_fnc(mfd, true, pid);
|
||||||
if (ret)
|
if (ret)
|
||||||
|
|
Loading…
Add table
Reference in a new issue