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

Commit ee4e05c3 authored by Aravind Venkateswaran's avatar Aravind Venkateswaran
Browse files

msm: mdss: Fix race conditions during device shutdown



Wait for the display commit thread to exit and abort all
pending ioctls when releasing the framebuffer device. This is
necessary to address any potential race conditions between these
threads that operate on a common data structure.

Change-Id: I5ab32758c34d4e80c4e85f949ffa0054d3cb5340
Signed-off-by: default avatarAravind Venkateswaran <aravindh@codeaurora.org>
parent 579f6eef
Loading
Loading
Loading
Loading
+85 −22
Original line number Diff line number Diff line
@@ -93,7 +93,7 @@ static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p,
		unsigned long val, void *data);

static int __mdss_fb_display_thread(void *data);
static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd);
static int mdss_fb_send_panel_event(struct msm_fb_data_type *mfd,
					int event, void *arg);
void mdss_fb_no_update_notify_timer_cb(unsigned long data)
@@ -299,6 +299,7 @@ static void mdss_fb_shutdown(struct platform_device *pdev)
{
	struct msm_fb_data_type *mfd = platform_get_drvdata(pdev);

	mfd->shutdown_pending = true;
	lock_fb_info(mfd->fbi);
	mdss_fb_release_all(mfd->fbi, true);
	unlock_fb_info(mfd->fbi);
@@ -781,13 +782,18 @@ static int mdss_fb_mmap(struct fb_info *info, struct vm_area_struct *vma)
	u32 len = PAGE_ALIGN((start & ~PAGE_MASK) + info->fix.smem_len);
	unsigned long off = vma->vm_pgoff << PAGE_SHIFT;
	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
	int ret = 0;

	if (!start) {
		pr_warn("No framebuffer memory is allocated.\n");
		return -ENOMEM;
	}

	mdss_fb_pan_idle(mfd);
	ret = mdss_fb_pan_idle(mfd);
	if (ret) {
		pr_err("Shutdown pending. Aborting operation\n");
		return ret;
	}

	/* Set VM flags. */
	start &= PAGE_MASK;
@@ -1144,13 +1150,6 @@ static int mdss_fb_register(struct msm_fb_data_type *mfd)
		     mfd->index, fbi->var.xres, fbi->var.yres,
		     fbi->fix.smem_len);

	mfd->disp_thread = kthread_run(__mdss_fb_display_thread, mfd,
			"mdss_fb%d", mfd->index);
	if (IS_ERR(mfd->disp_thread)) {
		pr_err("unable to start display thread %d\n", mfd->index);
		return PTR_ERR(mfd->disp_thread);
	}

	return 0;
}

@@ -1161,6 +1160,11 @@ static int mdss_fb_open(struct fb_info *info, int user)
	int result;
	int pid = current->tgid;

	if (mfd->shutdown_pending) {
		pr_err("Shutdown pending. Aborting operation\n");
		return -EPERM;
	}

	list_for_each_entry(pinfo, &mfd->proc_list, list) {
		if (pinfo->pid == pid)
			break;
@@ -1180,23 +1184,47 @@ static int mdss_fb_open(struct fb_info *info, int user)

	result = pm_runtime_get_sync(info->dev);

	if (result < 0)
	if (result < 0) {
		pr_err("pm_runtime: fail to wake up\n");
		goto pm_error;
	}

	if (!mfd->ref_cnt) {
		mfd->disp_thread = kthread_run(__mdss_fb_display_thread, mfd,
				"mdss_fb%d", mfd->index);
		if (IS_ERR(mfd->disp_thread)) {
			pr_err("unable to start display thread %d\n",
				mfd->index);
			result = PTR_ERR(mfd->disp_thread);
			goto thread_error;
		}

		result = mdss_fb_blank_sub(FB_BLANK_UNBLANK, info,
					   mfd->op_enable);
		if (result) {
			pm_runtime_put(info->dev);
			pr_err("can't turn on fb%d! rc=%d\n", mfd->index,
				result);
			return result;
			goto blank_error;
		}
	}

	pinfo->ref_cnt++;
	mfd->ref_cnt++;

	return 0;

blank_error:
	kthread_stop(mfd->disp_thread);

thread_error:
	if (pinfo && !pinfo->ref_cnt) {
		list_del(&pinfo->list);
		kfree(pinfo);
	}
	pm_runtime_put(info->dev);

pm_error:
	return result;
}

