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

Commit 4a47a0e0 authored by Bruno Prémont's avatar Bruno Prémont Committed by Florian Tobias Schandinat
Browse files

fb: sh-mobile: Fix deadlock risk between lock_fb_info() and console_lock()



Following on Herton's patch "fb: avoid possible deadlock caused by
fb_set_suspend" which moves lock_fb_info() out of fb_set_suspend()
to its callers, correct sh-mobile's locking around call to
fb_set_suspend() and the same sort of deaklocks with console_lock()
due to order of taking the lock.

console_lock() must be taken while fb_info is already locked and fb_info
must be locked while calling fb_set_suspend().

Signed-off-by: default avatarBruno Prémont <bonbons@linux-vserver.org>
Signed-off-by: default avatarGuennadi Liakhovetski <g.liakhovetski@gmx.de>
Signed-off-by: default avatarFlorian Tobias Schandinat <FlorianSchandinat@gmx.de>
Cc: stable@kernel.org
parent 9e769ff3
Loading
Loading
Loading
Loading
+26 −21
Original line number Diff line number Diff line
@@ -1111,6 +1111,7 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate,
static void sh_hdmi_edid_work_fn(struct work_struct *work)
{
	struct sh_hdmi *hdmi = container_of(work, struct sh_hdmi, edid_work.work);
	struct fb_info *info;
	struct sh_mobile_hdmi_info *pdata = hdmi->dev->platform_data;
	struct sh_mobile_lcdc_chan *ch;
	int ret;
@@ -1123,8 +1124,9 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)

	mutex_lock(&hdmi->mutex);

	info = hdmi->info;

	if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
		struct fb_info *info = hdmi->info;
		unsigned long parent_rate = 0, hdmi_rate;

		ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
@@ -1148,6 +1150,7 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)

		ch = info->par;

		if (lock_fb_info(info)) {
			console_lock();

			/* HDMI plug in */
@@ -1157,33 +1160,35 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
				 * First activation with the default monitor - just turn
				 * on, if we run a resume here, the logo disappears
				 */
			if (lock_fb_info(info)) {
				info->var.width = hdmi->var.width;
				info->var.height = hdmi->var.height;
				sh_hdmi_display_on(hdmi, info);
				unlock_fb_info(info);
			}
			} else {
				/* New monitor or have to wake up */
				fb_set_suspend(info, 0);
			}

			console_unlock();
			unlock_fb_info(info);
		}
	} else {
		ret = 0;
		if (!hdmi->info)
		if (!info)
			goto out;

		hdmi->monspec.modedb_len = 0;
		fb_destroy_modedb(hdmi->monspec.modedb);
		hdmi->monspec.modedb = NULL;

		if (lock_fb_info(info)) {
			console_lock();

			/* HDMI disconnect */
		fb_set_suspend(hdmi->info, 1);
			fb_set_suspend(info, 1);

			console_unlock();
			unlock_fb_info(info);
		}
	}

out: