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

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
...@@ -1111,6 +1111,7 @@ static long sh_hdmi_clk_configure(struct sh_hdmi *hdmi, unsigned long hdmi_rate, ...@@ -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) 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 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_hdmi_info *pdata = hdmi->dev->platform_data;
struct sh_mobile_lcdc_chan *ch; struct sh_mobile_lcdc_chan *ch;
int ret; int ret;
...@@ -1123,8 +1124,9 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) ...@@ -1123,8 +1124,9 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
mutex_lock(&hdmi->mutex); mutex_lock(&hdmi->mutex);
info = hdmi->info;
if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) { if (hdmi->hp_state == HDMI_HOTPLUG_CONNECTED) {
struct fb_info *info = hdmi->info;
unsigned long parent_rate = 0, hdmi_rate; unsigned long parent_rate = 0, hdmi_rate;
ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate); ret = sh_hdmi_read_edid(hdmi, &hdmi_rate, &parent_rate);
...@@ -1148,42 +1150,45 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work) ...@@ -1148,42 +1150,45 @@ static void sh_hdmi_edid_work_fn(struct work_struct *work)
ch = info->par; ch = info->par;
console_lock(); if (lock_fb_info(info)) {
console_lock();
/* HDMI plug in */ /* HDMI plug in */
if (!sh_hdmi_must_reconfigure(hdmi) && if (!sh_hdmi_must_reconfigure(hdmi) &&
info->state == FBINFO_STATE_RUNNING) { info->state == FBINFO_STATE_RUNNING) {
/* /*
* First activation with the default monitor - just turn * First activation with the default monitor - just turn
* on, if we run a resume here, the logo disappears * on, if we run a resume here, the logo disappears
*/ */
if (lock_fb_info(info)) {
info->var.width = hdmi->var.width; info->var.width = hdmi->var.width;
info->var.height = hdmi->var.height; info->var.height = hdmi->var.height;
sh_hdmi_display_on(hdmi, info); sh_hdmi_display_on(hdmi, info);
unlock_fb_info(info); } else {
/* New monitor or have to wake up */
fb_set_suspend(info, 0);
} }
} else {
/* New monitor or have to wake up */
fb_set_suspend(info, 0);
}
console_unlock(); console_unlock();
unlock_fb_info(info);
}
} else { } else {
ret = 0; ret = 0;
if (!hdmi->info) if (!info)
goto out; goto out;
hdmi->monspec.modedb_len = 0; hdmi->monspec.modedb_len = 0;
fb_destroy_modedb(hdmi->monspec.modedb); fb_destroy_modedb(hdmi->monspec.modedb);
hdmi->monspec.modedb = NULL; hdmi->monspec.modedb = NULL;
console_lock(); if (lock_fb_info(info)) {
console_lock();
/* HDMI disconnect */ /* HDMI disconnect */
fb_set_suspend(hdmi->info, 1); fb_set_suspend(info, 1);
console_unlock(); console_unlock();
unlock_fb_info(info);
}
} }
out: out:
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment