summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorIngrid Gallardo <ingridg@codeaurora.org>2014-07-31 19:42:10 -0700
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:34:02 -0700
commit3ee962653b755597843aeb3a1bf39836cadc4d45 (patch)
treeb14bad39a3de8cb72c0a454d055e7ae7a49e6e84
parent71c3d682f973937953be0760c3298e1d125cf58e (diff)
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>
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.c72
1 files changed, 47 insertions, 25 deletions
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c
index 1628fa100d4a..aad76953ab0d 100644
--- a/drivers/video/fbdev/msm/mdss_fb.c
+++ b/drivers/video/fbdev/msm/mdss_fb.c
@@ -1152,6 +1152,38 @@ void mdss_fb_update_backlight(struct msm_fb_data_type *mfd)
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,
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)
return -EPERM;
+ pr_debug("%pS mode:%d\n", __builtin_return_address(0),
+ blank_mode);
+
cur_power_state = mfd->panel_power_state;
switch (blank_mode) {
case FB_BLANK_UNBLANK:
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) &&
mfd->mdp.on_fnc) {
ret = mfd->mdp.on_fnc(mfd);
if (ret == 0) {
mfd->panel_power_state = MDSS_PANEL_POWER_ON;
mfd->panel_info->panel_dead = false;
+ } else if (mfd->disp_thread) {
+ mdss_fb_stop_disp_thread(mfd);
}
mutex_lock(&mfd->update.lock);
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;
mutex_lock(&mfd->bl_lock);
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);
mfd->bl_updated = 0;
}
@@ -2037,17 +2084,6 @@ static int mdss_fb_open(struct fb_info *info, int user)
}
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,
mfd->op_enable);
if (result) {
@@ -2063,10 +2099,6 @@ static int mdss_fb_open(struct fb_info *info, int user)
return 0;
blank_error:
- kthread_stop(mfd->disp_thread);
- mfd->disp_thread = NULL;
-
-thread_error:
pm_runtime_put(info->dev);
pm_error:
@@ -2137,11 +2169,6 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
pm_runtime_put(info->dev);
} 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) {
list_del(&pinfo->list);
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->disp_thread) {
- kthread_stop(mfd->disp_thread);
- mfd->disp_thread = NULL;
- }
-
if (mfd->mdp.release_fnc) {
ret = mfd->mdp.release_fnc(mfd, true, pid);
if (ret)