diff options
| author | Adrian Salido-Moreno <adrianm@codeaurora.org> | 2013-07-30 13:50:20 -0700 |
|---|---|---|
| committer | David Keitel <dkeitel@codeaurora.org> | 2016-03-23 20:19:58 -0700 |
| commit | 754bf27ee161e1a23f1ca227f7a44e0556b57879 (patch) | |
| tree | f175c3895fd00cbb55dc842f0596117785d95b4d /drivers/video/fbdev | |
| parent | 18ffde2b6cc09a760bef13fa4d5362998ea87e50 (diff) | |
msm: mdss: release process resources on fb close
Track overlays/rotator sessions created for each process and make sure
these are released during fb close. This can handle cases where crash
happens on a process that owns the resources, but panel wouldn't be
blanked due to other process still holding a reference to fb.
CRs-Fixed: 511804
Change-Id: Ib3b8b57c871f91c59e1bef36cd94b7d957185050
Signed-off-by: Adrian Salido-Moreno <adrianm@codeaurora.org>
Diffstat (limited to 'drivers/video/fbdev')
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.c | 49 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_fb.h | 9 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp.h | 2 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_overlay.c | 55 | ||||
| -rw-r--r-- | drivers/video/fbdev/msm/mdss_mdp_rotator.h | 2 |
5 files changed, 102 insertions, 15 deletions
diff --git a/drivers/video/fbdev/msm/mdss_fb.c b/drivers/video/fbdev/msm/mdss_fb.c index b09a42076b12..f7af14d2de81 100644 --- a/drivers/video/fbdev/msm/mdss_fb.c +++ b/drivers/video/fbdev/msm/mdss_fb.c @@ -323,6 +323,7 @@ static int mdss_fb_probe(struct platform_device *pdev) if (pdata->next) mfd->split_display = true; mfd->mdp = *mdp_instance; + INIT_LIST_HEAD(&mfd->proc_list); mutex_init(&mfd->lock); mutex_init(&mfd->bl_lock); @@ -1106,14 +1107,32 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd) static int mdss_fb_open(struct fb_info *info, int user) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct mdss_fb_proc_info *pinfo = NULL; int result; + int pid = current->tgid; + + list_for_each_entry(pinfo, &mfd->proc_list, list) { + if (pinfo->pid == pid) + break; + } + + if ((pinfo == NULL) || (pinfo->pid != pid)) { + pinfo = kmalloc(sizeof(*pinfo), GFP_KERNEL); + if (!pinfo) { + pr_err("unable to alloc process info\n"); + return -ENOMEM; + } + pinfo->pid = pid; + pinfo->ref_cnt = 0; + list_add(&pinfo->list, &mfd->proc_list); + pr_debug("new process entry pid=%d\n", pinfo->pid); + } result = pm_runtime_get_sync(info->dev); if (result < 0) pr_err("pm_runtime: fail to wake up\n"); - if (!mfd->ref_cnt) { result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info, mfd->op_enable); @@ -1125,6 +1144,7 @@ static int mdss_fb_open(struct fb_info *info, int user) } } + pinfo->ref_cnt++; mfd->ref_cnt++; return 0; } @@ -1132,7 +1152,9 @@ static int mdss_fb_open(struct fb_info *info, int user) static int mdss_fb_release(struct fb_info *info, int user) { struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par; + struct mdss_fb_proc_info *pinfo = NULL; int ret = 0; + int pid = current->tgid; if (!mfd->ref_cnt) { pr_info("try to close unopened fb %d!\n", mfd->index); @@ -1142,6 +1164,31 @@ static int mdss_fb_release(struct fb_info *info, int user) mdss_fb_pan_idle(mfd); mfd->ref_cnt--; + list_for_each_entry(pinfo, &mfd->proc_list, list) { + if (pinfo->pid == pid) + break; + } + + if (!pinfo || (pinfo->pid != pid)) { + pr_warn("unable to find process info for fb%d pid=%d\n", + mfd->index, pid); + } else { + pr_debug("found process entry pid=%d ref=%d\n", + pinfo->pid, pinfo->ref_cnt); + + pinfo->ref_cnt--; + if (pinfo->ref_cnt == 0) { + if (mfd->mdp.release_fnc) { + ret = mfd->mdp.release_fnc(mfd); + if (ret) + pr_err("error releasing fb%d pid=%d\n", + mfd->index, pinfo->pid); + } + list_del(&pinfo->list); + kfree(pinfo); + } + } + if (!mfd->ref_cnt) { ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info, mfd->op_enable); diff --git a/drivers/video/fbdev/msm/mdss_fb.h b/drivers/video/fbdev/msm/mdss_fb.h index 6019179e4216..3e94deef7963 100644 --- a/drivers/video/fbdev/msm/mdss_fb.h +++ b/drivers/video/fbdev/msm/mdss_fb.h @@ -64,6 +64,8 @@ struct msm_mdp_interface { int (*init_fnc)(struct msm_fb_data_type *mfd); int (*on_fnc)(struct msm_fb_data_type *mfd); int (*off_fnc)(struct msm_fb_data_type *mfd); + /* called to release resources associated to the process */ + int (*release_fnc)(struct msm_fb_data_type *mfd); int (*kickoff_fnc)(struct msm_fb_data_type *mfd); int (*ioctl_handler)(struct msm_fb_data_type *mfd, u32 cmd, void *arg); void (*dma_fnc)(struct msm_fb_data_type *mfd); @@ -84,6 +86,12 @@ struct msm_mdp_interface { / (2 * max_bright);\ } while (0) +struct mdss_fb_proc_info { + int pid; + u32 ref_cnt; + struct list_head list; +}; + struct msm_fb_data_type { u32 key; u32 index; @@ -154,6 +162,7 @@ struct msm_fb_data_type { u32 is_power_setting; u32 dcm_state; + struct list_head proc_list; }; struct msm_fb_backup_type { diff --git a/drivers/video/fbdev/msm/mdss_mdp.h b/drivers/video/fbdev/msm/mdss_mdp.h index ea3c52343e42..67044e26fdf8 100644 --- a/drivers/video/fbdev/msm/mdss_mdp.h +++ b/drivers/video/fbdev/msm/mdss_mdp.h @@ -315,6 +315,7 @@ struct mdss_mdp_pipe { u32 ftch_id; atomic_t ref_cnt; u32 play_cnt; + int pid; u32 flags; u32 bwc_mode; @@ -377,6 +378,7 @@ struct mdss_overlay_private { struct list_head overlay_list; struct list_head pipes_used; struct list_head pipes_cleanup; + struct list_head rot_proc_list; bool mixer_swap; }; diff --git a/drivers/video/fbdev/msm/mdss_mdp_overlay.c b/drivers/video/fbdev/msm/mdss_mdp_overlay.c index cbd59060cb18..c5480364d9b7 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_overlay.c +++ b/drivers/video/fbdev/msm/mdss_mdp_overlay.c @@ -241,6 +241,8 @@ static int mdss_mdp_overlay_rotator_setup(struct msm_fb_data_type *mfd, if (req->id == MSMFB_NEW_REQUEST) { rot = mdss_mdp_rotator_session_alloc(); + rot->pid = current->tgid; + list_add(&rot->list, &mdp5_data->rot_proc_list); if (!rot) { pr_err("unable to allocate rotator session\n"); @@ -439,6 +441,7 @@ static int mdss_mdp_overlay_pipe_setup(struct msm_fb_data_type *mfd, mutex_unlock(&mfd->lock); pipe->mixer = mixer; pipe->mfd = mfd; + pipe->pid = current->tgid; pipe->play_cnt = 0; } else { pipe = mdss_mdp_pipe_get(mdp5_data->mdata, req->id); @@ -905,6 +908,7 @@ static int mdss_mdp_overlay_release(struct msm_fb_data_type *mfd, int ndx) continue; } mutex_lock(&mfd->lock); + pipe->pid = 0; if (!list_empty(&pipe->used_list)) { list_del_init(&pipe->used_list); list_add(&pipe->cleanup_list, @@ -955,6 +959,10 @@ static int mdss_mdp_overlay_unset(struct msm_fb_data_type *mfd, int ndx) if (rot) { mdss_mdp_overlay_free_buf(&rot->src_buf); mdss_mdp_overlay_free_buf(&rot->dst_buf); + + rot->pid = 0; + if (!list_empty(&rot->list)) + list_del_init(&rot->list); ret = mdss_mdp_rotator_release(rot); } } else { @@ -967,18 +975,31 @@ done: return ret; } -static int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd) +/** + * mdss_mdp_overlay_release_all() - release any overlays associated with fb dev + * @mfd: Msm frame buffer structure associated with fb device + * + * Release any resources allocated by calling process, this can be called + * on fb_release to release any overlays/rotator sessions left open. + */ +static int __mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd) { struct mdss_mdp_pipe *pipe; + struct mdss_mdp_rotator_session *rot, *tmp; struct mdss_overlay_private *mdp5_data = mfd_to_mdp5_data(mfd); u32 unset_ndx = 0; int cnt = 0; + int pid = current->tgid; + + pr_debug("releasing all resources for fb%d pid=%d\n", mfd->index, pid); mutex_lock(&mdp5_data->ov_lock); mutex_lock(&mfd->lock); list_for_each_entry(pipe, &mdp5_data->pipes_used, used_list) { - unset_ndx |= pipe->ndx; - cnt++; + if (pipe->pid == pid) { + unset_ndx |= pipe->ndx; + cnt++; + } } if (cnt == 0 && !list_empty(&mdp5_data->pipes_cleanup)) { @@ -998,6 +1019,14 @@ static int mdss_mdp_overlay_release_all(struct msm_fb_data_type *mfd) if (cnt) mfd->mdp.kickoff_fnc(mfd); + list_for_each_entry_safe(rot, tmp, &mdp5_data->rot_proc_list, list) { + if (rot->pid == pid) { + if (!list_empty(&rot->list)) + list_del_init(&rot->list); + mdss_mdp_rotator_release(rot); + } + } + return 0; } @@ -2029,6 +2058,7 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) int rc; struct mdss_overlay_private *mdp5_data; struct mdss_mdp_mixer *mixer; + int need_cleanup; if (!mfd) return -ENODEV; @@ -2056,18 +2086,13 @@ static int mdss_mdp_overlay_off(struct msm_fb_data_type *mfd) if (mixer) mixer->cursor_enabled = 0; - if (!mfd->ref_cnt) { - mdss_mdp_overlay_release_all(mfd); - } else { - int need_cleanup; - mutex_lock(&mfd->lock); - need_cleanup = !list_empty(&mdp5_data->pipes_cleanup); - mutex_unlock(&mfd->lock); + mutex_lock(&mfd->lock); + need_cleanup = !list_empty(&mdp5_data->pipes_cleanup); + mutex_unlock(&mfd->lock); - if (need_cleanup) { - pr_debug("cleaning up some pipes\n"); - mdss_mdp_overlay_kickoff(mfd); - } + if (need_cleanup) { + pr_debug("cleaning up pipes on fb%d\n", mfd->index); + mdss_mdp_overlay_kickoff(mfd); } rc = mdss_mdp_ctl_stop(mdp5_data->ctl); @@ -2112,6 +2137,7 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) mdp5_interface->on_fnc = mdss_mdp_overlay_on; mdp5_interface->off_fnc = mdss_mdp_overlay_off; + mdp5_interface->release_fnc = __mdss_mdp_overlay_release_all; mdp5_interface->do_histogram = NULL; mdp5_interface->cursor_update = mdss_mdp_hw_cursor_update; mdp5_interface->dma_fnc = mdss_mdp_overlay_pan_display; @@ -2128,6 +2154,7 @@ int mdss_mdp_overlay_init(struct msm_fb_data_type *mfd) INIT_LIST_HEAD(&mdp5_data->pipes_used); INIT_LIST_HEAD(&mdp5_data->pipes_cleanup); + INIT_LIST_HEAD(&mdp5_data->rot_proc_list); mutex_init(&mdp5_data->ov_lock); mdp5_data->hw_refresh = true; mdp5_data->overlay_play_enable = true; diff --git a/drivers/video/fbdev/msm/mdss_mdp_rotator.h b/drivers/video/fbdev/msm/mdss_mdp_rotator.h index 43c9e6af7596..74eeeeb29f4c 100644 --- a/drivers/video/fbdev/msm/mdss_mdp_rotator.h +++ b/drivers/video/fbdev/msm/mdss_mdp_rotator.h @@ -23,6 +23,7 @@ struct mdss_mdp_rotator_session { u32 session_id; u32 ref_cnt; u32 params_changed; + int pid; u32 format; u32 flags; @@ -43,6 +44,7 @@ struct mdss_mdp_rotator_session { struct mdss_mdp_data dst_buf; struct list_head head; + struct list_head list; struct mdss_mdp_rotator_session *next; }; |
