2019-05-20 09:39:56

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 00/33] fbcon notifier begone!

Hi all,

This patch series removes the fbcon notifier. It also contains the
beginnings of trying to understand how locking in this area works.

The super short summary of locking rules is that everything in fbcon needs
to be protected by the monolithic console_lock, including the setup code.
So not really an option to pull the kms modeset code out from underneath
that, at least not without rewriting half the console layer. Or I'm not
yet seeing clear enough.

The other side is that fbdev userspace access vs. fbcon locking is totally
broken.

For context of this series I'm just going to quote the commit message that
started this all:

commit 6104c37094e729f3d4ce65797002112735d49cd1
Author: Daniel Vetter <[email protected]>
Date: Tue Aug 1 17:32:07 2017 +0200

fbcon: Make fbcon a built-time depency for fbdev

There's a bunch of folks who're trying to make printk less
contended and faster, but there's a problem: printk uses the
console_lock, and the console lock has become the BKL for all things
fbdev/fbcon, which in turn pulled in half the drm subsystem under that
lock. That's awkward.

There reasons for that is probably just a historical accident:

- fbcon is a runtime option of fbdev, i.e. at runtime you can pick
whether your fbdev driver instances are used as kernel consoles.
Unfortunately this wasn't implemented with some module option, but
through some module loading magic: As long as you don't load
fbcon.ko, there's no fbdev console support, but loading it (in any
order wrt fbdev drivers) will create console instances for all fbdev
drivers.

- This was implemented through a notifier chain. fbcon.ko enumerates
all fbdev instances at load time and also registers itself as
listener in the fbdev notifier. The fbdev core tries to register new
fbdev instances with fbcon using the notifier.

- On top of that the modifier chain is also used at runtime by the
fbdev subsystem to e.g. control backlights for panels.

- The problem is that the notifier puts a mutex locking context
between fbdev and fbcon, which mixes up the locking contexts for
both the runtime usage and the register time usage to notify fbcon.
And at runtime fbcon (through the fbdev core) might call into the
notifier from a printk critical section while console_lock is held.

- This means console_lock must be an outer lock for the entire fbdev
subsystem, which also means it must be acquired when registering a
new framebuffer driver as the outermost lock since we might call
into fbcon (through the notifier) which would result in a locking
inversion if fbcon would acquire the console_lock from its notifier
callback (which it needs to register the console).

- console_lock can be held anywhere, since printk can be called
anywhere, and through the above story, plus drm/kms being an fbdev
driver, we pull in a shocking amount of locking hiercharchy
underneath the console_lock. Which makes cleaning up printk really
hard (not even splitting console_lock into an rwsem is all that
useful due to this).

There's various ways to address this, but the cleanest would be to
make fbcon a compile-time option, where fbdev directly calls the fbcon
register functions from register_framebuffer, or dummy static inline
versions if fbcon is disabled. Maybe augmented with a runtime knob to
disable fbcon, if that's needed (for debugging perhaps).

But this could break some users who rely on the magic "loading
fbcon.ko enables/disables fbdev framebuffers at runtime" thing, even
if that's unlikely. Hence we must be careful:

1. Create a compile-time dependency between fbcon and fbdev in the
least minimal way. This is what this patch does.

2. Wait at least 1 year to give possible users time to scream about
how we broke their setup. Unlikely, since all distros make fbcon
compile-in, and embedded platforms only compile stuff they know they
need anyway. But still.

3. Convert the notifier to direct functions calls, with dummy static
inlines if fbcon is disabled. We'll still need the fb notifier for the
other uses (like backlights), but we can probably move it into the fb
core (atm it must be built-into vmlinux).

4. Push console_lock down the call-chain, until it is down in
console_register again.

5. Finally start to clean up and rework the printk/console locking.

For context of this saga see

commit 50e244cc793d511b86adea24972f3a7264cae114
Author: Alan Cox <[email protected]>
Date: Fri Jan 25 10:28:15 2013 +1000

fb: rework locking to fix lock ordering on takeover

plus the pile of commits on top that tried to make this all work
without terminally upsetting lockdep. We've uncovered all this when
console_lock lockdep annotations where added in

commit daee779718a319ff9f83e1ba3339334ac650bb22
Author: Daniel Vetter <[email protected]>
Date: Sat Sep 22 19:52:11 2012 +0200

console: implement lockdep support for console_lock

On the patch itself:
- Switch CONFIG_FRAMEBUFFER_CONSOLE to be a boolean, using the overall
CONFIG_FB tristate to decided whether it should be a module or
built-in.

- At first I thought I could force the build depency with just a dummy
symbol that fbcon.ko exports and fb.ko uses. But that leads to a
module depency cycle (it works fine when built-in).

Since this tight binding is the entire goal the simplest solution is
to move all the fbcon modules (and there's a bunch of optinal
source-files which are each modules of their own, for no good
reason) into the overall fb.ko core module. That's a bit more than
what I would have liked to do in this patch, but oh well.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Alan Cox <[email protected]>
Cc: Sergey Senozhatsky <[email protected]>
Cc: Steven Rostedt <[email protected]>
Reviewed-by: Sean Paul <[email protected]>
Signed-off-by: Bartlomiej Zolnierkiewicz <[email protected]>

Comments, review and testing much appreciated, as always.

Wrt long-term plans: I'm not sure where this will lead just yet, or
whether it'll lead anywhere at all. But I think removing the notifier
indirection is definitely a step into the right direction.

Cheers, Daniel

Daniel Vetter (33):
dummycon: Sprinkle locking checks
fbdev: locking check for fb_set_suspend
vt: might_sleep() annotation for do_blank_screen
vt: More locking checks
fbdev/sa1100fb: Remove dead code
fbdev/cyber2000: Remove struct display
fbdev/aty128fb: Remove dead code
fbcon: s/struct display/struct fbcon_display/
fbcon: Remove fbcon_has_exited
fbcon: call fbcon_fb_(un)registered directly
fbdev/sh_mobile: remove sh_mobile_lcdc_display_notify
fbdev/omap: sysfs files can't disappear before the device is gone
fbdev: sysfs files can't disappear before the device is gone
staging/olpc: lock_fb_info can't fail
fbdev/atyfb: lock_fb_info can't fail
fbdev: lock_fb_info cannot fail
fbcon: call fbcon_fb_bind directly
fbdev: make unregister/unlink functions not fail
fbdev: unify unlink_framebufer paths
fbdev/sh_mob: Remove fb notifier callback
fbdev: directly call fbcon_suspended/resumed
fbcon: Call fbcon_mode_deleted/new_modelist directly
fbdev: Call fbcon_get_requirement directly
Revert "backlight/fbcon: Add FB_EVENT_CONBLANK"
fbcon: directly call fbcon_fb_blanked
fbmem: pull fbcon_fb_blanked out of fb_blank
fbdev: remove FBINFO_MISC_USEREVENT around fb_blank
fb: Flatten control flow in fb_set_var
fbcon: replace FB_EVENT_MODE_CHANGE/_ALL with direct calls
vgaswitcheroo: call fbcon_remap_all directly
fbcon: Call con2fb_map functions directly
fbcon: Document what I learned about fbcon locking
staging/olpc_dcon: Add drm conversion to TODO

drivers/gpu/vga/vga_switcheroo.c | 11 +-
drivers/staging/olpc_dcon/TODO | 7 +
drivers/staging/olpc_dcon/olpc_dcon.c | 6 +-
drivers/tty/vt/vt.c | 18 +
drivers/video/backlight/backlight.c | 2 +-
drivers/video/backlight/lcd.c | 2 -
drivers/video/console/dummycon.c | 6 +
drivers/video/fbdev/aty/aty128fb.c | 64 ---
drivers/video/fbdev/aty/atyfb_base.c | 3 +-
drivers/video/fbdev/core/fbcmap.c | 6 +-
drivers/video/fbdev/core/fbcon.c | 303 ++++++--------
drivers/video/fbdev/core/fbcon.h | 6 +-
drivers/video/fbdev/core/fbmem.c | 374 ++++++------------
drivers/video/fbdev/core/fbsysfs.c | 20 +-
drivers/video/fbdev/cyber2000fb.c | 1 -
.../video/fbdev/omap2/omapfb/omapfb-sysfs.c | 21 +-
drivers/video/fbdev/sa1100fb.c | 25 --
drivers/video/fbdev/sh_mobile_lcdcfb.c | 112 +-----
drivers/video/fbdev/sh_mobile_lcdcfb.h | 5 -
include/linux/console_struct.h | 5 +-
include/linux/fb.h | 40 +-
include/linux/fbcon.h | 30 ++
22 files changed, 342 insertions(+), 725 deletions(-)

--
2.20.1



2019-05-20 09:40:03

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 12/33] fbdev/omap: sysfs files can't disappear before the device is gone

