summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAdrian Salido-Moreno <adrianm@codeaurora.org>2012-11-14 21:12:43 -0800
committerDavid Keitel <dkeitel@codeaurora.org>2016-03-23 20:13:21 -0700
commit0dc94c0e3b74494492fd5e0025707846eec8485c (patch)
treed2a2f93ef5d659b850aa3d7480d7a0aa7001690b
parenta31f977a0c692f56dcded0e1917fa1bc6cfe6c80 (diff)
msm: mdss: add proper locking during suspend/resume operations
Add locking mechanism to properly syncrhonize user space frame updates with suspend/resume operations. This should avoid some cases in which suspend operations will complete while frame update hasn't finished, leading to unwanted behavior. Change-Id: I4b254a6a547320199a6da722ef99563696686a20 Signed-off-by: Adrian Salido-Moreno <adrianm@codeaurora.org>
-rw-r--r--drivers/video/fbdev/msm/mdss_fb.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp.h1
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_ctl.c15
-rw-r--r--drivers/video/fbdev/msm/mdss_mdp_overlay.c132
4 files changed, 101 insertions, 48 deletions
diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h
index f2365661ae63..fea60ab11371 100644
--- a/drivers/video/fbdev/msm/mdss_fb.h
+++ b/drivers/video/fbdev/msm/mdss_fb.h
@@ -93,6 +93,7 @@ struct msm_fb_data_type {
u32 bl_scale;
u32 bl_min_lvl;
struct mutex lock;
+ struct mutex ov_lock;
struct platform_device *pdev;
diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h
index ffacc5d38450..470bb90bd1c7 100644
--- a/drivers/video/fbdev/msm/mdss_mdp.h
+++ b/drivers/video/fbdev/msm/mdss_mdp.h
@@ -284,7 +284,6 @@ int mdss_mdp_vsync_clk_enable(int enable);
void mdss_mdp_clk_ctrl(int enable, int isr);
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd);
-int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd);
int mdss_mdp_overlay_vsync_ctrl(struct msm_fb_data_type *mfd, int en);
int mdss_mdp_video_start(struct mdss_mdp_ctl *ctl);
int mdss_mdp_writeback_start(struct mdss_mdp_ctl *ctl);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_ctl.c b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
index 5bd432a22d39..00f58745290e 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_ctl.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_ctl.c
@@ -665,8 +665,6 @@ int mdss_mdp_ctl_off(struct msm_fb_data_type *mfd)
pr_debug("ctl_num=%d\n", mfd->ctl->num);
- mdss_mdp_overlay_release_all(mfd);
-
mutex_lock(&ctl->lock);
mdss_mdp_clk_ctrl(MDP_BLOCK_POWER_ON, false);
@@ -920,13 +918,16 @@ int mdss_mdp_display_commit(struct mdss_mdp_ctl *ctl, void *arg)
return -ENODEV;
}
- if (!ctl->power_on)
- return 0;
-
pr_debug("commit ctl=%d play_cnt=%d\n", ctl->num, ctl->play_cnt);
- if (mutex_lock_interruptible(&ctl->lock))
- return -EINTR;
+ ret = mutex_lock_interruptible(&ctl->lock);
+ if (ret)
+ return ret;
+
+ if (!ctl->power_on) {
+ mutex_unlock(&ctl->lock);
+ return 0;
+ }
mixer1_changed = (ctl->mixer_left && ctl->mixer_left->params_changed);
mixer2_changed = (ctl->mixer_right && ctl->mixer_right->params_changed);
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
index 4c04027e8518..e043da2baf7d 100644
--- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c
+++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c
@@ -356,8 +356,14 @@ static int mdss_mdp_overlay_set(struct msm_fb_data_type *mfd,
{
int ret;
- if (!mfd->panel_power_on)
+ ret = mutex_lock_interruptible(&mfd->ov_lock);
+ if (ret)
+ return ret;
+
+ if (!mfd->panel_power_on) {
+ mutex_unlock(&mfd->ov_lock);
return -EPERM;
+ }
if (req->flags & MDSS_MDP_ROT_ONLY) {
ret = mdss_mdp_overlay_rotator_setup(mfd, req);
@@ -372,6 +378,8 @@ static int mdss_mdp_overlay_set(struct msm_fb_data_type *mfd,
req->z_order -= MDSS_MDP_STAGE_0;
}
+ mutex_unlock(&mfd->ov_lock);
+
return ret;
}
@@ -417,6 +425,7 @@ static int mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
LIST_HEAD(destroy_pipes);
int i;
+ mutex_lock(&mfd->ov_lock);
mutex_lock(&mfd->lock);
list_for_each_entry_safe(pipe, tmp, &mfd->pipes_cleanup, cleanup_list) {
list_move(&pipe->cleanup_list, &destroy_pipes);
@@ -442,6 +451,7 @@ static int mdss_mdp_overlay_cleanup(struct msm_fb_data_type *mfd)
mutex_unlock(&mfd->lock);
list_for_each_entry_safe(pipe, tmp, &destroy_pipes, cleanup_list)
mdss_mdp_pipe_destroy(pipe);
+ mutex_unlock(&mfd->ov_lock);
return 0;
}
@@ -472,16 +482,11 @@ static int mdss_mdp_overlay_kickoff(struct mdss_mdp_ctl *ctl)
return ret;
}
-static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
+static int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx)
{
struct mdss_mdp_pipe *pipe;
- int i, ret = 0;
u32 pipe_ndx, unset_ndx = 0;
-
- if (!mfd || !mfd->ctl)
- return -ENODEV;
-
- pr_debug("unset ndx=%x\n", ndx);
+ int i;
if (ndx & MDSS_MDP_ROT_SESSION_MASK) {
struct mdss_mdp_rotator_session *rot;
@@ -490,14 +495,11 @@ static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
mdss_mdp_rotator_finish(rot);
} else {
pr_warn("unknown session id=%x\n", ndx);
- ret = -ENODEV;
+ return -ENODEV;
}
- return ret;
- }
-
- if (!mfd->ctl->power_on)
return 0;
+ }
for (i = 0; unset_ndx != ndx && i < MDSS_MDP_MAX_SSPP; i++) {
pipe_ndx = BIT(i);
@@ -515,37 +517,56 @@ static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
mdss_mdp_mixer_pipe_unstage(pipe);
}
}
+ return 0;
+}
+
+static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx)
+{
+ int ret = 0;
+
+ if (!mfd || !mfd->ctl)
+ return -ENODEV;
+
+ ret = mutex_lock_interruptible(&mfd->ov_lock);
+ if (ret)
+ return ret;
+
+ if (!mfd->panel_power_on) {
+ mutex_unlock(&mfd->ov_lock);
+ return -EPERM;
+ }
+
+ pr_debug("unset ndx=%x\n", ndx);
+
+ ret = mdss_mdp_overlay_release(mfd, ndx);
+
+ mutex_unlock(&mfd->ov_lock);
return ret;
}
-int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
+static int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd)
{
struct mdss_mdp_pipe *pipe;
u32 unset_ndx = 0;
int cnt = 0;
+ mutex_lock(&mfd->ov_lock);
mutex_lock(&mfd->lock);
- if (!list_empty(&mfd->pipes_used)) {
- list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
- if (pipe->ndx & MDSS_MDP_ROT_SESSION_MASK) {
- struct mdss_mdp_rotator_session *rot;
- rot = mdss_mdp_rotator_session_get(pipe->ndx);
- if (rot)
- mdss_mdp_rotator_finish(rot);
- } else {
- unset_ndx |= pipe->ndx;
- cnt++;
- }
- }
+ list_for_each_entry(pipe, &mfd->pipes_used, used_list) {
+ unset_ndx |= pipe->ndx;
+ cnt++;
}
mutex_unlock(&mfd->lock);
if (unset_ndx) {
pr_debug("%d pipes need cleanup (%x)\n", cnt, unset_ndx);
- mdss_mdp_overlay_unset(mfd, unset_ndx);
- mdss_mdp_overlay_kickoff(mfd->ctl);
+ mdss_mdp_overlay_release(mfd, unset_ndx);
}
+ mutex_unlock(&mfd->ov_lock);
+
+ if (cnt)
+ mdss_mdp_overlay_kickoff(mfd->ctl);
return 0;
}
@@ -635,9 +656,6 @@ static int mdss_mdp_overlay_queue(struct msm_fb_data_type *mfd,
ctl = pipe->mixer->ctl;
mdss_mdp_pipe_unlock(pipe);
- if ((ret == 0) && (mfd->panel_info.type == WRITEBACK_PANEL))
- ret = mdss_mdp_overlay_kickoff(ctl);
-
return ret;
}
@@ -648,14 +666,29 @@ static int mdss_mdp_overlay_play(struct msm_fb_data_type *mfd,
pr_debug("play req id=%x\n", req->id);
- if (!mfd->panel_power_on)
+ ret = mutex_lock_interruptible(&mfd->ov_lock);
+ if (ret)
+ return ret;
+
+ if (!mfd->panel_power_on) {
+ mutex_unlock(&mfd->ov_lock);
return -EPERM;
+ }
- if (req->id & MDSS_MDP_ROT_SESSION_MASK)
+ if (req->id & MDSS_MDP_ROT_SESSION_MASK) {
ret = mdss_mdp_overlay_rotate(mfd, req);
- else
+ } else {
ret = mdss_mdp_overlay_queue(mfd, req);
+ if ((ret == 0) && (mfd->panel_info.type == WRITEBACK_PANEL)) {
+ mutex_unlock(&mfd->ov_lock);
+ ret = mdss_mdp_overlay_kickoff(mfd->ctl);
+ return ret;
+ }
+ }
+
+ mutex_unlock(&mfd->ov_lock);
+
return ret;
}
@@ -729,10 +762,7 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
u32 offset;
int bpp, ret;
- if (!mfd)
- return;
-
- if (!mfd->ctl || !mfd->panel_power_on)
+ if (!mfd || !mfd->ctl)
return;
fbi = mfd->fbi;
@@ -742,6 +772,14 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
return;
}
+ if (mutex_lock_interruptible(&mfd->ov_lock))
+ return;
+
+ if (!mfd->panel_power_on) {
+ mutex_unlock(&mfd->ov_lock);
+ return;
+ }
+
memset(&data, 0, sizeof(data));
bpp = fbi->var.bits_per_pixel / 8;
@@ -792,6 +830,7 @@ static void mdss_mdp_overlay_pan_display(struct msm_fb_data_type *mfd)
return;
}
}
+ mutex_unlock(&mfd->ov_lock);
if (fbi->var.activate & FB_ACTIVATE_VBL)
mdss_mdp_overlay_kickoff(mfd->ctl);
@@ -1086,10 +1125,22 @@ static int mdss_mdp_overlay_ioctl_handler(struct msm_fb_data_type *mfd,
return ret;
}
+static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd)
+{
+ return mdss_mdp_ctl_on(mfd);
+}
+
+static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd)
+{
+ mdss_mdp_overlay_release_all(mfd);
+
+ return mdss_mdp_ctl_off(mfd);
+}
+
int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
{
- mfd->on_fnc = mdss_mdp_ctl_on;
- mfd->off_fnc = mdss_mdp_ctl_off;
+ mfd->on_fnc = mdss_mdp_overlay_on;
+ mfd->off_fnc = mdss_mdp_overlay_off;
mfd->hw_refresh = true;
mfd->do_histogram = NULL;
mfd->overlay_play_enable = true;
@@ -1102,6 +1153,7 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd)
INIT_LIST_HEAD(&mfd->pipes_used);
INIT_LIST_HEAD(&mfd->pipes_cleanup);
+ mutex_init(&mfd->ov_lock);
return 0;
}