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>
diff --git a/drivers/video/msm/mdss/mdss_fb.c b/drivers/video/msm/mdss/mdss_fb.c
index 24d4723..a4a2af4 100644
--- a/drivers/video/msm/mdss/mdss_fb.c
+++ b/drivers/video/msm/mdss/mdss_fb.c
@@ -322,6 +322,7 @@
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);
@@ -1101,14 +1102,32 @@
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);
@@ -1120,6 +1139,7 @@
}
}
+ pinfo->ref_cnt++;
mfd->ref_cnt++;
return 0;
}
@@ -1127,7 +1147,9 @@
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);
@@ -1137,6 +1159,31 @@
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/msm/mdss/mdss_fb.h b/drivers/video/msm/mdss/mdss_fb.h
index 030fd67..65218c0 100644
--- a/drivers/video/msm/mdss/mdss_fb.h
+++ b/drivers/video/msm/mdss/mdss_fb.h
@@ -61,6 +61,8 @@
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);
@@ -81,6 +83,12 @@
/ (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;
@@ -148,6 +156,7 @@
u32 is_power_setting;
u32 dcm_state;
+ struct list_head proc_list;
};
struct msm_fb_backup_type {
diff --git a/drivers/video/msm/mdss/mdss_mdp.h b/drivers/video/msm/mdss/mdss_mdp.h
index 38b587d..08849c8 100644
--- a/drivers/video/msm/mdss/mdss_mdp.h
+++ b/drivers/video/msm/mdss/mdss_mdp.h
@@ -315,6 +315,7 @@
u32 ftch_id;
atomic_t ref_cnt;
u32 play_cnt;
+ int pid;
u32 flags;
u32 bwc_mode;
@@ -377,6 +378,7 @@
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/msm/mdss/mdss_mdp_overlay.c b/drivers/video/msm/mdss/mdss_mdp_overlay.c
index 32fea95..1a5a44b 100644
--- a/drivers/video/msm/mdss/mdss_mdp_overlay.c
+++ b/drivers/video/msm/mdss/mdss_mdp_overlay.c
@@ -241,6 +241,8 @@
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 @@
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);
@@ -902,6 +905,7 @@
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,
@@ -952,6 +956,10 @@
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 {
@@ -964,18 +972,31 @@
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)) {
@@ -995,6 +1016,14 @@
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;
}
@@ -2016,6 +2045,7 @@
int rc;
struct mdss_overlay_private *mdp5_data;
struct mdss_mdp_mixer *mixer;
+ int need_cleanup;
if (!mfd)
return -ENODEV;
@@ -2043,18 +2073,13 @@
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);
@@ -2099,6 +2124,7 @@
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;
@@ -2115,6 +2141,7 @@
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/msm/mdss/mdss_mdp_rotator.h b/drivers/video/msm/mdss/mdss_mdp_rotator.h
index 43c9e6a..74eeeeb 100644
--- a/drivers/video/msm/mdss/mdss_mdp_rotator.h
+++ b/drivers/video/msm/mdss/mdss_mdp_rotator.h
@@ -23,6 +23,7 @@
u32 session_id;
u32 ref_cnt;
u32 params_changed;
+ int pid;
u32 format;
u32 flags;
@@ -43,6 +44,7 @@
struct mdss_mdp_data dst_buf;
struct list_head head;
+ struct list_head list;
struct mdss_mdp_rotator_session *next;
};