diff options
author | Veera Sundaram Sankaran <veeras@codeaurora.org> | 2016-05-05 19:03:54 -0700 |
---|---|---|
committer | Kyle Yan <kyan@codeaurora.org> | 2016-07-05 15:31:41 -0700 |
commit | 2bb0363c03e989ab64618f7112d76e7a828d5d6e (patch) | |
tree | ab800dd25de225a90864e7c1e01f13b4f12919e8 /drivers/video | |
parent | 95eadad55b28aaaa92b02698ed3600dc06eb6d24 (diff) |
msm: mdss: handle used_buf during overlay off with invalid switch state
There might be cases where driver gets the resolution switch
request followed by suspend or adb shell stop. In such cases,
since the ctl parameters are already reconfigured, driver skips
the NULL kickoff during overlay off due to invalid switch state.
This leads to memory leak as the used_bufs are left intact. Fix
by moving the used_bufs to free_list, so that memory can be freed
later and also leaves the buffer list clean.
Change-Id: I80c6ad2dc85da0427ac7ba1c127f0aa044a81c09
Signed-off-by: Veera Sundaram Sankaran <veeras@codeaurora.org>
Diffstat (limited to 'drivers/video')
-rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 35 |
1 files changed, 34 insertions, 1 deletions
diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index a6f85c6deda8..457c5462c44f 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -4880,6 +4880,39 @@ static void mdss_mdp_set_lm_flag(struct msm_fb_data_type *mfd) } } +static void mdss_mdp_handle_invalid_switch_state(struct msm_fb_data_type *mfd) +{ + int rc = 0; + struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); + struct mdss_mdp_ctl *ctl = mdp5_data->ctl; + struct mdss_mdp_ctl *sctl = mdss_mdp_get_split_ctl(ctl); + struct mdss_mdp_data *buf, *tmpbuf; + + mfd->switch_state = MDSS_MDP_NO_UPDATE_REQUESTED; + + /* + * Handle only for cmd mode panels as for video mode, buffers + * cannot be freed at this point. Needs revisting to handle the + * use case for video mode panels. + */ + if (mfd->panel_info->type == MIPI_CMD_PANEL) { + if (ctl->ops.wait_pingpong) + rc = ctl->ops.wait_pingpong(ctl, NULL); + if (!rc && sctl && sctl->ops.wait_pingpong) + rc = sctl->ops.wait_pingpong(sctl, NULL); + if (rc) { + pr_err("wait for pp failed\n"); + return; + } + + mutex_lock(&mdp5_data->list_lock); + list_for_each_entry_safe(buf, tmpbuf, + &mdp5_data->bufs_used, buf_list) + list_move(&buf->buf_list, &mdp5_data->bufs_freelist); + mutex_unlock(&mdp5_data->list_lock); + } +} + static int mdss_mdp_overlay_on(struct msm_fb_data_type *mfd) { int rc; @@ -5064,7 +5097,7 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) need_cleanup = false; pr_warn("fb%d blank while mode switch (%d) in progress\n", mfd->index, mfd->switch_state); - mfd->switch_state = MDSS_MDP_NO_UPDATE_REQUESTED; + mdss_mdp_handle_invalid_switch_state(mfd); } mutex_unlock(&mfd->switch_lock); |