static int mdss_fb_release_all(struct fb_info *info, bool release_all)
@@ -1238,6 +1266,9 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
			pm_runtime_put(info->dev);
		} while (release_all && pinfo->ref_cnt);

		if (release_all)
			kthread_stop(mfd->disp_thread);

		if (pinfo->ref_cnt == 0) {
			list_del(&pinfo->list);
			kfree(pinfo);
@@ -1274,6 +1305,8 @@ static int mdss_fb_release_all(struct fb_info *info, bool release_all)
	}

	if (!mfd->ref_cnt) {
		kthread_stop(mfd->disp_thread);

		ret = mdss_fb_blank_sub(FB_BLANK_POWERDOWN, info,
			mfd->op_enable);
		if (ret) {
@@ -1452,21 +1485,28 @@ static int __mdss_fb_sync_buf_done_callback(struct notifier_block *p,
 * hardware configuration. After this function returns it is safe to perform
 * software updates for next frame.
 */
static void mdss_fb_pan_idle(struct msm_fb_data_type *mfd)
static int mdss_fb_pan_idle(struct msm_fb_data_type *mfd)
{
	int ret;
	int ret = 0;

	ret = wait_event_timeout(mfd->idle_wait_q,
			!atomic_read(&mfd->commits_pending),
			(!atomic_read(&mfd->commits_pending) ||
			 mfd->shutdown_pending),
			msecs_to_jiffies(WAIT_DISP_OP_TIMEOUT));
	if (!ret) {
		pr_err("wait for idle timeout %d pending=%d\n",
				ret, atomic_read(&mfd->commits_pending));

		mdss_fb_signal_timeline(&mfd->mdp_sync_pt_data);
	} else if (mfd->shutdown_pending) {
		pr_debug("Shutdown signalled\n");
		return -EPERM;
	}

	return 0;
}


static int mdss_fb_pan_display_ex(struct fb_info *info,
		struct mdp_display_commit *disp_commit)
{
@@ -1484,7 +1524,11 @@ static int mdss_fb_pan_display_ex(struct fb_info *info,
	if (var->yoffset > (info->var.yres_virtual - info->var.yres))
		return -EINVAL;

	mdss_fb_pan_idle(mfd);
	ret = mdss_fb_pan_idle(mfd);
	if (ret) {
		pr_err("Shutdown pending. Aborting operation\n");
		return ret;
	}

	mutex_lock(&mfd->mdp_sync_pt_data.sync_mutex);
	if (info->fix.xpanstep)
@@ -1621,14 +1665,20 @@ static int __mdss_fb_display_thread(void *data)

	while (1) {
		wait_event(mfd->commit_wait_q,
				atomic_read(&mfd->commits_pending));
				(atomic_read(&mfd->commits_pending) ||
				 kthread_should_stop()));

		ret = __mdss_fb_perform_commit(mfd);
		if (kthread_should_stop())
			break;

		ret = __mdss_fb_perform_commit(mfd);
		atomic_dec(&mfd->commits_pending);
		wake_up_all(&mfd->idle_wait_q);
	}

	atomic_set(&mfd->commits_pending, 0);
	wake_up_all(&mfd->idle_wait_q);

	return ret;
}

@@ -1752,8 +1802,14 @@ static int mdss_fb_set_par(struct fb_info *info)
	struct msm_fb_data_type *mfd = (struct msm_fb_data_type *)info->par;
	struct fb_var_screeninfo *var = &info->var;
	int old_imgType;
	int ret = 0;

	ret = mdss_fb_pan_idle(mfd);
	if (ret) {
		pr_err("Shutdown pending. Aborting operation\n");
		return ret;
	}

	mdss_fb_pan_idle(mfd);
	old_imgType = mfd->fb_imgType;
	switch (var->bits_per_pixel) {
	case 16:
@@ -1813,7 +1869,7 @@ static int mdss_fb_set_par(struct fb_info *info)
		mfd->panel_reconfig = false;
	}

	return 0;
	return ret;
}

int mdss_fb_dcm(struct msm_fb_data_type *mfd, int req_state)
@@ -2052,8 +2108,15 @@ static int mdss_fb_ioctl(struct fb_info *info, unsigned int cmd,
	mfd = (struct msm_fb_data_type *)info->par;
	mdss_fb_power_setting_idle(mfd);
	if ((cmd != MSMFB_VSYNC_CTRL) && (cmd != MSMFB_OVERLAY_VSYNC_CTRL) &&
			(cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT))
		mdss_fb_pan_idle(mfd);
			(cmd != MSMFB_ASYNC_BLIT) && (cmd != MSMFB_BLIT) &&
			(cmd != MSMFB_NOTIFY_UPDATE)) {
		ret = mdss_fb_pan_idle(mfd);
		if (ret) {
			pr_debug("Shutdown pending. Aborting operation %x\n",
				cmd);
			return ret;
		}
	}

	switch (cmd) {
	case MSMFB_CURSOR:
+1 −0
Original line number Diff line number Diff line
@@ -202,6 +202,7 @@ struct msm_fb_data_type {
	atomic_t commits_pending;
	wait_queue_head_t commit_wait_q;
	wait_queue_head_t idle_wait_q;
	bool shutdown_pending;

	struct msm_fb_backup_type msm_fb_backup;
	struct completion power_set_comp;