Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a3b3d215 authored by Adrian Salido-Moreno's avatar Adrian Salido-Moreno Committed by Stephen Boyd
Browse files

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: default avatarAdrian Salido-Moreno <adrianm@codeaurora.org>
parent 7286daaf
Loading
Loading
Loading
Loading
+48 −1
Original line number Diff line number Diff line
@@ -322,6 +322,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);
@@ -1105,14 +1106,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);
@@ -1124,6 +1143,7 @@ static int mdss_fb_open(struct fb_info *info, int user)
		}
	}

	pinfo->ref_cnt++;
	mfd->ref_cnt++;
	return 0;
}
@@ -1131,7 +1151,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);
@@ -1141,6 +1163,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);
+9 −0
Original line number Diff line number Diff line
@@ -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 {
+2 −0
Original line number Diff line number Diff line
@@ -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;
};

+41 −14
Original line number Diff line number Diff line
@@ -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,19 +975,32 @@ 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) {
		if (pipe->pid == pid) {
			unset_ndx |= pipe->ndx;
			cnt++;
		}
	}

	if (cnt == 0 && !list_empty(&mdp5_data->pipes_cleanup)) {
		pr_debug("overlay release on fb%d called without commit!",
@@ -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,19 +2086,14 @@ 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);

	if (need_cleanup) {
			pr_debug("cleaning up some pipes\n");
		pr_debug("cleaning up pipes on fb%d\n", mfd->index);
		mdss_mdp_overlay_kickoff(mfd);
	}
	}

	rc = mdss_mdp_ctl_stop(mdp5_data->ctl);
	if (rc == 0) {
@@ -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;
+2 −0
Original line number Diff line number Diff line
@@ -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;
};