summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHans de Goede <hdegoede@redhat.com>2013-01-01 02:13:23 +0400
committerAlejandro Mery <amery@geeks.cl>2013-01-03 23:58:04 +0400
commit6752c4ad1ba9b58a62e0dfff951fa65f419530fc (patch)
tree5d293ffc633f586f102313cedf07fc868da1c9af
parent6cb4e223601cca149ede580873da43299c168003 (diff)
downloadlinux-sunxi-6752c4ad1ba9b58a62e0dfff951fa65f419530fc.tar.xz
sunxi-hdmi: Fix NULL ptr deref when EDID info is received before fb is registered
With the latest changes hdmi_edid_received() calls lock_fb_info() now, but calling lock_fb_info() on a not yet registered fb causes a NULL ptr exception. This patch fixes this by tracking if the fb has been registered yet, and only locking it if has (otherwise there will be no users of it, so no locking will be necessary). This patch also adds locking around the registered state trackig + checking as hdmi_edid_received() gets called from the hdmi tasklet thread, so it may race with Fb_Init(). Signed-off-by: Hans de Goede <hdegoede@redhat.com>
-rw-r--r--drivers/video/sunxi/disp/dev_fb.c29
-rw-r--r--drivers/video/sunxi/disp/dev_fb.h1
2 files changed, 22 insertions, 8 deletions
diff --git a/drivers/video/sunxi/disp/dev_fb.c b/drivers/video/sunxi/disp/dev_fb.c
index 43d788ebfac1..5de789bc423a 100644
--- a/drivers/video/sunxi/disp/dev_fb.c
+++ b/drivers/video/sunxi/disp/dev_fb.c
@@ -33,6 +33,7 @@
#include "disp_lcd.h"
fb_info_t g_fbi;
+static DEFINE_MUTEX(g_fbi_mutex);
static int screen0_output_type = -1;
module_param(screen0_output_type, int, 0444);
@@ -1564,6 +1565,7 @@ void hdmi_edid_received(unsigned char *edid, int block)
struct fb_event event;
__u32 sel = 0;
+ mutex_lock(&g_fbi_mutex);
for (sel = 0; sel < 2; sel++) {
struct fb_info *fbi = g_fbi.fbinfo[sel];
int err = 0;
@@ -1571,10 +1573,12 @@ void hdmi_edid_received(unsigned char *edid, int block)
if (g_fbi.disp_init.output_type[sel] != DISP_OUTPUT_TYPE_HDMI)
continue;
- if (!lock_fb_info(fbi))
- continue;
+ if (g_fbi.fb_registered[sel]) {
+ if (!lock_fb_info(fbi))
+ continue;
- console_lock();
+ console_lock();
+ }
if (block == 0) {
if (fbi->monspecs.modedb != NULL) {
@@ -1592,8 +1596,10 @@ void hdmi_edid_received(unsigned char *edid, int block)
* Should not happen? Avoid panics and skip in this
* case.
*/
- console_unlock();
- unlock_fb_info(fbi);
+ if (g_fbi.fb_registered[sel]) {
+ console_unlock();
+ unlock_fb_info(fbi);
+ }
WARN_ON(fbi->monspecs.modedb_len == 0);
continue;
@@ -1616,11 +1622,14 @@ void hdmi_edid_received(unsigned char *edid, int block)
event.info = fbi;
err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
- console_unlock();
- unlock_fb_info(fbi);
+ if (g_fbi.fb_registered[sel]) {
+ console_unlock();
+ unlock_fb_info(fbi);
+ }
WARN_ON(err);
}
+ mutex_unlock(&g_fbi_mutex);
}
EXPORT_SYMBOL(hdmi_edid_received);
@@ -1825,9 +1834,13 @@ __s32 Fb_Init(__u32 from)
#endif
}
- for (i = 0; i < SUNXI_MAX_FB; i++)
+ mutex_lock(&g_fbi_mutex);
+ for (i = 0; i < SUNXI_MAX_FB; i++) {
/* Register framebuffers after they are initialized */
register_framebuffer(g_fbi.fbinfo[i]);
+ g_fbi.fb_registered[i] = true;
+ }
+ mutex_unlock(&g_fbi_mutex);
if (g_fbi.disp_init.scaler_mode[0])
BSP_disp_print_reg(0, DISP_REG_SCALER0);
diff --git a/drivers/video/sunxi/disp/dev_fb.h b/drivers/video/sunxi/disp/dev_fb.h
index 8cb8d1ffb730..937cafb68d09 100644
--- a/drivers/video/sunxi/disp/dev_fb.h
+++ b/drivers/video/sunxi/disp/dev_fb.h
@@ -44,6 +44,7 @@ typedef struct {
__disp_init_t disp_init;
__bool fb_enable[SUNXI_MAX_FB];
+ __bool fb_registered[SUNXI_MAX_FB];
__fb_mode_t fb_mode[SUNXI_MAX_FB];
/*
* [fb_id][0]: screen0 layer handle;