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

Commit 0166f8e2 authored by Linux Build Service Account's avatar Linux Build Service Account Committed by Gerrit - the friendly Code Review server
Browse files

Merge "msm: mdss: Fix race conditions during device shutdown"

parents ae9fe4fb ee4e05c3
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;