Which means lock_fb_info can never fail. Remove the error handling.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
---
.../video/fbdev/omap2/omapfb/omapfb-sysfs.c | 21 +++++++------------
1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
index 8087a009c54f..bd0d20283372 100644
--- a/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
+++ b/drivers/video/fbdev/omap2/omapfb/omapfb-sysfs.c
@@ -60,8 +60,7 @@ static ssize_t store_rotate_type(struct device *dev,
if (rot_type != OMAP_DSS_ROT_DMA && rot_type != OMAP_DSS_ROT_VRFB)
return -EINVAL;

- if (!lock_fb_info(fbi))
- return -ENODEV;
+ lock_fb_info(fbi);

r = 0;
if (rot_type == ofbi->rotation_type)
@@ -112,8 +111,7 @@ static ssize_t store_mirror(struct device *dev,
if (r)
return r;

- if (!lock_fb_info(fbi))
- return -ENODEV;
+ lock_fb_info(fbi);

ofbi->mirror = mirror;

@@ -149,8 +147,7 @@ static ssize_t show_overlays(struct device *dev,
ssize_t l = 0;
int t;

- if (!lock_fb_info(fbi))
- return -ENODEV;
+ lock_fb_info(fbi);
omapfb_lock(fbdev);

for (t = 0; t < ofbi->num_overlays; t++) {
@@ -208,8 +205,7 @@ static ssize_t store_overlays(struct device *dev, struct device_attribute *attr,
if (buf[len - 1] == '\n')
len = len - 1;

- if (!lock_fb_info(fbi))
- return -ENODEV;
+ lock_fb_info(fbi);
omapfb_lock(fbdev);

if (len > 0) {
@@ -340,8 +336,7 @@ static ssize_t show_overlays_rotate(struct device *dev,
ssize_t l = 0;
int t;

- if (!lock_fb_info(fbi))
- return -ENODEV;
+ lock_fb_info(fbi);

for (t = 0; t < ofbi->num_overlays; t++) {
l += snprintf(buf + l, PAGE_SIZE - l, "%s%d",
@@ -369,8 +364,7 @@ static ssize_t store_overlays_rotate(struct device *dev,
if (buf[len - 1] == '\n')
len = len - 1;

- if (!lock_fb_info(fbi))
- return -ENODEV;
+ lock_fb_info(fbi);

if (len > 0) {
char *p = (char *)buf;
@@ -453,8 +447,7 @@ static ssize_t store_size(struct device *dev, struct device_attribute *attr,

size = PAGE_ALIGN(size);

- if (!lock_fb_info(fbi))
- return -ENODEV;
+ lock_fb_info(fbi);

if (display && display->driver->sync)
display->driver->sync(display);
--
2.20.1


2019-05-20 09:41:07

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 11/33] fbdev/sh_mobile: remove sh_mobile_lcdc_display_notify

It's dead code, and removing it avoids me having to understand
what it's doing with lock_fb_info.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
---
drivers/video/fbdev/sh_mobile_lcdcfb.c | 63 --------------------------
drivers/video/fbdev/sh_mobile_lcdcfb.h | 5 --
2 files changed, 68 deletions(-)

diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
index dc46be38c970..c5924f5e98c6 100644
--- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
+++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
@@ -556,67 +556,6 @@ sh_mobile_lcdc_must_reconfigure(struct sh_mobile_lcdc_chan *ch,
static int sh_mobile_lcdc_check_var(struct fb_var_screeninfo *var,
struct fb_info *info);

-static int sh_mobile_lcdc_display_notify(struct sh_mobile_lcdc_chan *ch,
- enum sh_mobile_lcdc_entity_event event,
- const struct fb_videomode *mode,
- const struct fb_monspecs *monspec)
-{
- struct fb_info *info = ch->info;
- struct fb_var_screeninfo var;
- int ret = 0;
-
- switch (event) {
- case SH_MOBILE_LCDC_EVENT_DISPLAY_CONNECT:
- /* HDMI plug in */
- console_lock();
- if (lock_fb_info(info)) {
-
-
- ch->display.width = monspec->max_x * 10;
- ch->display.height = monspec->max_y * 10;
-
- if (!sh_mobile_lcdc_must_reconfigure(ch, mode) &&
- info->state == FBINFO_STATE_RUNNING) {
- /* First activation with the default monitor.
- * Just turn on, if we run a resume here, the
- * logo disappears.
- */
- info->var.width = ch->display.width;
- info->var.height = ch->display.height;
- sh_mobile_lcdc_display_on(ch);
- } else {
- /* New monitor or have to wake up */
- fb_set_suspend(info, 0);
- }
-
-
- unlock_fb_info(info);
- }
- console_unlock();
- break;
-
- case SH_MOBILE_LCDC_EVENT_DISPLAY_DISCONNECT:
- /* HDMI disconnect */
- console_lock();
- if (lock_fb_info(info)) {
- fb_set_suspend(info, 1);
- unlock_fb_info(info);
- }
- console_unlock();
- break;
-
- case SH_MOBILE_LCDC_EVENT_DISPLAY_MODE:
- /* Validate a proposed new mode */
- fb_videomode_to_var(&var, mode);
- var.bits_per_pixel = info->var.bits_per_pixel;
- var.grayscale = info->var.grayscale;
- ret = sh_mobile_lcdc_check_var(&var, info);
- break;
- }
-
- return ret;
-}
-
/* -----------------------------------------------------------------------------
* Format helpers
*/
@@ -2540,8 +2479,6 @@ sh_mobile_lcdc_channel_init(struct sh_mobile_lcdc_chan *ch)
unsigned int max_size;
unsigned int i;

- ch->notify = sh_mobile_lcdc_display_notify;
-
/* Validate the format. */
format = sh_mobile_format_info(cfg->fourcc);
if (format == NULL) {
diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.h b/drivers/video/fbdev/sh_mobile_lcdcfb.h
index b8e47a8bd8ab..589400372098 100644
--- a/drivers/video/fbdev/sh_mobile_lcdcfb.h
+++ b/drivers/video/fbdev/sh_mobile_lcdcfb.h
@@ -87,11 +87,6 @@ struct sh_mobile_lcdc_chan {
unsigned long base_addr_c;
unsigned int line_size;

- int (*notify)(struct sh_mobile_lcdc_chan *ch,
- enum sh_mobile_lcdc_entity_event event,
- const struct fb_videomode *mode,
- const struct fb_monspecs *monspec);
-
/* Backlight */
struct backlight_device *bl;
unsigned int bl_brightness;
--
2.20.1


2019-05-20 09:42:26

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 20/33] fbdev/sh_mob: Remove fb notifier callback

This seems to be entirely defunct:

- The FB_EVEN_SUSPEND/RESUME events are only sent out by
fb_set_suspend. Which is supposed to be called by drivers in their
suspend/resume hooks, and not itself call into drivers. Luckily
sh_mob doesn't call fb_set_suspend, so this seems to do nothing
useful.

- The notify hook calls sh_mobile_fb_reconfig() which in turn can
call into the fb notifier. Or attempt too, since that would
deadlock.

So looks like leftover hacks from when this was originally introduced
in

commit 6011bdeaa6089d49c02de69f05980da7bad314ab
Author: Guennadi Liakhovetski <[email protected]>
Date: Wed Jul 21 10:13:21 2010 +0000

fbdev: sh-mobile: HDMI support for SH-Mobile SoCs

So let's just remove it.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Bartlomiej Zolnierkiewicz <[email protected]>
Cc: Markus Elfring <[email protected]>
Cc: Geert Uytterhoeven <[email protected]>
Cc: Wolfram Sang <[email protected]>
---
drivers/video/fbdev/sh_mobile_lcdcfb.c | 38 --------------------------
1 file changed, 38 deletions(-)

diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
index c5924f5e98c6..0d7a044852d7 100644
--- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
+++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
@@ -213,7 +213,6 @@ struct sh_mobile_lcdc_priv {
struct sh_mobile_lcdc_chan ch[2];
struct sh_mobile_lcdc_overlay overlays[4];

- struct notifier_block notifier;
int started;
int forced_fourcc; /* 2 channel LCDC must share fourcc setting */
};
@@ -2258,37 +2257,6 @@ static const struct dev_pm_ops sh_mobile_lcdc_dev_pm_ops = {
* Framebuffer notifier
*/

-/* locking: called with info->lock held */
-static int sh_mobile_lcdc_notify(struct notifier_block *nb,
- unsigned long action, void *data)
-{
- struct fb_event *event = data;
- struct fb_info *info = event->info;
- struct sh_mobile_lcdc_chan *ch = info->par;
-
- if (&ch->lcdc->notifier != nb)
- return NOTIFY_DONE;
-
- dev_dbg(info->dev, "%s(): action = %lu, data = %p\n",
- __func__, action, event->data);
-
- switch(action) {
- case FB_EVENT_SUSPEND:
- sh_mobile_lcdc_display_off(ch);
- sh_mobile_lcdc_stop(ch->lcdc);
- break;
- case FB_EVENT_RESUME:
- mutex_lock(&ch->open_lock);
- sh_mobile_fb_reconfig(info);
- mutex_unlock(&ch->open_lock);
-
- sh_mobile_lcdc_display_on(ch);
- sh_mobile_lcdc_start(ch->lcdc);
- }
-
- return NOTIFY_OK;
-}
-
/* -----------------------------------------------------------------------------
* Probe/remove and driver init/exit
*/
@@ -2316,8 +2284,6 @@ static int sh_mobile_lcdc_remove(struct platform_device *pdev)
struct sh_mobile_lcdc_priv *priv = platform_get_drvdata(pdev);
unsigned int i;

- fb_unregister_client(&priv->notifier);
-
for (i = 0; i < ARRAY_SIZE(priv->overlays); i++)
sh_mobile_lcdc_overlay_fb_unregister(&priv->overlays[i]);
for (i = 0; i < ARRAY_SIZE(priv->ch); i++)
@@ -2707,10 +2673,6 @@ static int sh_mobile_lcdc_probe(struct platform_device *pdev)
goto err1;
}

- /* Failure ignored */
- priv->notifier.notifier_call = sh_mobile_lcdc_notify;
- fb_register_client(&priv->notifier);
-
return 0;
err1:
sh_mobile_lcdc_remove(pdev);
--
2.20.1


2019-05-20 09:42:25

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 24/33] Revert "backlight/fbcon: Add FB_EVENT_CONBLANK"

This reverts commit 994efacdf9a087b52f71e620b58dfa526b0cf928.

The justification is that if hw blanking fails (i.e. fbops->fb_blank)
fails, then we still want to shut down the backlight. Which is exactly
_not_ what fb_blank() does and so rather inconsistent if we end up
with different behaviour between fbcon and direct fbdev usage. Given
that the entire notifier maze is getting in the way anyway I figured
it's simplest to revert this not well justified commit.

Cc: Richard Purdie <[email protected]>
Signed-off-by: Daniel Vetter <[email protected]>
Cc: Lee Jones <[email protected]>
Cc: Daniel Thompson <[email protected]>
Cc: Jingoo Han <[email protected]>
Cc: Bartlomiej Zolnierkiewicz <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Hans de Goede <[email protected]>
Cc: Yisheng Xie <[email protected]>
Cc: [email protected]
---
drivers/video/backlight/backlight.c | 2 +-
drivers/video/fbdev/core/fbcon.c | 9 ---------
include/linux/fb.h | 4 +---
3 files changed, 2 insertions(+), 13 deletions(-)

diff --git a/drivers/video/backlight/backlight.c b/drivers/video/backlight/backlight.c
index deb824bef6e2..c55590ec0057 100644
--- a/drivers/video/backlight/backlight.c
+++ b/drivers/video/backlight/backlight.c
@@ -46,7 +46,7 @@ static int fb_notifier_callback(struct notifier_block *self,
int fb_blank = 0;

/* If we aren't interested in this event, skip it immediately ... */
- if (event != FB_EVENT_BLANK && event != FB_EVENT_CONBLANK)
+ if (event != FB_EVENT_BLANK)
return 0;

bd = container_of(self, struct backlight_device, fb_notif);
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 58b876718d81..1549056a848e 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2346,8 +2346,6 @@ static int fbcon_switch(struct vc_data *vc)
static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
int blank)
{
- struct fb_event event;
-
if (blank) {
unsigned short charmask = vc->vc_hi_font_mask ?
0x1ff : 0xff;
@@ -2358,13 +2356,6 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,
fbcon_clear(vc, 0, 0, vc->vc_rows, vc->vc_cols);
vc->vc_video_erase_char = oldc;
}
-
-
- lock_fb_info(info);
- event.info = info;
- event.data = &blank;
- fb_notifier_call_chain(FB_EVENT_CONBLANK, &event);
- unlock_fb_info(info);
}

static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
diff --git a/include/linux/fb.h b/include/linux/fb.h
index e76185244593..4b9b882f8f52 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -130,12 +130,10 @@ struct fb_cursor_user {
#define FB_EVENT_GET_CONSOLE_MAP 0x07
/* CONSOLE-SPECIFIC: set console to framebuffer mapping */
#define FB_EVENT_SET_CONSOLE_MAP 0x08
-/* A hardware display blank change occurred */
+/* A display blank is requested */
#define FB_EVENT_BLANK 0x09
/* Private modelist is to be replaced */
#define FB_EVENT_MODE_CHANGE_ALL 0x0B
-/* A software display blank change occurred */
-#define FB_EVENT_CONBLANK 0x0C
/* CONSOLE-SPECIFIC: remap all consoles to new fb - for vga_switcheroo */
#define FB_EVENT_REMAP_ALL_CONSOLE 0x0F
/* A hardware display blank early change occurred */
--
2.20.1


2019-05-20 09:42:25

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 29/33] fbcon: replace FB_EVENT_MODE_CHANGE/_ALL with direct calls

Create a new wrapper function for this, feels like there's some
refactoring room here between the two modes.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Lee Jones <[email protected]>
Cc: Daniel Thompson <[email protected]>
Cc: Jingoo Han <[email protected]>
Cc: Bartlomiej Zolnierkiewicz <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Hans de Goede <[email protected]>
Cc: Yisheng Xie <[email protected]>
Cc: "Michał Mirosław" <[email protected]>
Cc: Peter Rosin <[email protected]>
Cc: Mikulas Patocka <[email protected]>
Cc: [email protected]
---
drivers/video/backlight/lcd.c | 2 --
drivers/video/fbdev/core/fbcon.c | 15 +++++++++------
drivers/video/fbdev/core/fbmem.c | 13 ++-----------
drivers/video/fbdev/sh_mobile_lcdcfb.c | 11 +----------
include/linux/fb.h | 4 ----
include/linux/fbcon.h | 2 ++
6 files changed, 14 insertions(+), 33 deletions(-)

diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
index 4b40c6a4d441..16298041b141 100644
--- a/drivers/video/backlight/lcd.c
+++ b/drivers/video/backlight/lcd.c
@@ -32,8 +32,6 @@ static int fb_notifier_callback(struct notifier_block *self,
/* If we aren't interested in this event, skip it immediately ... */
switch (event) {
case FB_EVENT_BLANK:
- case FB_EVENT_MODE_CHANGE:
- case FB_EVENT_MODE_CHANGE_ALL:
case FB_EARLY_EVENT_BLANK:
case FB_R_EARLY_EVENT_BLANK:
break;
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index c1a7476e980f..8cc62d340387 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -3005,6 +3005,15 @@ static void fbcon_set_all_vcs(struct fb_info *info)
fbcon_modechanged(info);
}

+
+void fbcon_update_vcs(struct fb_info *info, bool all)
+{
+ if (all)
+ fbcon_set_all_vcs(info);
+ else
+ fbcon_modechanged(info);
+}
+
int fbcon_mode_deleted(struct fb_info *info,
struct fb_videomode *mode)
{
@@ -3314,12 +3323,6 @@ static int fbcon_event_notify(struct notifier_block *self,
int idx, ret = 0;

switch(action) {
- case FB_EVENT_MODE_CHANGE:
- fbcon_modechanged(info);
- break;
- case FB_EVENT_MODE_CHANGE_ALL:
- fbcon_set_all_vcs(info);
- break;
case FB_EVENT_SET_CONSOLE_MAP:
/* called with console lock held */
con2fb = event->data;
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index cbd58ba8a59d..55b88163edc2 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1039,17 +1039,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
!list_empty(&info->modelist))
ret = fb_add_videomode(&mode, &info->modelist);

- if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
- struct fb_event event;
- int evnt = (activate & FB_ACTIVATE_ALL) ?
- FB_EVENT_MODE_CHANGE_ALL :
- FB_EVENT_MODE_CHANGE;
-
- info->flags &= ~FBINFO_MISC_USEREVENT;
- event.info = info;
- event.data = &mode;
- fb_notifier_call_chain(evnt, &event);
- }
+ if (!ret && (flags & FBINFO_MISC_USEREVENT))
+ fbcon_update_vcs(info, activate & FB_ACTIVATE_ALL);

return ret;
}
diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
index 0d7a044852d7..bb1a610d0363 100644
--- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
+++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
@@ -1776,8 +1776,6 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
struct sh_mobile_lcdc_chan *ch = info->par;
struct fb_var_screeninfo var;
struct fb_videomode mode;
- struct fb_event event;
- int evnt = FB_EVENT_MODE_CHANGE_ALL;

if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
/* More framebuffer users are active */
@@ -1799,14 +1797,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
/* Couldn't reconfigure, hopefully, can continue as before */
return;

- /*
- * fb_set_var() calls the notifier change internally, only if
- * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
- * user event, we have to call the chain ourselves.
- */
- event.info = info;
- event.data = &ch->display.mode;
- fb_notifier_call_chain(evnt, &event);
+ fbcon_update_vcs(info, true);
}

/*
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 4b9b882f8f52..54d6bee09121 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -124,16 +124,12 @@ struct fb_cursor_user {
* Register/unregister for framebuffer events
*/

-/* The resolution of the passed in fb_info about to change */
-#define FB_EVENT_MODE_CHANGE 0x01
/* CONSOLE-SPECIFIC: get console to framebuffer mapping */
#define FB_EVENT_GET_CONSOLE_MAP 0x07
/* CONSOLE-SPECIFIC: set console to framebuffer mapping */
#define FB_EVENT_SET_CONSOLE_MAP 0x08
/* A display blank is requested */
#define FB_EVENT_BLANK 0x09
-/* Private modelist is to be replaced */
-#define FB_EVENT_MODE_CHANGE_ALL 0x0B
/* CONSOLE-SPECIFIC: remap all consoles to new fb - for vga_switcheroo */
#define FB_EVENT_REMAP_ALL_CONSOLE 0x0F
/* A hardware display blank early change occurred */
diff --git a/include/linux/fbcon.h b/include/linux/fbcon.h
index 90e196c835dd..daaa97b0c9e6 100644
--- a/include/linux/fbcon.h
+++ b/include/linux/fbcon.h
@@ -15,6 +15,7 @@ void fbcon_new_modelist(struct fb_info *info);
void fbcon_get_requirement(struct fb_info *info,
struct fb_blit_caps *caps);
void fbcon_fb_blanked(struct fb_info *info, int blank);
+void fbcon_update_vcs(struct fb_info *info, bool all);
#else
static inline void fb_console_init(void) {}
static inline void fb_console_exit(void) {}
@@ -29,6 +30,7 @@ void fbcon_new_modelist(struct fb_info *info) {}
void fbcon_get_requirement(struct fb_info *info,
struct fb_blit_caps *caps) {}
void fbcon_fb_blanked(struct fb_info *info, int blank) {}
+void fbcon_update_vcs(struct fb_info *info, bool all) {}
#endif

#endif /* _LINUX_FBCON_H */
--
2.20.1


2019-05-20 09:42:32

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 32/33] fbcon: Document what I learned about fbcon locking

It's not pretty.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Bartlomiej Zolnierkiewicz <[email protected]>
Cc: Hans de Goede <[email protected]>
Cc: Yisheng Xie <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 19 +++++++++++++++++++
1 file changed, 19 insertions(+)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index b40b56702c61..cbbcf7a795f2 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -87,6 +87,25 @@
# define DPRINTK(fmt, args...)
#endif

+/*
+ * FIXME: Locking
+ *
+ * - fbcon state itself is protected by the console_lock, and the code does a
+ * pretty good job at making sure that lock is held everywhere it's needed.
+ *
+ * - access to the registered_fb array is entirely unprotected. This should use
+ * proper object lifetime handling, i.e. get/put_fb_info. This also means
+ * switching from indices to proper pointers for fb_info everywhere.
+ *
+ * - fbcon doesn't bother with fb_lock/unlock at all. This is buggy, since it
+ * means concurrent access to the same fbdev from both fbcon and userspace
+ * will blow up. To fix this all fbcon calls from fbmem.c need to be moved out
+ * of fb_lock/unlock protected sections, since otherwise we'll recurse and
+ * deadlock eventually. Aside: Due to these deadlock issues the fbdev code in
+ * fbmem.c cannot use locking asserts, and there's lots of callers which get
+ * the rules wrong, e.g. fbsysfs.c entirely missed fb_lock/unlock calls too.
+ */
+
enum {
FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */
FBCON_LOGO_DRAW = -2, /* draw the logo to a console */
--
2.20.1


2019-05-20 09:42:33

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 28/33] fb: Flatten control flow in fb_set_var

Instead of wiring almost everything down to the very last line using
goto soup (but not consistently, where would the fun be otherwise)
drop out early when checks fail. This allows us to flatten the huge
indent levels to just 1.

Aside: If a driver doesn't set ->fb_check_var, then FB_ACTIVATE_NOW
does nothing. This bug exists ever since this code was extracted as a
common helper in 2002, hence I decided against fixing it. Everyone
just better have a fb_check_var to make sure things work correctly.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Bartlomiej Zolnierkiewicz <[email protected]>
Cc: "Michał Mirosław" <[email protected]>
Cc: Peter Rosin <[email protected]>
Cc: Hans de Goede <[email protected]>
Cc: Mikulas Patocka <[email protected]>
---
drivers/video/fbdev/core/fbmem.c | 126 +++++++++++++++----------------
1 file changed, 63 insertions(+), 63 deletions(-)

diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 65a075ccac4a..cbd58ba8a59d 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -954,6 +954,9 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
{
int flags = info->flags;
int ret = 0;
+ u32 activate;
+ struct fb_var_screeninfo old_var;
+ struct fb_videomode mode;

if (var->activate & FB_ACTIVATE_INV_MODE) {
struct fb_videomode mode1, mode2;
@@ -970,87 +973,84 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
fb_delete_videomode(&mode1, &info->modelist);


- ret = (ret) ? -EINVAL : 0;
- goto done;
+ return ret ? -EINVAL : 0;
}

- if ((var->activate & FB_ACTIVATE_FORCE) ||
- memcmp(&info->var, var, sizeof(struct fb_var_screeninfo))) {
- u32 activate = var->activate;
+ if (!(var->activate & FB_ACTIVATE_FORCE) &&
+ !memcmp(&info->var, var, sizeof(struct fb_var_screeninfo)))
+ return 0;

- /* When using FOURCC mode, make sure the red, green, blue and
- * transp fields are set to 0.
- */
- if ((info->fix.capabilities & FB_CAP_FOURCC) &&
- var->grayscale > 1) {
- if (var->red.offset || var->green.offset ||
- var->blue.offset || var->transp.offset ||
- var->red.length || var->green.length ||
- var->blue.length || var->transp.length ||
- var->red.msb_right || var->green.msb_right ||
- var->blue.msb_right || var->transp.msb_right)
- return -EINVAL;
- }
+ activate = var->activate;

- if (!info->fbops->fb_check_var) {
- *var = info->var;
- goto done;
- }
+ /* When using FOURCC mode, make sure the red, green, blue and
+ * transp fields are set to 0.
+ */
+ if ((info->fix.capabilities & FB_CAP_FOURCC) &&
+ var->grayscale > 1) {
+ if (var->red.offset || var->green.offset ||
+ var->blue.offset || var->transp.offset ||
+ var->red.length || var->green.length ||
+ var->blue.length || var->transp.length ||
+ var->red.msb_right || var->green.msb_right ||
+ var->blue.msb_right || var->transp.msb_right)
+ return -EINVAL;
+ }
+
+ if (!info->fbops->fb_check_var) {
+ *var = info->var;
+ return 0;
+ }

- ret = info->fbops->fb_check_var(var, info);
+ ret = info->fbops->fb_check_var(var, info);

- if (ret)
- goto done;
+ if (ret)
+ return ret;

- if ((var->activate & FB_ACTIVATE_MASK) == FB_ACTIVATE_NOW) {
- struct fb_var_screeninfo old_var;
- struct fb_videomode mode;
+ if ((var->activate & FB_ACTIVATE_MASK) != FB_ACTIVATE_NOW)
+ return 0;

- if (info->fbops->fb_get_caps) {
- ret = fb_check_caps(info, var, activate);
+ if (info->fbops->fb_get_caps) {
+ ret = fb_check_caps(info, var, activate);

- if (ret)
- goto done;
- }
+ if (ret)
+ return ret;
+ }

- old_var = info->var;
- info->var = *var;
+ old_var = info->var;
+ info->var = *var;

- if (info->fbops->fb_set_par) {
- ret = info->fbops->fb_set_par(info);
+ if (info->fbops->fb_set_par) {
+ ret = info->fbops->fb_set_par(info);

- if (ret) {
- info->var = old_var;
- printk(KERN_WARNING "detected "
- "fb_set_par error, "
- "error code: %d\n", ret);
- goto done;
- }
- }
+ if (ret) {
+ info->var = old_var;
+ printk(KERN_WARNING "detected "
+ "fb_set_par error, "
+ "error code: %d\n", ret);
+ return ret;
+ }
+ }

- fb_pan_display(info, &info->var);
- fb_set_cmap(&info->cmap, info);
- fb_var_to_videomode(&mode, &info->var);
+ fb_pan_display(info, &info->var);
+ fb_set_cmap(&info->cmap, info);
+ fb_var_to_videomode(&mode, &info->var);

- if (info->modelist.prev && info->modelist.next &&
- !list_empty(&info->modelist))
- ret = fb_add_videomode(&mode, &info->modelist);
+ if (info->modelist.prev && info->modelist.next &&
+ !list_empty(&info->modelist))
+ ret = fb_add_videomode(&mode, &info->modelist);

- if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
- struct fb_event event;
- int evnt = (activate & FB_ACTIVATE_ALL) ?
- FB_EVENT_MODE_CHANGE_ALL :
- FB_EVENT_MODE_CHANGE;
+ if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
+ struct fb_event event;
+ int evnt = (activate & FB_ACTIVATE_ALL) ?
+ FB_EVENT_MODE_CHANGE_ALL :
+ FB_EVENT_MODE_CHANGE;

- info->flags &= ~FBINFO_MISC_USEREVENT;
- event.info = info;
- event.data = &mode;
- fb_notifier_call_chain(evnt, &event);
- }
- }
+ info->flags &= ~FBINFO_MISC_USEREVENT;
+ event.info = info;
+ event.data = &mode;
+ fb_notifier_call_chain(evnt, &event);
}

- done:
return ret;
}
EXPORT_SYMBOL(fb_set_var);
--
2.20.1


2019-05-20 09:42:35

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 17/33] fbcon: call fbcon_fb_bind directly

Also remove the error return value. That's all errors for either
driver bugs (trying to unbind something that isn't bound), or errors
of the new driver that will take over.

There's nothing the outgoing driver can do about this anyway, so
switch over to void.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Bartlomiej Zolnierkiewicz <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Hans de Goede <[email protected]>
Cc: Sergey Senozhatsky <[email protected]>
Cc: Peter Rosin <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Konstantin Khorenko <[email protected]>
Cc: Yisheng Xie <[email protected]>
Cc: "Michał Mirosław" <[email protected]>
Cc: Mikulas Patocka <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: [email protected]
---
drivers/video/fbdev/core/fbcon.c | 24 +++++++-----------------
drivers/video/fbdev/core/fbmem.c | 7 ++-----
include/linux/fb.h | 2 --
include/linux/fbcon.h | 2 ++
4 files changed, 11 insertions(+), 24 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 35443add7f7e..a8d12914b559 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -3042,7 +3042,7 @@ static int fbcon_mode_deleted(struct fb_info *info,
}

#ifdef CONFIG_VT_HW_CONSOLE_BINDING
-static int fbcon_unbind(void)
+static void fbcon_unbind(void)
{
int ret;

@@ -3051,25 +3051,21 @@ static int fbcon_unbind(void)

if (!ret)
fbcon_has_console_bind = 0;
-
- return ret;
}
#else
-static inline int fbcon_unbind(void)
-{
- return -EINVAL;
-}
+static inline void fbcon_unbind(void) {}
#endif /* CONFIG_VT_HW_CONSOLE_BINDING */

/* called with console_lock held */
-static int fbcon_fb_unbind(int idx)
+void fbcon_fb_unbind(struct fb_info *info)
{
int i, new_idx = -1, ret = 0;
+ int idx = info->node;

WARN_CONSOLE_UNLOCKED();

if (!fbcon_has_console_bind)
- return 0;
+ return;

for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map[i] != idx &&
@@ -3102,15 +3098,13 @@ static int fbcon_fb_unbind(int idx)
idx, 0);
if (ret) {
con2fb_map[i] = idx;
- return ret;
+ return;
}
}
}
}
- ret = fbcon_unbind();
+ fbcon_unbind();
}
-
- return ret;
}

/* called with console_lock held */
@@ -3348,10 +3342,6 @@ static int fbcon_event_notify(struct notifier_block *self,
mode = event->data;
ret = fbcon_mode_deleted(info, mode);
break;
- case FB_EVENT_FB_UNBIND:
- idx = info->node;
- ret = fbcon_fb_unbind(idx);
- break;
case FB_EVENT_SET_CONSOLE_MAP:
/* called with console lock held */
con2fb = event->data;
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 1987aba4f5a2..156523cc48bf 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1708,8 +1708,6 @@ static int do_register_framebuffer(struct fb_info *fb_info)

static int unbind_console(struct fb_info *fb_info)
{
- struct fb_event event;
- int ret;
int i = fb_info->node;

if (i < 0 || i >= FB_MAX || registered_fb[i] != fb_info)
@@ -1717,12 +1715,11 @@ static int unbind_console(struct fb_info *fb_info)

console_lock();
lock_fb_info(fb_info);
- event.info = fb_info;
- ret = fb_notifier_call_chain(FB_EVENT_FB_UNBIND, &event);
+ fbcon_fb_unbind(fb_info);
unlock_fb_info(fb_info);
console_unlock();

- return ret;
+ return 0;
}

static int __unlink_framebuffer(struct fb_info *fb_info);
diff --git a/include/linux/fb.h b/include/linux/fb.h
index fd60207c0685..38fae1678939 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -151,8 +151,6 @@ struct fb_cursor_user {
#define FB_EVENT_CONBLANK 0x0C
/* Get drawing requirements */
#define FB_EVENT_GET_REQ 0x0D
-/* Unbind from the console if possible */
-#define FB_EVENT_FB_UNBIND 0x0E
/* CONSOLE-SPECIFIC: remap all consoles to new fb - for vga_switcheroo */
#define FB_EVENT_REMAP_ALL_CONSOLE 0x0F
/* A hardware display blank early change occurred */
diff --git a/include/linux/fbcon.h b/include/linux/fbcon.h
index 94a71e9e1257..38d44fdb6d14 100644
--- a/include/linux/fbcon.h
+++ b/include/linux/fbcon.h
@@ -6,11 +6,13 @@ void __init fb_console_init(void);
void __exit fb_console_exit(void);
int fbcon_fb_registered(struct fb_info *info);
void fbcon_fb_unregistered(struct fb_info *info);
+void fbcon_fb_unbind(struct fb_info *info);
#else
static inline void fb_console_init(void) {}
static inline void fb_console_exit(void) {}
static inline int fbcon_fb_registered(struct fb_info *info) { return 0; }
static inline void fbcon_fb_unregistered(struct fb_info *info) {}
+static inline void fbcon_fb_unbind(struct fb_info *info) {}
#endif

#endif /* _LINUX_FBCON_H */
--
2.20.1


2019-05-20 09:42:46

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 22/33] fbcon: Call fbcon_mode_deleted/new_modelist directly

I'm not entirely clear on what new_modelist actually does, it seems
exclusively for a sysfs interface. Which in the end does amount to a
normal fb_set_par to check the mode, but then takes a different path
in both fbmem.c and fbcon.c.

I have no idea why these 2 paths are different, but then I also don't
really want to find out. So just do the simple conversion to a direct
function call.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Bartlomiej Zolnierkiewicz <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Hans de Goede <[email protected]>
Cc: Mikulas Patocka <[email protected]>
Cc: Sergey Senozhatsky <[email protected]>
Cc: Kees Cook <[email protected]>
Cc: Peter Rosin <[email protected]>
Cc: Yisheng Xie <[email protected]>
Cc: "Michał Mirosław" <[email protected]>
Cc: [email protected]
---
drivers/video/fbdev/core/fbcon.c | 14 +++-----------
drivers/video/fbdev/core/fbmem.c | 22 +++++++---------------
include/linux/fb.h | 5 -----
include/linux/fbcon.h | 6 ++++++
4 files changed, 16 insertions(+), 31 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index b056d1190788..5635acb4b11c 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -3015,8 +3015,8 @@ static void fbcon_set_all_vcs(struct fb_info *info)
fbcon_modechanged(info);
}

-static int fbcon_mode_deleted(struct fb_info *info,
- struct fb_videomode *mode)
+int fbcon_mode_deleted(struct fb_info *info,
+ struct fb_videomode *mode)
{
struct fb_info *fb_info;
struct fbcon_display *p;
@@ -3258,7 +3258,7 @@ static void fbcon_fb_blanked(struct fb_info *info, int blank)
ops->blank_state = blank;
}

-static void fbcon_new_modelist(struct fb_info *info)
+void fbcon_new_modelist(struct fb_info *info)
{
int i;
struct vc_data *vc;
@@ -3320,7 +3320,6 @@ static int fbcon_event_notify(struct notifier_block *self,
{
struct fb_event *event = data;
struct fb_info *info = event->info;
- struct fb_videomode *mode;
struct fb_con2fbmap *con2fb;
struct fb_blit_caps *caps;
int idx, ret = 0;
@@ -3332,10 +3331,6 @@ static int fbcon_event_notify(struct notifier_block *self,
case FB_EVENT_MODE_CHANGE_ALL:
fbcon_set_all_vcs(info);
break;
- case FB_EVENT_MODE_DELETE:
- mode = event->data;
- ret = fbcon_mode_deleted(info, mode);
- break;
case FB_EVENT_SET_CONSOLE_MAP:
/* called with console lock held */
con2fb = event->data;
@@ -3349,9 +3344,6 @@ static int fbcon_event_notify(struct notifier_block *self,
case FB_EVENT_BLANK:
fbcon_fb_blanked(info, *(int *)event->data);
break;
- case FB_EVENT_NEW_MODELIST:
- fbcon_new_modelist(info);
- break;
case FB_EVENT_GET_REQ:
caps = event->data;
fbcon_get_requirement(info, caps);
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 7c55846ee5fc..96d280228746 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -966,16 +966,11 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
/* make sure we don't delete the videomode of current var */
ret = fb_mode_is_equal(&mode1, &mode2);

- if (!ret) {
- struct fb_event event;
-
- event.info = info;
- event.data = &mode1;
- ret = fb_notifier_call_chain(FB_EVENT_MODE_DELETE, &event);
- }
+ if (!ret)
+ fbcon_mode_deleted(info, &mode1);

if (!ret)
- fb_delete_videomode(&mode1, &info->modelist);
+ fb_delete_videomode(&mode1, &info->modelist);


ret = (ret) ? -EINVAL : 0;
@@ -1956,7 +1951,6 @@ subsys_initcall(fbmem_init);

int fb_new_modelist(struct fb_info *info)
{
- struct fb_event event;
struct fb_var_screeninfo var = info->var;
struct list_head *pos, *n;
struct fb_modelist *modelist;
@@ -1976,14 +1970,12 @@ int fb_new_modelist(struct fb_info *info)
}
}

- err = 1;
+ if (list_empty(&info->modelist))
+ return 1;

- if (!list_empty(&info->modelist)) {
- event.info = info;
- err = fb_notifier_call_chain(FB_EVENT_NEW_MODELIST, &event);
- }
+ fbcon_new_modelist(info);

- return err;
+ return 0;
}

MODULE_LICENSE("GPL");
diff --git a/include/linux/fb.h b/include/linux/fb.h
index a78bbd372cfd..e6595a381792 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -126,8 +126,6 @@ struct fb_cursor_user {

/* The resolution of the passed in fb_info about to change */
#define FB_EVENT_MODE_CHANGE 0x01
-/* An entry from the modelist was removed */
-#define FB_EVENT_MODE_DELETE 0x04
/* CONSOLE-SPECIFIC: get console to framebuffer mapping */
#define FB_EVENT_GET_CONSOLE_MAP 0x07
/* CONSOLE-SPECIFIC: set console to framebuffer mapping */
@@ -135,9 +133,6 @@ struct fb_cursor_user {
/* A hardware display blank change occurred */
#define FB_EVENT_BLANK 0x09
/* Private modelist is to be replaced */
-#define FB_EVENT_NEW_MODELIST 0x0A
-/* The resolution of the passed in fb_info about to change and
- all vc's should be changed */
#define FB_EVENT_MODE_CHANGE_ALL 0x0B
/* A software display blank change occurred */
#define FB_EVENT_CONBLANK 0x0C
diff --git a/include/linux/fbcon.h b/include/linux/fbcon.h
index 61a22e6c0c64..42b06848b459 100644
--- a/include/linux/fbcon.h
+++ b/include/linux/fbcon.h
@@ -9,6 +9,9 @@ void fbcon_fb_unregistered(struct fb_info *info);
void fbcon_fb_unbind(struct fb_info *info);
void fbcon_suspended(struct fb_info *info);
void fbcon_resumed(struct fb_info *info);
+int fbcon_mode_deleted(struct fb_info *info,
+ struct fb_videomode *mode);
+void fbcon_new_modelist(struct fb_info *info);
#else
static inline void fb_console_init(void) {}
static inline void fb_console_exit(void) {}
@@ -17,6 +20,9 @@ static inline void fbcon_fb_unregistered(struct fb_info *info) {}
static inline void fbcon_fb_unbind(struct fb_info *info) {}
static inline void fbcon_suspended(void) {}
static inline void fbcon_resumed(void) {}
+int fbcon_mode_deleted(struct fb_info *info,
+ struct fb_videomode *mode) { return 0; }
+void fbcon_new_modelist(struct fb_info *info) {}
#endif

#endif /* _LINUX_FBCON_H */
--
2.20.1


2019-05-20 09:44:20

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 15/33] fbdev/atyfb: lock_fb_info can't fail

It's properly protected by reboot_lock.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Mikulas Patocka <[email protected]>
Cc: "David S. Miller" <[email protected]>
Cc: "Ville Syrjälä" <[email protected]>
Cc: Bartlomiej Zolnierkiewicz <[email protected]>
Cc: Daniel Vetter <[email protected]>
---
drivers/video/fbdev/aty/atyfb_base.c | 3 +--
1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/drivers/video/fbdev/aty/atyfb_base.c b/drivers/video/fbdev/aty/atyfb_base.c
index b6fe103df145..eebb62d82a23 100644
--- a/drivers/video/fbdev/aty/atyfb_base.c
+++ b/drivers/video/fbdev/aty/atyfb_base.c
@@ -3916,8 +3916,7 @@ static int atyfb_reboot_notify(struct notifier_block *nb,
if (!reboot_info)
goto out;

- if (!lock_fb_info(reboot_info))
- goto out;
+ lock_fb_info(reboot_info);

par = reboot_info->par;

--
2.20.1


2019-05-20 10:17:51

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 11/33] fbdev/sh_mobile: remove sh_mobile_lcdc_display_notify

On Mon, May 20, 2019 at 10:25 AM Daniel Vetter <[email protected]> wrote:
> It's dead code, and removing it avoids me having to understand
> what it's doing with lock_fb_info.
>
> Signed-off-by: Daniel Vetter <[email protected]>

Reviewed-by: Geert Uytterhoeven <[email protected]>

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2019-05-20 10:36:22

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 20/33] fbdev/sh_mob: Remove fb notifier callback

On Mon, May 20, 2019 at 11:06 AM Geert Uytterhoeven
<[email protected]> wrote:
>
> On Mon, May 20, 2019 at 10:22 AM Daniel Vetter <[email protected]> wrote:
> > This seems to be entirely defunct:
> >
> > - The FB_EVEN_SUSPEND/RESUME events are only sent out by
> > fb_set_suspend. Which is supposed to be called by drivers in their
> > suspend/resume hooks, and not itself call into drivers. Luckily
> > sh_mob doesn't call fb_set_suspend, so this seems to do nothing
> > useful.
> >
> > - The notify hook calls sh_mobile_fb_reconfig() which in turn can
> > call into the fb notifier. Or attempt too, since that would
> > deadlock.
> >
> > So looks like leftover hacks from when this was originally introduced
> > in
> >
> > commit 6011bdeaa6089d49c02de69f05980da7bad314ab
> > Author: Guennadi Liakhovetski <[email protected]>
> > Date: Wed Jul 21 10:13:21 2010 +0000
> >
> > fbdev: sh-mobile: HDMI support for SH-Mobile SoCs
> >
> > So let's just remove it.
> >
> > Signed-off-by: Daniel Vetter <[email protected]>
>
> Reviewed-by: Geert Uytterhoeven <[email protected]>
>
> Display still works fine on Armadillo800-EVA, before and after system
> suspend/resume, so:
>
> Tested-by: Geert Uytterhoeven <[email protected]>

I'm impressed, I honestly think I do not fully understand what the
shmob driver is doing here, so thank you very much for giving this a
spin!

Cheers, Daniel

>
> Gr{oetje,eeting}s,
>
> Geert
>
> --
> Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]
>
> In personal conversations with technical people, I call myself a hacker. But
> when I'm talking to journalists I just say "programmer" or something like that.
> -- Linus Torvalds



--
Daniel Vetter
Software Engineer, Intel Corporation
+41 (0) 79 365 57 48 - http://blog.ffwll.ch

2019-05-20 13:09:26

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 20/33] fbdev/sh_mob: Remove fb notifier callback

On Mon, May 20, 2019 at 10:22 AM Daniel Vetter <[email protected]> wrote:
> This seems to be entirely defunct:
>
> - The FB_EVEN_SUSPEND/RESUME events are only sent out by
> fb_set_suspend. Which is supposed to be called by drivers in their
> suspend/resume hooks, and not itself call into drivers. Luckily
> sh_mob doesn't call fb_set_suspend, so this seems to do nothing
> useful.
>
> - The notify hook calls sh_mobile_fb_reconfig() which in turn can
> call into the fb notifier. Or attempt too, since that would
> deadlock.
>
> So looks like leftover hacks from when this was originally introduced
> in
>
> commit 6011bdeaa6089d49c02de69f05980da7bad314ab
> Author: Guennadi Liakhovetski <[email protected]>
> Date: Wed Jul 21 10:13:21 2010 +0000
>
> fbdev: sh-mobile: HDMI support for SH-Mobile SoCs
>
> So let's just remove it.
>
> Signed-off-by: Daniel Vetter <[email protected]>

Reviewed-by: Geert Uytterhoeven <[email protected]>

Display still works fine on Armadillo800-EVA, before and after system
suspend/resume, so:

Tested-by: Geert Uytterhoeven <[email protected]>

Gr{oetje,eeting}s,

Geert

--
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- [email protected]

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
-- Linus Torvalds

2019-05-21 10:59:10

by Maarten Lankhorst

[permalink] [raw]
Subject: Re: [PATCH 29/33] fbcon: replace FB_EVENT_MODE_CHANGE/_ALL with direct calls

Op 20-05-2019 om 10:22 schreef Daniel Vetter:
> Create a new wrapper function for this, feels like there's some
> refactoring room here between the two modes.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Lee Jones <[email protected]>
> Cc: Daniel Thompson <[email protected]>
> Cc: Jingoo Han <[email protected]>
> Cc: Bartlomiej Zolnierkiewicz <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Hans de Goede <[email protected]>
> Cc: Yisheng Xie <[email protected]>
> Cc: "Michał Mirosław" <[email protected]>
> Cc: Peter Rosin <[email protected]>
> Cc: Mikulas Patocka <[email protected]>
> Cc: [email protected]
> ---
> drivers/video/backlight/lcd.c | 2 --
> drivers/video/fbdev/core/fbcon.c | 15 +++++++++------
> drivers/video/fbdev/core/fbmem.c | 13 ++-----------
> drivers/video/fbdev/sh_mobile_lcdcfb.c | 11 +----------
> include/linux/fb.h | 4 ----
> include/linux/fbcon.h | 2 ++
> 6 files changed, 14 insertions(+), 33 deletions(-)
>
> diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
> index 4b40c6a4d441..16298041b141 100644
> --- a/drivers/video/backlight/lcd.c
> +++ b/drivers/video/backlight/lcd.c
> @@ -32,8 +32,6 @@ static int fb_notifier_callback(struct notifier_block *self,
> /* If we aren't interested in this event, skip it immediately ... */
> switch (event) {
> case FB_EVENT_BLANK:
> - case FB_EVENT_MODE_CHANGE:
> - case FB_EVENT_MODE_CHANGE_ALL:
> case FB_EARLY_EVENT_BLANK:
> case FB_R_EARLY_EVENT_BLANK:
> break;

Below it performs a call to set_mode() if it's none of the blanking events; it can be removed. :)

> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> index c1a7476e980f..8cc62d340387 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -3005,6 +3005,15 @@ static void fbcon_set_all_vcs(struct fb_info *info)
> fbcon_modechanged(info);
> }
>
> +
> +void fbcon_update_vcs(struct fb_info *info, bool all)
> +{
> + if (all)
> + fbcon_set_all_vcs(info);
> + else
> + fbcon_modechanged(info);
> +}
> +
> int fbcon_mode_deleted(struct fb_info *info,
> struct fb_videomode *mode)
> {
> @@ -3314,12 +3323,6 @@ static int fbcon_event_notify(struct notifier_block *self,
> int idx, ret = 0;
>
> switch(action) {
> - case FB_EVENT_MODE_CHANGE:
> - fbcon_modechanged(info);
> - break;
> - case FB_EVENT_MODE_CHANGE_ALL:
> - fbcon_set_all_vcs(info);
> - break;
> case FB_EVENT_SET_CONSOLE_MAP:
> /* called with console lock held */
> con2fb = event->data;
> diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
> index cbd58ba8a59d..55b88163edc2 100644
> --- a/drivers/video/fbdev/core/fbmem.c
> +++ b/drivers/video/fbdev/core/fbmem.c
> @@ -1039,17 +1039,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
> !list_empty(&info->modelist))
> ret = fb_add_videomode(&mode, &info->modelist);
>
> - if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
> - struct fb_event event;
> - int evnt = (activate & FB_ACTIVATE_ALL) ?
> - FB_EVENT_MODE_CHANGE_ALL :
> - FB_EVENT_MODE_CHANGE;
> -
> - info->flags &= ~FBINFO_MISC_USEREVENT;
> - event.info = info;
> - event.data = &mode;
> - fb_notifier_call_chain(evnt, &event);
> - }
> + if (!ret && (flags & FBINFO_MISC_USEREVENT))
> + fbcon_update_vcs(info, activate & FB_ACTIVATE_ALL);
>
> return ret;
> }
> diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
> index 0d7a044852d7..bb1a610d0363 100644
> --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
> +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
> @@ -1776,8 +1776,6 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
> struct sh_mobile_lcdc_chan *ch = info->par;
> struct fb_var_screeninfo var;
> struct fb_videomode mode;
> - struct fb_event event;
> - int evnt = FB_EVENT_MODE_CHANGE_ALL;
>
> if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
> /* More framebuffer users are active */
> @@ -1799,14 +1797,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
> /* Couldn't reconfigure, hopefully, can continue as before */
> return;
>
> - /*
> - * fb_set_var() calls the notifier change internally, only if
> - * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
> - * user event, we have to call the chain ourselves.
> - */
> - event.info = info;
> - event.data = &ch->display.mode;
> - fb_notifier_call_chain(evnt, &event);
> + fbcon_update_vcs(info, true);
> }
>
> /*
> diff --git a/include/linux/fb.h b/include/linux/fb.h
> index 4b9b882f8f52..54d6bee09121 100644
> --- a/include/linux/fb.h
> +++ b/include/linux/fb.h
> @@ -124,16 +124,12 @@ struct fb_cursor_user {
> * Register/unregister for framebuffer events
> */
>
> -/* The resolution of the passed in fb_info about to change */
> -#define FB_EVENT_MODE_CHANGE 0x01
> /* CONSOLE-SPECIFIC: get console to framebuffer mapping */
> #define FB_EVENT_GET_CONSOLE_MAP 0x07
> /* CONSOLE-SPECIFIC: set console to framebuffer mapping */
> #define FB_EVENT_SET_CONSOLE_MAP 0x08
> /* A display blank is requested */
> #define FB_EVENT_BLANK 0x09
> -/* Private modelist is to be replaced */
> -#define FB_EVENT_MODE_CHANGE_ALL 0x0B
> /* CONSOLE-SPECIFIC: remap all consoles to new fb - for vga_switcheroo */
> #define FB_EVENT_REMAP_ALL_CONSOLE 0x0F
> /* A hardware display blank early change occurred */
> diff --git a/include/linux/fbcon.h b/include/linux/fbcon.h
> index 90e196c835dd..daaa97b0c9e6 100644
> --- a/include/linux/fbcon.h
> +++ b/include/linux/fbcon.h
> @@ -15,6 +15,7 @@ void fbcon_new_modelist(struct fb_info *info);
> void fbcon_get_requirement(struct fb_info *info,
> struct fb_blit_caps *caps);
> void fbcon_fb_blanked(struct fb_info *info, int blank);
> +void fbcon_update_vcs(struct fb_info *info, bool all);
> #else
> static inline void fb_console_init(void) {}
> static inline void fb_console_exit(void) {}
> @@ -29,6 +30,7 @@ void fbcon_new_modelist(struct fb_info *info) {}
> void fbcon_get_requirement(struct fb_info *info,
> struct fb_blit_caps *caps) {}
> void fbcon_fb_blanked(struct fb_info *info, int blank) {}
> +void fbcon_update_vcs(struct fb_info *info, bool all) {}
> #endif
>
> #endif /* _LINUX_FBCON_H */



2019-05-21 11:16:55

by Maarten Lankhorst

[permalink] [raw]
Subject: Re: [PATCH 32/33] fbcon: Document what I learned about fbcon locking

Op 20-05-2019 om 10:22 schreef Daniel Vetter:
> It's not pretty.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Bartlomiej Zolnierkiewicz <[email protected]>
> Cc: Hans de Goede <[email protected]>
> Cc: Yisheng Xie <[email protected]>
> ---
> drivers/video/fbdev/core/fbcon.c | 19 +++++++++++++++++++
> 1 file changed, 19 insertions(+)
>
> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> index b40b56702c61..cbbcf7a795f2 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -87,6 +87,25 @@
> # define DPRINTK(fmt, args...)
> #endif
>
> +/*
> + * FIXME: Locking
> + *
> + * - fbcon state itself is protected by the console_lock, and the code does a
> + * pretty good job at making sure that lock is held everywhere it's needed.
> + *
> + * - access to the registered_fb array is entirely unprotected. This should use
> + * proper object lifetime handling, i.e. get/put_fb_info. This also means
> + * switching from indices to proper pointers for fb_info everywhere.
> + *
> + * - fbcon doesn't bother with fb_lock/unlock at all. This is buggy, since it
> + * means concurrent access to the same fbdev from both fbcon and userspace
> + * will blow up. To fix this all fbcon calls from fbmem.c need to be moved out
> + * of fb_lock/unlock protected sections, since otherwise we'll recurse and
> + * deadlock eventually. Aside: Due to these deadlock issues the fbdev code in
> + * fbmem.c cannot use locking asserts, and there's lots of callers which get
> + * the rules wrong, e.g. fbsysfs.c entirely missed fb_lock/unlock calls too.
> + */
> +
> enum {
> FBCON_LOGO_CANSHOW = -1, /* the logo can be shown */
> FBCON_LOGO_DRAW = -2, /* draw the logo to a console */

I did a casual review, so for whole series with the small nitpicks I had, and any feedback by others, kbuild and the arm mess being fixed up:

Reviewed-by: Maarten Lankhorst <[email protected]>

However, according to reviewer's statement of oversight:

While I have reviewed the patch and believe it to be sound, I do not (unless explicitly stated elsewhere)
make any warranties or guarantees that it will achieve its stated purpose or function properly in any given situation.

:)

~Maarten


2019-05-21 12:45:05

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 29/33] fbcon: replace FB_EVENT_MODE_CHANGE/_ALL with direct calls

On Tue, May 21, 2019 at 12:56:30PM +0200, Maarten Lankhorst wrote:
> Op 20-05-2019 om 10:22 schreef Daniel Vetter:
> > Create a new wrapper function for this, feels like there's some
> > refactoring room here between the two modes.
> >
> > Signed-off-by: Daniel Vetter <[email protected]>
> > Cc: Lee Jones <[email protected]>
> > Cc: Daniel Thompson <[email protected]>
> > Cc: Jingoo Han <[email protected]>
> > Cc: Bartlomiej Zolnierkiewicz <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Hans de Goede <[email protected]>
> > Cc: Yisheng Xie <[email protected]>
> > Cc: "Michał Mirosław" <[email protected]>
> > Cc: Peter Rosin <[email protected]>
> > Cc: Mikulas Patocka <[email protected]>
> > Cc: [email protected]
> > ---
> > drivers/video/backlight/lcd.c | 2 --
> > drivers/video/fbdev/core/fbcon.c | 15 +++++++++------
> > drivers/video/fbdev/core/fbmem.c | 13 ++-----------
> > drivers/video/fbdev/sh_mobile_lcdcfb.c | 11 +----------
> > include/linux/fb.h | 4 ----
> > include/linux/fbcon.h | 2 ++
> > 6 files changed, 14 insertions(+), 33 deletions(-)
> >
> > diff --git a/drivers/video/backlight/lcd.c b/drivers/video/backlight/lcd.c
> > index 4b40c6a4d441..16298041b141 100644
> > --- a/drivers/video/backlight/lcd.c
> > +++ b/drivers/video/backlight/lcd.c
> > @@ -32,8 +32,6 @@ static int fb_notifier_callback(struct notifier_block *self,
> > /* If we aren't interested in this event, skip it immediately ... */
> > switch (event) {
> > case FB_EVENT_BLANK:
> > - case FB_EVENT_MODE_CHANGE:
> > - case FB_EVENT_MODE_CHANGE_ALL:
> > case FB_EARLY_EVENT_BLANK:
> > case FB_R_EARLY_EVENT_BLANK:
> > break;
>
> Below it performs a call to set_mode() if it's none of the blanking events; it can be removed. :)

Oops ... I think I'll insert a patch here to create a new MODESET event
for backlights. We still need this one I think (maybe not for kms, but for
old fbdev drivers). And maybe a wrapper for fb_backlight_notify on top ...

Thanks for spotting this.
-Daniel

>
> > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > index c1a7476e980f..8cc62d340387 100644
> > --- a/drivers/video/fbdev/core/fbcon.c
> > +++ b/drivers/video/fbdev/core/fbcon.c
> > @@ -3005,6 +3005,15 @@ static void fbcon_set_all_vcs(struct fb_info *info)
> > fbcon_modechanged(info);
> > }
> >
> > +
> > +void fbcon_update_vcs(struct fb_info *info, bool all)
> > +{
> > + if (all)
> > + fbcon_set_all_vcs(info);
> > + else
> > + fbcon_modechanged(info);
> > +}
> > +
> > int fbcon_mode_deleted(struct fb_info *info,
> > struct fb_videomode *mode)
> > {
> > @@ -3314,12 +3323,6 @@ static int fbcon_event_notify(struct notifier_block *self,
> > int idx, ret = 0;
> >
> > switch(action) {
> > - case FB_EVENT_MODE_CHANGE:
> > - fbcon_modechanged(info);
> > - break;
> > - case FB_EVENT_MODE_CHANGE_ALL:
> > - fbcon_set_all_vcs(info);
> > - break;
> > case FB_EVENT_SET_CONSOLE_MAP:
> > /* called with console lock held */
> > con2fb = event->data;
> > diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
> > index cbd58ba8a59d..55b88163edc2 100644
> > --- a/drivers/video/fbdev/core/fbmem.c
> > +++ b/drivers/video/fbdev/core/fbmem.c
> > @@ -1039,17 +1039,8 @@ fb_set_var(struct fb_info *info, struct fb_var_screeninfo *var)
> > !list_empty(&info->modelist))
> > ret = fb_add_videomode(&mode, &info->modelist);
> >
> > - if (!ret && (flags & FBINFO_MISC_USEREVENT)) {
> > - struct fb_event event;
> > - int evnt = (activate & FB_ACTIVATE_ALL) ?
> > - FB_EVENT_MODE_CHANGE_ALL :
> > - FB_EVENT_MODE_CHANGE;
> > -
> > - info->flags &= ~FBINFO_MISC_USEREVENT;
> > - event.info = info;
> > - event.data = &mode;
> > - fb_notifier_call_chain(evnt, &event);
> > - }
> > + if (!ret && (flags & FBINFO_MISC_USEREVENT))
> > + fbcon_update_vcs(info, activate & FB_ACTIVATE_ALL);
> >
> > return ret;
> > }
> > diff --git a/drivers/video/fbdev/sh_mobile_lcdcfb.c b/drivers/video/fbdev/sh_mobile_lcdcfb.c
> > index 0d7a044852d7..bb1a610d0363 100644
> > --- a/drivers/video/fbdev/sh_mobile_lcdcfb.c
> > +++ b/drivers/video/fbdev/sh_mobile_lcdcfb.c
> > @@ -1776,8 +1776,6 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
> > struct sh_mobile_lcdc_chan *ch = info->par;
> > struct fb_var_screeninfo var;
> > struct fb_videomode mode;
> > - struct fb_event event;
> > - int evnt = FB_EVENT_MODE_CHANGE_ALL;
> >
> > if (ch->use_count > 1 || (ch->use_count == 1 && !info->fbcon_par))
> > /* More framebuffer users are active */
> > @@ -1799,14 +1797,7 @@ static void sh_mobile_fb_reconfig(struct fb_info *info)
> > /* Couldn't reconfigure, hopefully, can continue as before */
> > return;
> >
> > - /*
> > - * fb_set_var() calls the notifier change internally, only if
> > - * FBINFO_MISC_USEREVENT flag is set. Since we do not want to fake a
> > - * user event, we have to call the chain ourselves.
> > - */
> > - event.info = info;
> > - event.data = &ch->display.mode;
> > - fb_notifier_call_chain(evnt, &event);
> > + fbcon_update_vcs(info, true);
> > }
> >
> > /*
> > diff --git a/include/linux/fb.h b/include/linux/fb.h
> > index 4b9b882f8f52..54d6bee09121 100644
> > --- a/include/linux/fb.h
> > +++ b/include/linux/fb.h
> > @@ -124,16 +124,12 @@ struct fb_cursor_user {
> > * Register/unregister for framebuffer events
> > */
> >
> > -/* The resolution of the passed in fb_info about to change */
> > -#define FB_EVENT_MODE_CHANGE 0x01
> > /* CONSOLE-SPECIFIC: get console to framebuffer mapping */
> > #define FB_EVENT_GET_CONSOLE_MAP 0x07
> > /* CONSOLE-SPECIFIC: set console to framebuffer mapping */
> > #define FB_EVENT_SET_CONSOLE_MAP 0x08
> > /* A display blank is requested */
> > #define FB_EVENT_BLANK 0x09
> > -/* Private modelist is to be replaced */
> > -#define FB_EVENT_MODE_CHANGE_ALL 0x0B
> > /* CONSOLE-SPECIFIC: remap all consoles to new fb - for vga_switcheroo */
> > #define FB_EVENT_REMAP_ALL_CONSOLE 0x0F
> > /* A hardware display blank early change occurred */
> > diff --git a/include/linux/fbcon.h b/include/linux/fbcon.h
> > index 90e196c835dd..daaa97b0c9e6 100644
> > --- a/include/linux/fbcon.h
> > +++ b/include/linux/fbcon.h
> > @@ -15,6 +15,7 @@ void fbcon_new_modelist(struct fb_info *info);
> > void fbcon_get_requirement(struct fb_info *info,
> > struct fb_blit_caps *caps);
> > void fbcon_fb_blanked(struct fb_info *info, int blank);
> > +void fbcon_update_vcs(struct fb_info *info, bool all);
> > #else
> > static inline void fb_console_init(void) {}
> > static inline void fb_console_exit(void) {}
> > @@ -29,6 +30,7 @@ void fbcon_new_modelist(struct fb_info *info) {}
> > void fbcon_get_requirement(struct fb_info *info,
> > struct fb_blit_caps *caps) {}
> > void fbcon_fb_blanked(struct fb_info *info, int blank) {}
> > +void fbcon_update_vcs(struct fb_info *info, bool all) {}
> > #endif
> >
> > #endif /* _LINUX_FBCON_H */
>
>

--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch