diff options
| author | Adrian Salido-Moreno <adrianm@codeaurora.org> | 2012-11-14 21:12:43 -0800 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:13:21 -0700 |
| commit | 0dc94c0e3b74494492fd5e0025707846eec8485c (patch) | |
| tree | d2a2f93ef5d659b850aa3d7480d7a0aa7001690b | |
| parent | a31f977a0c692f56dcded0e1917fa1bc6cfe6c80 (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.h | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 1 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_ctl.c | 15 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 132 |
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; } |
