2022-02-01 20:50:01

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 00/21] some fbcon patches, mostly locking

Hi all,

This took way longer than I hoped, but well I got lost in head-scratching
locking problems. Anyway ended up typing a pile of fbcon patches. Rough
overview:

- MAINTAINER entry for fbdev core in drm-misc, with the usual group
maintainering

- The reverts, but with a compile time option. I looked into combining
this with the RFC from Helge, but it looked like worse than either
approach, so I've kept mine. I think merging either is fine, no personal
stake here on the bikeshed color.

- The real distraction, aka a bunch of cleanups and mostly locking work
for fbcon. I managed to ditch at least one locking FIXME from fbcon.c.

The bad news that I spent a bunch more time pondering about the bigger
locking issues in fbcon.c, and I think as-is they're unfixable. We need
the threaded printk support to land first, so that we're not adding
lock_fb_info() to all printk() contexts. Because that just cannot work.

That also means we'll likely have another fbcon regression to face, in the
form of worse oops printing ability. And that one I don't think we can fix
with clever application of #ifdef, because changing locking rules at
compile time in fundamental ways is just not a very good idea.

Anyway, testing, review, feedback and all that very much welcome, as
usual.

Cheers, Daniel

Daniel Vetter (21):
MAINTAINERS: Add entry for fbdev core
fbcon: Resurrect fbcon accelerated scrolling code
fbcon: Restore fbcon scrolling acceleration
fbcon: delete a few unneeded forward decl
fbcon: Introduce wrapper for console->fb_info lookup
fbcon: delete delayed loading code
fbdev/sysfs: Fix locking
fbcon: Use delayed work for cursor
fbcon: Replace FBCON_FLAGS_INIT with a boolean
fb: Delete fb_info->queue
fbcon: Extract fbcon_open/release helpers
fbcon: Ditch error handling for con2fb_release_oldinfo
fbcon: move more common code into fb_open()
fbcon: use lock_fb_info in fbcon_open/release
fbcon: Consistently protect deferred_takeover with console_lock()
fbcon: Move console_lock for register/unlink/unregister
fbcon: Move more code into fbcon_release
fbcon: untangle fbcon_exit
fbcon: Maintain a private array of fb_info
Revert "fbdev: Prevent probing generic drivers if a FB is already
registered"
fbdev: Make registered_fb[] private to fbmem.c

Documentation/gpu/todo.rst | 13 +-
MAINTAINERS | 6 +
drivers/video/console/Kconfig | 11 +
drivers/video/fbdev/core/bitblit.c | 16 +
drivers/video/fbdev/core/fbcon.c | 1072 +++++++++++++++++------
drivers/video/fbdev/core/fbcon.h | 67 +-
drivers/video/fbdev/core/fbcon_ccw.c | 28 +-
drivers/video/fbdev/core/fbcon_cw.c | 28 +-
drivers/video/fbdev/core/fbcon_rotate.h | 21 +
drivers/video/fbdev/core/fbcon_ud.c | 37 +-
drivers/video/fbdev/core/fbmem.c | 35 +-
drivers/video/fbdev/core/fbsysfs.c | 2 +
drivers/video/fbdev/core/tileblit.c | 16 +
drivers/video/fbdev/efifb.c | 11 -
drivers/video/fbdev/simplefb.c | 11 -
drivers/video/fbdev/skeletonfb.c | 12 +-
include/linux/fb.h | 10 +-
17 files changed, 1017 insertions(+), 379 deletions(-)

--
2.33.0


2022-02-01 20:50:03

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

Ever since Tomi extracted the core code in 2014 it's been defacto me
maintaining this, with help from others from dri-devel and sometimes
Linus (but those are mostly merge conflicts):

$ git shortlog -ns drivers/video/fbdev/core/ | head -n5
35 Daniel Vetter
23 Linus Torvalds
10 Hans de Goede
9 Dave Airlie
6 Peter Rosin

I think ideally we'd also record that the various firmware fb drivers
(efifb, vesafb, ...) are also maintained in drm-misc because for the
past few years the patches have either been to fix handover issues
with drm drivers, or caused handover issues with drm drivers. So any
other tree just doesn't make sense. But also, there's plenty of
outdated MAINTAINER entries for these with people and git trees that
haven't been active in years, so maybe let's just leave them alone.
And furthermore distros are now adopting simpledrm as the firmware fb
driver, so hopefully the need to care about the fbdev firmware drivers
will go down going forward.

Note that drm-misc is group maintained, I expect that to continue like
we've done before, so no new expectations that patches all go through
my hands. That would be silly. This also means I'm happy to put any
other volunteer's name in the M: line, but otherwise git log says I'm
the one who's stuck with this.

Cc: Dave Airlie <[email protected]>
Cc: Jani Nikula <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Linux Fbdev development list <[email protected]>
Cc: Pavel Machek <[email protected]>
Cc: Sam Ravnborg <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Javier Martinez Canillas <[email protected]>
Cc: DRI Development <[email protected]>
Cc: Linux Kernel Mailing List <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Geert Uytterhoeven <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Sven Schnelle <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Daniel Vetter <[email protected]>
---
MAINTAINERS | 6 ++++++
1 file changed, 6 insertions(+)

diff --git a/MAINTAINERS b/MAINTAINERS
index ea3e6c914384..49809eaa3096 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -7573,6 +7573,12 @@ S: Maintained
W: http://floatingpoint.sourceforge.net/emulator/index.html
F: arch/x86/math-emu/

+FRAMEBUFFER CORE
+M: Daniel Vetter <[email protected]>
+F: drivers/video/fbdev/core/
+S: Odd Fixes
+T: git git://anongit.freedesktop.org/drm/drm-misc
+
FRAMEBUFFER LAYER
M: Helge Deller <[email protected]>
L: [email protected]
--
2.33.0

2022-02-01 20:50:07

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 05/21] fbcon: Introduce wrapper for console->fb_info lookup

Half of it is protected by console_lock, but the other half is a lot
more awkward: Registration/deregistration of fbdev are serialized, but
we don't really clear out anything in con2fb_map and so there's
potential for use-after free mixups.

First step is to encapsulate the lookup.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Helge Deller <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 76 ++++++++++++++++++--------------
1 file changed, 44 insertions(+), 32 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 2a575620ef59..8f971de35885 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -110,6 +110,18 @@ static struct fbcon_display fb_display[MAX_NR_CONSOLES];
static signed char con2fb_map[MAX_NR_CONSOLES];
static signed char con2fb_map_boot[MAX_NR_CONSOLES];

+static struct fb_info *fbcon_info_from_console(int console)
+{
+ WARN_CONSOLE_UNLOCKED();
+
+ /*
+ * Note that only con2fb_map is protected by the console lock,
+ * registered_fb is protected by a separate mutex. This lookup can
+ * therefore race.
+ */
+ return registered_fb[con2fb_map[console]];
+}
+
static int logo_lines;
/* logo_shown is an index to vc_cons when >= 0; otherwise follows FBCON_LOGO
enums. */
@@ -197,7 +209,7 @@ static void fbcon_rotate(struct fb_info *info, u32 rotate)
if (!ops || ops->currcon == -1)
return;

- fb_info = registered_fb[con2fb_map[ops->currcon]];
+ fb_info = fbcon_info_from_console(ops->currcon);

if (info == fb_info) {
struct fbcon_display *p = &fb_display[ops->currcon];
@@ -224,7 +236,7 @@ static void fbcon_rotate_all(struct fb_info *info, u32 rotate)
for (i = first_fb_vc; i <= last_fb_vc; i++) {
vc = vc_cons[i].d;
if (!vc || vc->vc_mode != KD_TEXT ||
- registered_fb[con2fb_map[i]] != info)
+ fbcon_info_from_console(i) != info)
continue;

p = &fb_display[vc->vc_num];
@@ -354,7 +366,7 @@ static void fb_flashcursor(struct work_struct *work)
vc = vc_cons[ops->currcon].d;

if (!vc || !con_is_visible(vc) ||
- registered_fb[con2fb_map[vc->vc_num]] != info ||
+ fbcon_info_from_console(vc->vc_num) != info ||
vc->vc_deccm != 1) {
console_unlock();
return;
@@ -789,7 +801,7 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
if (show_logo) {
struct vc_data *fg_vc = vc_cons[fg_console].d;
struct fb_info *fg_info =
- registered_fb[con2fb_map[fg_console]];
+ fbcon_info_from_console(fg_console);

fbcon_prepare_logo(fg_vc, fg_info, fg_vc->vc_cols,
fg_vc->vc_rows, fg_vc->vc_cols,
@@ -1012,7 +1024,7 @@ static void fbcon_init(struct vc_data *vc, int init)
if (con2fb_map[vc->vc_num] == -1)
con2fb_map[vc->vc_num] = info_idx;

- info = registered_fb[con2fb_map[vc->vc_num]];
+ info = fbcon_info_from_console(vc->vc_num);

if (logo_shown < 0 && console_loglevel <= CONSOLE_LOGLEVEL_QUIET)
logo_shown = FBCON_LOGO_DONTSHOW;
@@ -1231,7 +1243,7 @@ static void fbcon_deinit(struct vc_data *vc)
static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
int width)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;

struct fbcon_display *p = &fb_display[vc->vc_num];
@@ -1269,7 +1281,7 @@ static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
int count, int ypos, int xpos)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_display *p = &fb_display[vc->vc_num];
struct fbcon_ops *ops = info->fbcon_par;

@@ -1289,7 +1301,7 @@ static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos)

static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;

if (!fbcon_is_inactive(vc, info))
@@ -1298,7 +1310,7 @@ static void fbcon_clear_margins(struct vc_data *vc, int bottom_only)

static void fbcon_cursor(struct vc_data *vc, int mode)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;
int c = scr_readw((u16 *) vc->vc_pos);

@@ -1427,7 +1439,7 @@ static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,

static __inline__ void ywrap_up(struct vc_data *vc, int count)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];

@@ -1446,7 +1458,7 @@ static __inline__ void ywrap_up(struct vc_data *vc, int count)

static __inline__ void ywrap_down(struct vc_data *vc, int count)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];

@@ -1465,7 +1477,7 @@ static __inline__ void ywrap_down(struct vc_data *vc, int count)

static __inline__ void ypan_up(struct vc_data *vc, int count)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_display *p = &fb_display[vc->vc_num];
struct fbcon_ops *ops = info->fbcon_par;

@@ -1489,7 +1501,7 @@ static __inline__ void ypan_up(struct vc_data *vc, int count)

static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];

@@ -1513,7 +1525,7 @@ static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)

static __inline__ void ypan_down(struct vc_data *vc, int count)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_display *p = &fb_display[vc->vc_num];
struct fbcon_ops *ops = info->fbcon_par;

@@ -1537,7 +1549,7 @@ static __inline__ void ypan_down(struct vc_data *vc, int count)

static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];

@@ -1562,7 +1574,7 @@ static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
int dy, int dx, int height, int width, u_int y_break)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;
u_int b;

@@ -1604,7 +1616,7 @@ static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy,
static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
int height, int width)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_display *p = &fb_display[vc->vc_num];

if (fbcon_is_inactive(vc, info))
@@ -1733,7 +1745,7 @@ static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p,
static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
enum con_scroll dir, unsigned int count)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_display *p = &fb_display[vc->vc_num];
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
@@ -2013,7 +2025,7 @@ static void updatescrollmode(struct fbcon_display *p,
static int fbcon_resize(struct vc_data *vc, unsigned int width,
unsigned int height, unsigned int user)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];
struct fb_var_screeninfo var = info->var;
@@ -2082,7 +2094,7 @@ static int fbcon_switch(struct vc_data *vc)
struct fb_var_screeninfo var;
int i, ret, prev_console;

- info = registered_fb[con2fb_map[vc->vc_num]];
+ info = fbcon_info_from_console(vc->vc_num);
ops = info->fbcon_par;

if (logo_shown >= 0) {
@@ -2096,7 +2108,7 @@ static int fbcon_switch(struct vc_data *vc)

prev_console = ops->currcon;
if (prev_console != -1)
- old_info = registered_fb[con2fb_map[prev_console]];
+ old_info = fbcon_info_from_console(prev_console);
/*
* FIXME: If we have multiple fbdev's loaded, we need to
* update all info->currcon. Perhaps, we can place this
@@ -2219,7 +2231,7 @@ static void fbcon_generic_blank(struct vc_data *vc, struct fb_info *info,

static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;

if (mode_switch) {
@@ -2261,7 +2273,7 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)

static int fbcon_debug_enter(struct vc_data *vc)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;

ops->save_graphics = ops->graphics;
@@ -2274,7 +2286,7 @@ static int fbcon_debug_enter(struct vc_data *vc)

static int fbcon_debug_leave(struct vc_data *vc)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;

ops->graphics = ops->save_graphics;
@@ -2410,7 +2422,7 @@ static void set_vc_hi_font(struct vc_data *vc, bool set)
static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
const u8 * data, int userfont)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
struct fbcon_ops *ops = info->fbcon_par;
struct fbcon_display *p = &fb_display[vc->vc_num];
int resize;
@@ -2464,7 +2476,7 @@ static int fbcon_do_set_font(struct vc_data *vc, int w, int h, int charcount,
static int fbcon_set_font(struct vc_data *vc, struct console_font *font,
unsigned int flags)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
unsigned charcount = font->charcount;
int w = font->width;
int h = font->height;
@@ -2528,7 +2540,7 @@ static int fbcon_set_font(struct vc_data *vc, struct console_font *font,

static int fbcon_set_def_font(struct vc_data *vc, struct console_font *font, char *name)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
const struct font_desc *f;

if (!name)
@@ -2552,7 +2564,7 @@ static struct fb_cmap palette_cmap = {

static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table)
{
- struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fb_info *info = fbcon_info_from_console(vc->vc_num);
int i, j, k, depth;
u8 val;

@@ -2668,7 +2680,7 @@ static void fbcon_modechanged(struct fb_info *info)
return;
vc = vc_cons[ops->currcon].d;
if (vc->vc_mode != KD_TEXT ||
- registered_fb[con2fb_map[ops->currcon]] != info)
+ fbcon_info_from_console(ops->currcon) != info)
return;

p = &fb_display[vc->vc_num];
@@ -2708,7 +2720,7 @@ static void fbcon_set_all_vcs(struct fb_info *info)
for (i = first_fb_vc; i <= last_fb_vc; i++) {
vc = vc_cons[i].d;
if (!vc || vc->vc_mode != KD_TEXT ||
- registered_fb[con2fb_map[i]] != info)
+ fbcon_info_from_console(i) != info)
continue;

if (con_is_visible(vc)) {
@@ -2971,7 +2983,7 @@ void fbcon_fb_blanked(struct fb_info *info, int blank)

vc = vc_cons[ops->currcon].d;
if (vc->vc_mode != KD_TEXT ||
- registered_fb[con2fb_map[ops->currcon]] != info)
+ fbcon_info_from_console(ops->currcon) != info)
return;

if (con_is_visible(vc)) {
@@ -2991,7 +3003,7 @@ void fbcon_new_modelist(struct fb_info *info)
const struct fb_videomode *mode;

for (i = first_fb_vc; i <= last_fb_vc; i++) {
- if (registered_fb[con2fb_map[i]] != info)
+ if (fbcon_info_from_console(i) != info)
continue;
if (!fb_display[i].mode)
continue;
--
2.33.0

2022-02-01 20:50:07

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 06/21] fbcon: delete delayed loading code

Before

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

it was possible to load fbcon and fbdev drivers in any order, which
means that fbcon init had to handle the case where fbdev drivers where
already registered.

This is no longer possible, hence delete that code.

Note that the exit case is a bit more complex and will be done in a
separate patch.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Helge Deller <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Du Cheng <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 8f971de35885..814b648e8f09 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -942,7 +942,7 @@ static const char *fbcon_startup(void)
return display_desc;
/*
* Instead of blindly using registered_fb[0], we use info_idx, set by
- * fb_console_init();
+ * fbcon_fb_registered();
*/
info = registered_fb[info_idx];
if (!info)
@@ -3316,17 +3316,6 @@ static void fbcon_start(void)
return;
}
#endif
-
- if (num_registered_fb) {
- int i;
-
- for_each_registered_fb(i) {
- info_idx = i;
- break;
- }
-
- do_fbcon_takeover(0);
- }
}

static void fbcon_exit(void)
--
2.33.0

2022-02-01 20:50:10

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 08/21] fbcon: Use delayed work for cursor

Allows us to delete a bunch of hand-rolled stuff. Also to simplify the
code we initialize the cursor_work completely when we allocate the
fbcon_ops structure, instead of trying to cope with console
re-initialization.

The motiviation here is that fbcon code stops using the fb_info.queue,
which helps with locking issues around cleanup and all that in a later
patch.

Also note that this allows us to ditch the hand-rolled work cleanup in
fbcon_exit - we already call fbcon_del_cursor_timer, which takes care
of everything. Plus this was racy anyway.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Tetsuo Handa <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 85 +++++++++++++-------------------
drivers/video/fbdev/core/fbcon.h | 4 +-
2 files changed, 35 insertions(+), 54 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 814b648e8f09..affb40658fee 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -348,8 +348,8 @@ static int get_color(struct vc_data *vc, struct fb_info *info,

static void fb_flashcursor(struct work_struct *work)
{
- struct fb_info *info = container_of(work, struct fb_info, queue);
- struct fbcon_ops *ops = info->fbcon_par;
+ struct fbcon_ops *ops = container_of(work, struct fbcon_ops, cursor_work.work);
+ struct fb_info *info;
struct vc_data *vc = NULL;
int c;
int mode;
@@ -362,7 +362,10 @@ static void fb_flashcursor(struct work_struct *work)
if (ret == 0)
return;

- if (ops && ops->currcon != -1)
+ /* protected by console_lock */
+ info = ops->info;
+
+ if (ops->currcon != -1)
vc = vc_cons[ops->currcon].d;

if (!vc || !con_is_visible(vc) ||
@@ -378,42 +381,25 @@ static void fb_flashcursor(struct work_struct *work)
ops->cursor(vc, info, mode, get_color(vc, info, c, 1),
get_color(vc, info, c, 0));
console_unlock();
-}

-static void cursor_timer_handler(struct timer_list *t)
-{
- struct fbcon_ops *ops = from_timer(ops, t, cursor_timer);
- struct fb_info *info = ops->info;
-
- queue_work(system_power_efficient_wq, &info->queue);
- mod_timer(&ops->cursor_timer, jiffies + ops->cur_blink_jiffies);
+ queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
+ ops->cur_blink_jiffies);
}

-static void fbcon_add_cursor_timer(struct fb_info *info)
+static void fbcon_add_cursor_work(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;

- if ((!info->queue.func || info->queue.func == fb_flashcursor) &&
- !(ops->flags & FBCON_FLAGS_CURSOR_TIMER) &&
- !fbcon_cursor_noblink) {
- if (!info->queue.func)
- INIT_WORK(&info->queue, fb_flashcursor);
-
- timer_setup(&ops->cursor_timer, cursor_timer_handler, 0);
- mod_timer(&ops->cursor_timer, jiffies + ops->cur_blink_jiffies);
- ops->flags |= FBCON_FLAGS_CURSOR_TIMER;
- }
+ if (!fbcon_cursor_noblink)
+ queue_delayed_work(system_power_efficient_wq, &ops->cursor_work,
+ ops->cur_blink_jiffies);
}

-static void fbcon_del_cursor_timer(struct fb_info *info)
+static void fbcon_del_cursor_work(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;

- if (info->queue.func == fb_flashcursor &&
- ops->flags & FBCON_FLAGS_CURSOR_TIMER) {
- del_timer_sync(&ops->cursor_timer);
- ops->flags &= ~FBCON_FLAGS_CURSOR_TIMER;
- }
+ cancel_delayed_work_sync(&ops->cursor_work);
}

#ifndef MODULE
@@ -712,6 +698,8 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
if (!ops)
err = -ENOMEM;
+
+ INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
}

if (!err) {
@@ -749,7 +737,7 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
}

if (!err) {
- fbcon_del_cursor_timer(oldinfo);
+ fbcon_del_cursor_work(oldinfo);
kfree(ops->cursor_state.mask);
kfree(ops->cursor_data);
kfree(ops->cursor_src);
@@ -865,7 +853,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
logo_shown != FBCON_LOGO_DONTSHOW);

if (!found)
- fbcon_add_cursor_timer(info);
+ fbcon_add_cursor_work(info);
con2fb_map_boot[unit] = newidx;
con2fb_init_display(vc, info, unit, show_logo);
}
@@ -962,6 +950,8 @@ static const char *fbcon_startup(void)
return NULL;
}

+ INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
+
ops->currcon = -1;
ops->graphics = 1;
ops->cur_rotate = -1;
@@ -1004,7 +994,7 @@ static const char *fbcon_startup(void)
info->var.yres,
info->var.bits_per_pixel);

- fbcon_add_cursor_timer(info);
+ fbcon_add_cursor_work(info);
return display_desc;
}

@@ -1194,7 +1184,7 @@ static void fbcon_deinit(struct vc_data *vc)
goto finished;

if (con_is_visible(vc))
- fbcon_del_cursor_timer(info);
+ fbcon_del_cursor_work(info);

ops->flags &= ~FBCON_FLAGS_INIT;
finished:
@@ -1320,9 +1310,9 @@ static void fbcon_cursor(struct vc_data *vc, int mode)
return;

if (vc->vc_cursor_type & CUR_SW)
- fbcon_del_cursor_timer(info);
+ fbcon_del_cursor_work(info);
else
- fbcon_add_cursor_timer(info);
+ fbcon_add_cursor_work(info);

ops->cursor_flash = (mode == CM_ERASE) ? 0 : 1;

@@ -2149,14 +2139,14 @@ static int fbcon_switch(struct vc_data *vc)
}

if (old_info != info)
- fbcon_del_cursor_timer(old_info);
+ fbcon_del_cursor_work(old_info);
}

if (fbcon_is_inactive(vc, info) ||
ops->blank_state != FB_BLANK_UNBLANK)
- fbcon_del_cursor_timer(info);
+ fbcon_del_cursor_work(info);
else
- fbcon_add_cursor_timer(info);
+ fbcon_add_cursor_work(info);

set_blitting_type(vc, info);
ops->cursor_reset = 1;
@@ -2264,9 +2254,9 @@ static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch)

if (mode_switch || fbcon_is_inactive(vc, info) ||
ops->blank_state != FB_BLANK_UNBLANK)
- fbcon_del_cursor_timer(info);
+ fbcon_del_cursor_work(info);
else
- fbcon_add_cursor_timer(info);
+ fbcon_add_cursor_work(info);

return 0;
}
@@ -3198,7 +3188,7 @@ static ssize_t show_cursor_blink(struct device *device,
if (!ops)
goto err;

- blink = (ops->flags & FBCON_FLAGS_CURSOR_TIMER) ? 1 : 0;
+ blink = delayed_work_pending(&ops->cursor_work);
err:
console_unlock();
return snprintf(buf, PAGE_SIZE, "%d\n", blink);
@@ -3227,10 +3217,10 @@ static ssize_t store_cursor_blink(struct device *device,

if (blink) {
fbcon_cursor_noblink = 0;
- fbcon_add_cursor_timer(info);
+ fbcon_add_cursor_work(info);
} else {
fbcon_cursor_noblink = 1;
- fbcon_del_cursor_timer(info);
+ fbcon_del_cursor_work(info);
}

err:
@@ -3331,15 +3321,9 @@ static void fbcon_exit(void)
#endif

for_each_registered_fb(i) {
- int pending = 0;
-
mapped = 0;
info = registered_fb[i];

- if (info->queue.func)
- pending = cancel_work_sync(&info->queue);
- pr_debug("fbcon: %s pending work\n", (pending ? "canceled" : "no"));
-
for (j = first_fb_vc; j <= last_fb_vc; j++) {
if (con2fb_map[j] == i) {
mapped = 1;
@@ -3355,15 +3339,12 @@ static void fbcon_exit(void)
if (info->fbcon_par) {
struct fbcon_ops *ops = info->fbcon_par;

- fbcon_del_cursor_timer(info);
+ fbcon_del_cursor_work(info);
kfree(ops->cursor_src);
kfree(ops->cursor_state.mask);
kfree(info->fbcon_par);
info->fbcon_par = NULL;
}
-
- if (info->queue.func == fb_flashcursor)
- info->queue.func = NULL;
}
}
}
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index 5246d0f2574b..dce5ce41093e 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -14,11 +14,11 @@
#include <linux/types.h>
#include <linux/vt_buffer.h>
#include <linux/vt_kern.h>
+#include <linux/workqueue.h>

#include <asm/io.h>

#define FBCON_FLAGS_INIT 1
-#define FBCON_FLAGS_CURSOR_TIMER 2

/*
* This is the interface between the low-level console driver and the
@@ -66,7 +66,7 @@ struct fbcon_ops {
int (*update_start)(struct fb_info *info);
int (*rotate_font)(struct fb_info *info, struct vc_data *vc);
struct fb_var_screeninfo var; /* copy of the current fb_var_screeninfo */
- struct timer_list cursor_timer; /* Cursor timer */
+ struct delayed_work cursor_work; /* Cursor timer */
struct fb_cursor cursor_state;
struct fbcon_display *p;
struct fb_info *info;
--
2.33.0

2022-02-01 20:50:12

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 12/21] fbcon: Ditch error handling for con2fb_release_oldinfo

It doesn't ever fail anymore.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Tetsuo Handa <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 37 +++++++++++---------------------
1 file changed, 13 insertions(+), 24 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index eea2ee14b64c..b83a5a77d8a8 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -737,9 +737,8 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
return err;
}

-static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
- struct fb_info *newinfo, int unit,
- int oldidx, int found)
+static void con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
+ struct fb_info *newinfo)
{
struct fbcon_ops *ops = oldinfo->fbcon_par;
int ret;
@@ -768,8 +767,6 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
"detected unhandled fb_set_par error, "
"error code %d\n", ret);
}
-
- return 0;
}

static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
@@ -823,7 +820,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
int oldidx = con2fb_map[unit];
struct fb_info *info = registered_fb[newidx];
struct fb_info *oldinfo = NULL;
- int found, err = 0;
+ int found, err = 0, show_logo;

WARN_CONSOLE_UNLOCKED();

@@ -852,18 +849,15 @@ static int set_con2fb_map(int unit, int newidx, int user)
* fbcon should release it.
*/
if (!err && oldinfo && !search_fb_in_map(oldidx))
- err = con2fb_release_oldinfo(vc, oldinfo, info, unit, oldidx,
- found);
+ con2fb_release_oldinfo(vc, oldinfo, info);

- if (!err) {
- int show_logo = (fg_console == 0 && !user &&
- logo_shown != FBCON_LOGO_DONTSHOW);
+ show_logo = (fg_console == 0 && !user &&
+ logo_shown != FBCON_LOGO_DONTSHOW);

- if (!found)
- fbcon_add_cursor_work(info);
- con2fb_map_boot[unit] = newidx;
- con2fb_init_display(vc, info, unit, show_logo);
- }
+ if (!found)
+ fbcon_add_cursor_work(info);
+ con2fb_map_boot[unit] = newidx;
+ con2fb_init_display(vc, info, unit, show_logo);

if (!search_fb_in_map(info_idx))
info_idx = newidx;
@@ -2786,7 +2780,7 @@ static inline void fbcon_unbind(void) {}
/* called with console_lock held */
void fbcon_fb_unbind(struct fb_info *info)
{
- int i, new_idx = -1, ret = 0;
+ int i, new_idx = -1;
int idx = info->node;

WARN_CONSOLE_UNLOCKED();
@@ -2820,13 +2814,8 @@ void fbcon_fb_unbind(struct fb_info *info)
if (con2fb_map[i] == idx) {
con2fb_map[i] = -1;
if (!search_fb_in_map(idx)) {
- ret = con2fb_release_oldinfo(vc_cons[i].d,
- info, NULL, i,
- idx, 0);
- if (ret) {
- con2fb_map[i] = idx;
- return;
- }
+ con2fb_release_oldinfo(vc_cons[i].d,
+ info, NULL);
}
}
}
--
2.33.0

2022-02-01 20:50:12

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 14/21] fbcon: use lock_fb_info in fbcon_open/release

Now we get to the real motiviation, because fbmem.c insists that
that's the right lock for these.

Ofc fbcon.c has a lot more places where it probably should call
lock_fb_info(). But looking at fbmem.c at least most of these seem to
be protected by console_lock() too, which is probably what papers over
any issues.

Note that this means we're shuffling around a bit the locking sections
for some of the console takeover and unbind paths, but not all:
- console binding/unbinding from the console layer never with
lock_fb_info
- unbind (as opposed to unlink) never bother with lock_fb_info

Also the real serialization against set_par and set_pan are still
doing by wrapping the entire ioctl code in console_lock(). So this
shuffling shouldn't be worse than what we had from a "can you trigger
races?" pov, but it's at least clearer.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Sam Ravnborg <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: William Kucharski <[email protected]>
Cc: Alex Deucher <[email protected]>
Cc: Zheyu Ma <[email protected]>
Cc: Zhen Lei <[email protected]>
Cc: Xiyu Yang <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 5 +++++
drivers/video/fbdev/core/fbmem.c | 4 ----
2 files changed, 5 insertions(+), 4 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 5a3391ff038d..496bc5f2133e 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -682,8 +682,10 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)

static void fbcon_release(struct fb_info *info)
{
+ lock_fb_info(info);
if (info->fbops->fb_release)
info->fbops->fb_release(info, 0);
+ unlock_fb_info(info);

module_put(info->fbops->owner);
}
@@ -695,11 +697,14 @@ static int fbcon_open(struct fb_info *info)
if (!try_module_get(info->fbops->owner))
return -ENODEV;

+ lock_fb_info(info);
if (info->fbops->fb_open &&
info->fbops->fb_open(info, 0)) {
+ unlock_fb_info(info);
module_put(info->fbops->owner);
return -ENODEV;
}
+ unlock_fb_info(info);

ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
if (!ops) {
diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 0fa7ede94fa6..fd51d12f2702 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1653,9 +1653,7 @@ static int do_register_framebuffer(struct fb_info *fb_info)
console_lock();
else
atomic_inc(&ignore_console_lock_warning);
- lock_fb_info(fb_info);
ret = fbcon_fb_registered(fb_info);
- unlock_fb_info(fb_info);

if (!lockless_register_fb)
console_unlock();
@@ -1672,9 +1670,7 @@ static void unbind_console(struct fb_info *fb_info)
return;

console_lock();
- lock_fb_info(fb_info);
fbcon_fb_unbind(fb_info);
- unlock_fb_info(fb_info);
console_unlock();
}

--
2.33.0

2022-02-01 20:50:18

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 20/21] Revert "fbdev: Prevent probing generic drivers if a FB is already registered"

This reverts commit fb561bf9abde49f7e00fdbf9ed2ccf2d86cac8ee.

With

commit 27599aacbaefcbf2af7b06b0029459bbf682000d
Author: Thomas Zimmermann <[email protected]>
Date: Tue Jan 25 10:12:18 2022 +0100

fbdev: Hot-unplug firmware fb devices on forced removal

this should be fixed properly and we can remove this somewhat hackish
check here (e.g. this won't catch drm drivers if fbdev emulation isn't
enabled).

Cc: Thomas Zimmermann <[email protected]>
Cc: Zack Rusin <[email protected]>
Cc: Javier Martinez Canillas <[email protected]>
Cc: Zack Rusin <[email protected]>
Cc: Hans de Goede <[email protected]>
Cc: Ilya Trukhanov <[email protected]>
Signed-off-by: Daniel Vetter <[email protected]>
Cc: Peter Jones <[email protected]>
Cc: [email protected]
---
drivers/video/fbdev/efifb.c | 11 -----------
drivers/video/fbdev/simplefb.c | 11 -----------
2 files changed, 22 deletions(-)

diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c
index ea42ba6445b2..edca3703b964 100644
--- a/drivers/video/fbdev/efifb.c
+++ b/drivers/video/fbdev/efifb.c
@@ -351,17 +351,6 @@ static int efifb_probe(struct platform_device *dev)
char *option = NULL;
efi_memory_desc_t md;

- /*
- * Generic drivers must not be registered if a framebuffer exists.
- * If a native driver was probed, the display hardware was already
- * taken and attempting to use the system framebuffer is dangerous.
- */
- if (num_registered_fb > 0) {
- dev_err(&dev->dev,
- "efifb: a framebuffer is already registered\n");
- return -EINVAL;
- }
-
if (screen_info.orig_video_isVGA != VIDEO_TYPE_EFI || pci_dev_disabled)
return -ENODEV;

diff --git a/drivers/video/fbdev/simplefb.c b/drivers/video/fbdev/simplefb.c
index 57541887188b..ee8b4412f7e4 100644
--- a/drivers/video/fbdev/simplefb.c
+++ b/drivers/video/fbdev/simplefb.c
@@ -407,17 +407,6 @@ static int simplefb_probe(struct platform_device *pdev)
struct simplefb_par *par;
struct resource *mem;

- /*
- * Generic drivers must not be registered if a framebuffer exists.
- * If a native driver was probed, the display hardware was already
- * taken and attempting to use the system framebuffer is dangerous.
- */
- if (num_registered_fb > 0) {
- dev_err(&pdev->dev,
- "simplefb: a framebuffer is already registered\n");
- return -EINVAL;
- }
-
if (fb_get_options("simplefb", NULL))
return -ENODEV;

--
2.33.0

2022-02-01 20:50:25

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 11/21] fbcon: Extract fbcon_open/release helpers

There's two minor behaviour changes in here:
- in error paths we now consistently call fb_ops->fb_release
- fb_release really can't fail (fbmem.c ignores it too) and there's no
reasonable cleanup we can do anyway.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Du Cheng <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 107 +++++++++++++++----------------
1 file changed, 53 insertions(+), 54 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index fa30e1909164..eea2ee14b64c 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -680,19 +680,37 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)

#endif /* CONFIG_MISC_TILEBLITTING */

+static int fbcon_open(struct fb_info *info)
+{
+ if (!try_module_get(info->fbops->owner))
+ return -ENODEV;
+
+ if (info->fbops->fb_open &&
+ info->fbops->fb_open(info, 0)) {
+ module_put(info->fbops->owner);
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+static void fbcon_release(struct fb_info *info)
+{
+ if (info->fbops->fb_release)
+ info->fbops->fb_release(info, 0);
+
+ module_put(info->fbops->owner);
+}

static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
int unit, int oldidx)
{
struct fbcon_ops *ops = NULL;
- int err = 0;
-
- if (!try_module_get(info->fbops->owner))
- err = -ENODEV;
+ int err;

- if (!err && info->fbops->fb_open &&
- info->fbops->fb_open(info, 0))
- err = -ENODEV;
+ err = fbcon_open(info);
+ if (err)
+ return err;

if (!err) {
ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
@@ -713,7 +731,7 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,

if (err) {
con2fb_map[unit] = oldidx;
- module_put(info->fbops->owner);
+ fbcon_release(info);
}

return err;
@@ -724,45 +742,34 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
int oldidx, int found)
{
struct fbcon_ops *ops = oldinfo->fbcon_par;
- int err = 0, ret;
+ int ret;

- if (oldinfo->fbops->fb_release &&
- oldinfo->fbops->fb_release(oldinfo, 0)) {
- con2fb_map[unit] = oldidx;
- if (!found && newinfo->fbops->fb_release)
- newinfo->fbops->fb_release(newinfo, 0);
- if (!found)
- module_put(newinfo->fbops->owner);
- err = -ENODEV;
- }
+ fbcon_release(oldinfo);

- if (!err) {
- fbcon_del_cursor_work(oldinfo);
- kfree(ops->cursor_state.mask);
- kfree(ops->cursor_data);
- kfree(ops->cursor_src);
- kfree(ops->fontbuffer);
- kfree(oldinfo->fbcon_par);
- oldinfo->fbcon_par = NULL;
- module_put(oldinfo->fbops->owner);
- /*
- If oldinfo and newinfo are driving the same hardware,
- the fb_release() method of oldinfo may attempt to
- restore the hardware state. This will leave the
- newinfo in an undefined state. Thus, a call to
- fb_set_par() may be needed for the newinfo.
- */
- if (newinfo && newinfo->fbops->fb_set_par) {
- ret = newinfo->fbops->fb_set_par(newinfo);
+ fbcon_del_cursor_work(oldinfo);
+ kfree(ops->cursor_state.mask);
+ kfree(ops->cursor_data);
+ kfree(ops->cursor_src);
+ kfree(ops->fontbuffer);
+ kfree(oldinfo->fbcon_par);
+ oldinfo->fbcon_par = NULL;
+ /*
+ If oldinfo and newinfo are driving the same hardware,
+ the fb_release() method of oldinfo may attempt to
+ restore the hardware state. This will leave the
+ newinfo in an undefined state. Thus, a call to
+ fb_set_par() may be needed for the newinfo.
+ */
+ if (newinfo && newinfo->fbops->fb_set_par) {
+ ret = newinfo->fbops->fb_set_par(newinfo);

- if (ret)
- printk(KERN_ERR "con2fb_release_oldinfo: "
- "detected unhandled fb_set_par error, "
- "error code %d\n", ret);
- }
+ if (ret)
+ printk(KERN_ERR "con2fb_release_oldinfo: "
+ "detected unhandled fb_set_par error, "
+ "error code %d\n", ret);
}

- return err;
+ return 0;
}

static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
@@ -917,7 +924,6 @@ static const char *fbcon_startup(void)
struct fbcon_display *p = &fb_display[fg_console];
struct vc_data *vc = vc_cons[fg_console].d;
const struct font_desc *font = NULL;
- struct module *owner;
struct fb_info *info = NULL;
struct fbcon_ops *ops;
int rows, cols;
@@ -936,17 +942,12 @@ static const char *fbcon_startup(void)
if (!info)
return NULL;

- owner = info->fbops->owner;
- if (!try_module_get(owner))
+ if (fbcon_open(info))
return NULL;
- if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) {
- module_put(owner);
- return NULL;
- }

ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
if (!ops) {
- module_put(owner);
+ fbcon_release(info);
return NULL;
}

@@ -3331,10 +3332,6 @@ static void fbcon_exit(void)
}

if (mapped) {
- if (info->fbops->fb_release)
- info->fbops->fb_release(info, 0);
- module_put(info->fbops->owner);
-
if (info->fbcon_par) {
struct fbcon_ops *ops = info->fbcon_par;

@@ -3344,6 +3341,8 @@ static void fbcon_exit(void)
kfree(info->fbcon_par);
info->fbcon_par = NULL;
}
+
+ fbcon_release(info);
}
}
}
--
2.33.0

2022-02-01 20:50:25

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 18/21] fbcon: untangle fbcon_exit

There's a bunch of confusions going on here:
- The deferred fbcon setup notifier should only be cleaned up from
fb_console_exit(), to be symmetric with fb_console_init()
- We also need to make sure we don't race with the work, which means
temporarily dropping the console lock (or we can deadlock)
- That also means no point in clearing deferred_takeover, we are
unloading everything anyway.
- Finally rename fbcon_exit to fbcon_release_all and move it, since
that's what's it doing when being called from consw->con_deinit
through fbcon_deinit.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Tetsuo Handa <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 63 ++++++++++++++++----------------
1 file changed, 32 insertions(+), 31 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 5c14e24d14a1..22581952b4fd 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -185,7 +185,6 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
int unit);
static void fbcon_modechanged(struct fb_info *info);
static void fbcon_set_all_vcs(struct fb_info *info);
-static void fbcon_exit(void);

static struct device *fbcon_device;

@@ -1149,6 +1148,27 @@ static void fbcon_free_font(struct fbcon_display *p, bool freefont)

static void set_vc_hi_font(struct vc_data *vc, bool set);

+static void fbcon_release_all(void)
+{
+ struct fb_info *info;
+ int i, j, mapped;
+
+ for_each_registered_fb(i) {
+ mapped = 0;
+ info = registered_fb[i];
+
+ for (j = first_fb_vc; j <= last_fb_vc; j++) {
+ if (con2fb_map[j] == i) {
+ mapped = 1;
+ con2fb_map[j] = -1;
+ }
+ }
+
+ if (mapped)
+ fbcon_release(info);
+ }
+}
+
static void fbcon_deinit(struct vc_data *vc)
{
struct fbcon_display *p = &fb_display[vc->vc_num];
@@ -1188,7 +1208,7 @@ static void fbcon_deinit(struct vc_data *vc)
set_vc_hi_font(vc, false);

if (!con_is_bound(&fb_con))
- fbcon_exit();
+ fbcon_release_all();

if (vc->vc_num == logo_shown)
logo_shown = FBCON_LOGO_CANSHOW;
@@ -3316,34 +3336,6 @@ static void fbcon_start(void)
#endif
}

-static void fbcon_exit(void)
-{
- struct fb_info *info;
- int i, j, mapped;
-
-#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
- if (deferred_takeover) {
- dummycon_unregister_output_notifier(&fbcon_output_nb);
- deferred_takeover = false;
- }
-#endif
-
- for_each_registered_fb(i) {
- mapped = 0;
- info = registered_fb[i];
-
- for (j = first_fb_vc; j <= last_fb_vc; j++) {
- if (con2fb_map[j] == i) {
- mapped = 1;
- con2fb_map[j] = -1;
- }
- }
-
- if (mapped)
- fbcon_release(info);
- }
-}
-
void __init fb_console_init(void)
{
int i;
@@ -3383,10 +3375,19 @@ static void __exit fbcon_deinit_device(void)

void __exit fb_console_exit(void)
{
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
+ console_lock();
+ if (deferred_takeover)
+ dummycon_unregister_output_notifier(&fbcon_output_nb);
+ console_unlock();
+
+ cancel_work_sync(&fbcon_deferred_takeover_work);
+#endif
+
console_lock();
fbcon_deinit_device();
device_destroy(fb_class, MKDEV(0, 0));
- fbcon_exit();
+
do_unregister_con_driver(&fb_con);
console_unlock();
}
--
2.33.0

2022-02-01 20:51:13

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 03/21] fbcon: Restore fbcon scrolling acceleration

This functionally undoes 39aead8373b3 ("fbcon: Disable accelerated
scrolling"), but behind the FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
option.

References: https://lore.kernel.org/dri-devel/[email protected]/
Fixes: 39aead8373b3 ("fbcon: Disable accelerated scrolling")
Cc: Helge Deller <[email protected]>
Cc: <[email protected]> # v5.11+
Cc: Claudio Suarez <[email protected]>
Cc: Dave Airlie <[email protected]>
Cc: Jani Nikula <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Linux Fbdev development list <[email protected]>
Cc: Pavel Machek <[email protected]>
Cc: Sam Ravnborg <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Javier Martinez Canillas <[email protected]>
Cc: DRI Development <[email protected]>
Cc: Linux Kernel Mailing List <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Geert Uytterhoeven <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Sven Schnelle <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Daniel Vetter <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 48 ++++++++++++++++++++++++++++----
1 file changed, 42 insertions(+), 6 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 2ff90061c7f3..39dc18a5de86 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1125,13 +1125,15 @@ static void fbcon_init(struct vc_data *vc, int init)

ops->graphics = 0;

- /*
- * No more hw acceleration for fbcon.
- *
- * FIXME: Garbage collect all the now dead code after sufficient time
- * has passed.
- */
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+ if ((info->flags & FBINFO_HWACCEL_COPYAREA) &&
+ !(info->flags & FBINFO_HWACCEL_DISABLED))
+ p->scrollmode = SCROLL_MOVE;
+ else /* default to something safe */
+ p->scrollmode = SCROLL_REDRAW;
+#else
p->scrollmode = SCROLL_REDRAW;
+#endif

/*
* ++guenther: console.c:vc_allocate() relies on initializing
@@ -1971,15 +1973,49 @@ static void updatescrollmode(struct fbcon_display *p,
{
struct fbcon_ops *ops = info->fbcon_par;
int fh = vc->vc_font.height;
+ int cap = info->flags;
+ u16 t = 0;
+ int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
+ info->fix.xpanstep);
+ int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
info->var.xres_virtual);
+ int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
+ divides(ypan, vc->vc_font.height) && vyres > yres;
+ int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
+ divides(ywrap, vc->vc_font.height) &&
+ divides(vc->vc_font.height, vyres) &&
+ divides(vc->vc_font.height, yres);
+ int reading_fast = cap & FBINFO_READS_FAST;
+ int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
+ !(cap & FBINFO_HWACCEL_DISABLED);
+ int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
+ !(cap & FBINFO_HWACCEL_DISABLED);

p->vrows = vyres/fh;
if (yres > (fh * (vc->vc_rows + 1)))
p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
if ((yres % fh) && (vyres % fh < yres % fh))
p->vrows--;
+
+ if (good_wrap || good_pan) {
+ if (reading_fast || fast_copyarea)
+ p->scrollmode = good_wrap ?
+ SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
+ else
+ p->scrollmode = good_wrap ? SCROLL_REDRAW :
+ SCROLL_PAN_REDRAW;
+ } else {
+ if (reading_fast || (fast_copyarea && !fast_imageblit))
+ p->scrollmode = SCROLL_MOVE;
+ else
+ p->scrollmode = SCROLL_REDRAW;
+ }
+
+#ifndef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
+ p->scrollmode = SCROLL_REDRAW;
+#endif
}

#define PITCH(w) (((w) + 7) >> 3)
--
2.33.0

2022-02-01 20:51:22

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 19/21] fbcon: Maintain a private array of fb_info

Accessing the one in fbmem.c without taking the right locks is a bad
idea. Instead maintain our own private copy, which is fully protected
by console_lock() (like everything else in fbcon.c). That copy is
serialized through fbcon_fb_registered/unregistered() calls.

Also this means we do not need to hold a full fb_info reference, which
is nice because doing so would mean a refcount loop between the
console and the fb_info. But it's also not nice since it means
console_lock() must be held absolutely everywhere. Well strictly
speaking we could still try to do some refcounting games again by
calling get_fb_info before we drop the console_lock. But things will
get tricky.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 82 +++++++++++++++++---------------
1 file changed, 43 insertions(+), 39 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 22581952b4fd..a0ca34b29615 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -86,10 +86,6 @@
* - 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
@@ -107,6 +103,13 @@ enum {

static struct fbcon_display fb_display[MAX_NR_CONSOLES];

+struct fb_info *fbcon_registered_fb[FB_MAX];
+int fbcon_num_registered_fb;
+
+#define fbcon_for_each_registered_fb(i) \
+ for (i = 0; WARN_CONSOLE_UNLOCKED(), i < FB_MAX; i++) \
+ if (!fbcon_registered_fb[i]) {} else
+
static signed char con2fb_map[MAX_NR_CONSOLES];
static signed char con2fb_map_boot[MAX_NR_CONSOLES];

@@ -114,12 +117,7 @@ static struct fb_info *fbcon_info_from_console(int console)
{
WARN_CONSOLE_UNLOCKED();

- /*
- * Note that only con2fb_map is protected by the console lock,
- * registered_fb is protected by a separate mutex. This lookup can
- * therefore race.
- */
- return registered_fb[con2fb_map[console]];
+ return fbcon_registered_fb[con2fb_map[console]];
}

static int logo_lines;
@@ -516,7 +514,7 @@ static int do_fbcon_takeover(int show_logo)
{
int err, i;

- if (!num_registered_fb)
+ if (!fbcon_num_registered_fb)
return -ENODEV;

if (!show_logo)
@@ -822,7 +820,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
{
struct vc_data *vc = vc_cons[unit].d;
int oldidx = con2fb_map[unit];
- struct fb_info *info = registered_fb[newidx];
+ struct fb_info *info = fbcon_registered_fb[newidx];
struct fb_info *oldinfo = NULL;
int found, err = 0, show_logo;

@@ -840,7 +838,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
}

if (oldidx != -1)
- oldinfo = registered_fb[oldidx];
+ oldinfo = fbcon_registered_fb[oldidx];

found = search_fb_in_map(newidx);

@@ -932,13 +930,13 @@ static const char *fbcon_startup(void)
* If num_registered_fb is zero, this is a call for the dummy part.
* The frame buffer devices weren't initialized yet.
*/
- if (!num_registered_fb || info_idx == -1)
+ if (!fbcon_num_registered_fb || info_idx == -1)
return display_desc;
/*
* Instead of blindly using registered_fb[0], we use info_idx, set by
* fbcon_fb_registered();
*/
- info = registered_fb[info_idx];
+ info = fbcon_registered_fb[info_idx];
if (!info)
return NULL;

@@ -1153,9 +1151,9 @@ static void fbcon_release_all(void)
struct fb_info *info;
int i, j, mapped;

- for_each_registered_fb(i) {
+ fbcon_for_each_registered_fb(i) {
mapped = 0;
- info = registered_fb[i];
+ info = fbcon_registered_fb[i];

for (j = first_fb_vc; j <= last_fb_vc; j++) {
if (con2fb_map[j] == i) {
@@ -1182,7 +1180,7 @@ static void fbcon_deinit(struct vc_data *vc)
if (idx == -1)
goto finished;

- info = registered_fb[idx];
+ info = fbcon_registered_fb[idx];

if (!info)
goto finished;
@@ -2118,9 +2116,9 @@ static int fbcon_switch(struct vc_data *vc)
*
* info->currcon = vc->vc_num;
*/
- for_each_registered_fb(i) {
- if (registered_fb[i]->fbcon_par) {
- struct fbcon_ops *o = registered_fb[i]->fbcon_par;
+ fbcon_for_each_registered_fb(i) {
+ if (fbcon_registered_fb[i]->fbcon_par) {
+ struct fbcon_ops *o = fbcon_registered_fb[i]->fbcon_par;

o->currcon = vc->vc_num;
}
@@ -2765,7 +2763,7 @@ int fbcon_mode_deleted(struct fb_info *info,
j = con2fb_map[i];
if (j == -1)
continue;
- fb_info = registered_fb[j];
+ fb_info = fbcon_registered_fb[j];
if (fb_info != info)
continue;
p = &fb_display[i];
@@ -2821,7 +2819,7 @@ void fbcon_fb_unbind(struct fb_info *info)
set_con2fb_map(i, new_idx, 0);
}
} else {
- struct fb_info *info = registered_fb[idx];
+ struct fb_info *info = fbcon_registered_fb[idx];

/* This is sort of like set_con2fb_map, except it maps
* the consoles to no device and then releases the
@@ -2851,6 +2849,9 @@ void fbcon_fb_unregistered(struct fb_info *info)

console_lock();

+ fbcon_registered_fb[info->node] = NULL;
+ fbcon_num_registered_fb--;
+
if (deferred_takeover) {
console_unlock();
return;
@@ -2865,7 +2866,7 @@ void fbcon_fb_unregistered(struct fb_info *info)
if (idx == info_idx) {
info_idx = -1;

- for_each_registered_fb(i) {
+ fbcon_for_each_registered_fb(i) {
info_idx = i;
break;
}
@@ -2881,7 +2882,7 @@ void fbcon_fb_unregistered(struct fb_info *info)
if (primary_device == idx)
primary_device = -1;

- if (!num_registered_fb)
+ if (!fbcon_num_registered_fb)
do_unregister_con_driver(&fb_con);
console_unlock();
}
@@ -2956,6 +2957,9 @@ int fbcon_fb_registered(struct fb_info *info)
else
atomic_inc(&ignore_console_lock_warning);

+ fbcon_registered_fb[info->node] = info;
+ fbcon_num_registered_fb++;
+
idx = info->node;
fbcon_select_primary(info);

@@ -3075,9 +3079,9 @@ int fbcon_set_con2fb_map_ioctl(void __user *argp)
return -EINVAL;
if (con2fb.framebuffer >= FB_MAX)
return -EINVAL;
- if (!registered_fb[con2fb.framebuffer])
+ if (!fbcon_registered_fb[con2fb.framebuffer])
request_module("fb%d", con2fb.framebuffer);
- if (!registered_fb[con2fb.framebuffer]) {
+ if (!fbcon_registered_fb[con2fb.framebuffer]) {
return -EINVAL;
}

@@ -3144,10 +3148,10 @@ static ssize_t store_rotate(struct device *device,
console_lock();
idx = con2fb_map[fg_console];

- if (idx == -1 || registered_fb[idx] == NULL)
+ if (idx == -1 || fbcon_registered_fb[idx] == NULL)
goto err;

- info = registered_fb[idx];
+ info = fbcon_registered_fb[idx];
rotate = simple_strtoul(buf, last, 0);
fbcon_rotate(info, rotate);
err:
@@ -3166,10 +3170,10 @@ static ssize_t store_rotate_all(struct device *device,
console_lock();
idx = con2fb_map[fg_console];

- if (idx == -1 || registered_fb[idx] == NULL)
+ if (idx == -1 || fbcon_registered_fb[idx] == NULL)
goto err;

- info = registered_fb[idx];
+ info = fbcon_registered_fb[idx];
rotate = simple_strtoul(buf, last, 0);
fbcon_rotate_all(info, rotate);
err:
@@ -3186,10 +3190,10 @@ static ssize_t show_rotate(struct device *device,
console_lock();
idx = con2fb_map[fg_console];

- if (idx == -1 || registered_fb[idx] == NULL)
+ if (idx == -1 || fbcon_registered_fb[idx] == NULL)
goto err;

- info = registered_fb[idx];
+ info = fbcon_registered_fb[idx];
rotate = fbcon_get_rotate(info);
err:
console_unlock();
@@ -3206,10 +3210,10 @@ static ssize_t show_cursor_blink(struct device *device,
console_lock();
idx = con2fb_map[fg_console];

- if (idx == -1 || registered_fb[idx] == NULL)
+ if (idx == -1 || fbcon_registered_fb[idx] == NULL)
goto err;

- info = registered_fb[idx];
+ info = fbcon_registered_fb[idx];
ops = info->fbcon_par;

if (!ops)
@@ -3232,10 +3236,10 @@ static ssize_t store_cursor_blink(struct device *device,
console_lock();
idx = con2fb_map[fg_console];

- if (idx == -1 || registered_fb[idx] == NULL)
+ if (idx == -1 || fbcon_registered_fb[idx] == NULL)
goto err;

- info = registered_fb[idx];
+ info = fbcon_registered_fb[idx];

if (!info->fbcon_par)
goto err;
@@ -3295,8 +3299,8 @@ static void fbcon_register_existing_fbs(struct work_struct *work)
deferred_takeover = false;
logo_shown = FBCON_LOGO_DONTSHOW;

- for_each_registered_fb(i)
- fbcon_fb_registered(registered_fb[i]);
+ fbcon_for_each_registered_fb(i)
+ fbcon_fb_registered(fbcon_registered_fb[i]);

console_unlock();
}
--
2.33.0

2022-02-01 20:51:15

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 10/21] fb: Delete fb_info->queue

It was only used by fbcon, and that now switched to its own,
private work.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Helge Deller <[email protected]>
Cc: [email protected]
---
include/linux/fb.h | 1 -
1 file changed, 1 deletion(-)

diff --git a/include/linux/fb.h b/include/linux/fb.h
index 02f362c661c8..a8a00d2ba1f3 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -449,7 +449,6 @@ struct fb_info {
struct fb_var_screeninfo var; /* Current var */
struct fb_fix_screeninfo fix; /* Current fix */
struct fb_monspecs monspecs; /* Current Monitor specs */
- struct work_struct queue; /* Framebuffer event queue */
struct fb_pixmap pixmap; /* Image hardware mapper */
struct fb_pixmap sprite; /* Cursor hardware mapper */
struct fb_cmap cmap; /* Current cmap */
--
2.33.0

2022-02-01 20:51:23

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 17/21] fbcon: Move more code into fbcon_release

con2fb_release_oldinfo() has a bunch more kfree() calls than
fbcon_exit(), but since kfree() on NULL is harmless doing that in both
places should be ok. This is also a bit more symmetric now again with
fbcon_open also allocating the fbcon_ops structure.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Claudio Suarez <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 33 +++++++++++++-------------------
1 file changed, 13 insertions(+), 20 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index e5e8aaf6f60d..5c14e24d14a1 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -688,6 +688,18 @@ static void fbcon_release(struct fb_info *info)
unlock_fb_info(info);

module_put(info->fbops->owner);
+
+ if (info->fbcon_par) {
+ struct fbcon_ops *ops = info->fbcon_par;
+
+ fbcon_del_cursor_work(info);
+ kfree(ops->cursor_state.mask);
+ kfree(ops->cursor_data);
+ kfree(ops->cursor_src);
+ kfree(ops->fontbuffer);
+ kfree(info->fbcon_par);
+ info->fbcon_par = NULL;
+ }
}

static int fbcon_open(struct fb_info *info)
@@ -741,18 +753,10 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
static void con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
struct fb_info *newinfo)
{
- struct fbcon_ops *ops = oldinfo->fbcon_par;
int ret;

fbcon_release(oldinfo);

- fbcon_del_cursor_work(oldinfo);
- kfree(ops->cursor_state.mask);
- kfree(ops->cursor_data);
- kfree(ops->cursor_src);
- kfree(ops->fontbuffer);
- kfree(oldinfo->fbcon_par);
- oldinfo->fbcon_par = NULL;
/*
If oldinfo and newinfo are driving the same hardware,
the fb_release() method of oldinfo may attempt to
@@ -3335,19 +3339,8 @@ static void fbcon_exit(void)
}
}

- if (mapped) {
- if (info->fbcon_par) {
- struct fbcon_ops *ops = info->fbcon_par;
-
- fbcon_del_cursor_work(info);
- kfree(ops->cursor_src);
- kfree(ops->cursor_state.mask);
- kfree(info->fbcon_par);
- info->fbcon_par = NULL;
- }
-
+ if (mapped)
fbcon_release(info);
- }
}
}

--
2.33.0

2022-02-01 20:51:16

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 09/21] fbcon: Replace FBCON_FLAGS_INIT with a boolean

It's only one flag and slightly tidier code.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Claudio Suarez <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 11 +++++------
drivers/video/fbdev/core/fbcon.h | 4 +---
2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index affb40658fee..fa30e1909164 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -773,7 +773,7 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,

ops->currcon = fg_console;

- if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) {
+ if (info->fbops->fb_set_par && !ops->initialized) {
ret = info->fbops->fb_set_par(info);

if (ret)
@@ -782,7 +782,7 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
"error code %d\n", ret);
}

- ops->flags |= FBCON_FLAGS_INIT;
+ ops->initialized = true;
ops->graphics = 0;
fbcon_set_disp(info, &info->var, unit);

@@ -1101,8 +1101,7 @@ static void fbcon_init(struct vc_data *vc, int init)
* We need to do it in fbcon_init() to prevent screen corruption.
*/
if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) {
- if (info->fbops->fb_set_par &&
- !(ops->flags & FBCON_FLAGS_INIT)) {
+ if (info->fbops->fb_set_par && !ops->initialized) {
ret = info->fbops->fb_set_par(info);

if (ret)
@@ -1111,7 +1110,7 @@ static void fbcon_init(struct vc_data *vc, int init)
"error code %d\n", ret);
}

- ops->flags |= FBCON_FLAGS_INIT;
+ ops->initialized = true;
}

ops->graphics = 0;
@@ -1186,7 +1185,7 @@ static void fbcon_deinit(struct vc_data *vc)
if (con_is_visible(vc))
fbcon_del_cursor_work(info);

- ops->flags &= ~FBCON_FLAGS_INIT;
+ ops->initialized = false;
finished:

fbcon_free_font(p, free_font);
diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index dce5ce41093e..b18d0cbf73b6 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -18,8 +18,6 @@

#include <asm/io.h>

-#define FBCON_FLAGS_INIT 1
-
/*
* This is the interface between the low-level console driver and the
* low-level frame buffer device
@@ -77,7 +75,7 @@ struct fbcon_ops {
int blank_state;
int graphics;
int save_graphics; /* for debug enter/leave */
- int flags;
+ bool initialized;
int rotate;
int cur_rotate;
char *cursor_data;
--
2.33.0

2022-02-01 20:51:16

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 02/21] fbcon: Resurrect fbcon accelerated scrolling code

This reverts commit b3ec8cdf457e ("fbdev: Garbage collect fbdev
scrolling acceleration, part 1 (from TODO list)"), but with a twist:

Because distros like fedora&suse (probably more) really want to move
away from fbcon as much as possible, and don't have a need for fancy
accelerated fbcon even less, hide the code behind an option.

There's also been noises about resurrecting the scrollback code and
other pieces, so there's plenty of need for such an option it seems.

Compared to direct revert I did move functions around a bit so they're
all in one block, to minimize the number of #ifdef.

I also tried to stuff this all into a separate file, but that didn't
really look much better. I also considered duplicating fbcon_scroll()
since that's a bit meh now, but again didn't seem worth the trouble.
Maybe when we resurect more code.

And finally to shut up unused parameter warnings warnings the macros
became static inline.

References: https://lore.kernel.org/dri-devel/[email protected]/
Fixes: b3ec8cdf457e ("fbdev: Garbage collect fbdev scrolling acceleration, part 1 (from TODO list)")
Cc: Claudio Suarez <[email protected]>
Cc: <[email protected]> # v5.16+
Cc: Dave Airlie <[email protected]>
Cc: Jani Nikula <[email protected]>
Cc: Linus Torvalds <[email protected]>
Cc: Linux Fbdev development list <[email protected]>
Cc: Pavel Machek <[email protected]>
Cc: Sam Ravnborg <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Javier Martinez Canillas <[email protected]>
Cc: DRI Development <[email protected]>
Cc: Linux Kernel Mailing List <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Tomi Valkeinen <[email protected]>
Cc: Geert Uytterhoeven <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Sven Schnelle <[email protected]>
Cc: Gerd Hoffmann <[email protected]>
Signed-off-by: Daniel Vetter <[email protected]>
---
Documentation/gpu/todo.rst | 13 +-
drivers/video/console/Kconfig | 11 +
drivers/video/fbdev/core/bitblit.c | 16 +
drivers/video/fbdev/core/fbcon.c | 491 +++++++++++++++++++++++-
drivers/video/fbdev/core/fbcon.h | 59 +++
drivers/video/fbdev/core/fbcon_ccw.c | 28 +-
drivers/video/fbdev/core/fbcon_cw.c | 28 +-
drivers/video/fbdev/core/fbcon_rotate.h | 21 +
drivers/video/fbdev/core/fbcon_ud.c | 37 +-
drivers/video/fbdev/core/tileblit.c | 16 +
drivers/video/fbdev/skeletonfb.c | 12 +-
include/linux/fb.h | 2 +-
12 files changed, 701 insertions(+), 33 deletions(-)

diff --git a/Documentation/gpu/todo.rst b/Documentation/gpu/todo.rst
index da138dd39883..29506815d24a 100644
--- a/Documentation/gpu/todo.rst
+++ b/Documentation/gpu/todo.rst
@@ -303,19 +303,16 @@ Level: Advanced
Garbage collect fbdev scrolling acceleration
--------------------------------------------

-Scroll acceleration has been disabled in fbcon. Now it works as the old
-SCROLL_REDRAW mode. A ton of code was removed in fbcon.c and the hook bmove was
-removed from fbcon_ops.
-Remaining tasks:
+Scroll acceleration is disabled in fbcon by hard-wiring p->scrollmode =
+SCROLL_REDRAW. There's a ton of code this will allow us to remove:

-- a bunch of the hooks in fbcon_ops could be removed or simplified by calling
+- lots of code in fbcon.c
+
+- a bunch of the hooks in fbcon_ops, maybe the remaining hooks could be called
directly instead of the function table (with a switch on p->rotate)

- fb_copyarea is unused after this, and can be deleted from all drivers

-- after that, fb_copyarea can be deleted from fb_ops in include/linux/fb.h as
- well as cfb_copyarea
-
Note that not all acceleration code can be deleted, since clearing and cursor
support is still accelerated, which might be good candidates for further
deletion projects.
diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
index 840d9813b0bc..f83f5c755084 100644
--- a/drivers/video/console/Kconfig
+++ b/drivers/video/console/Kconfig
@@ -78,6 +78,17 @@ config FRAMEBUFFER_CONSOLE
help
Low-level framebuffer-based console driver.

+config FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+ bool "Enable legacy fbcon code for hw acceleration"
+ depends on FRAMEBUFFER_CONSOLE
+ default n
+ help
+ Only enable this options if you are in full control of machine since
+ the fbcon acceleration code is essentially unmaintained and known
+ problematic.
+
+ If unsure, select n.
+
config FRAMEBUFFER_CONSOLE_DETECT_PRIMARY
bool "Map the console to the primary display device"
depends on FRAMEBUFFER_CONSOLE
diff --git a/drivers/video/fbdev/core/bitblit.c b/drivers/video/fbdev/core/bitblit.c
index 01fae2c96965..f98e8f298bc1 100644
--- a/drivers/video/fbdev/core/bitblit.c
+++ b/drivers/video/fbdev/core/bitblit.c
@@ -43,6 +43,21 @@ static void update_attr(u8 *dst, u8 *src, int attribute,
}
}

+static void bit_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int dy, int dx, int height, int width)
+{
+ struct fb_copyarea area;
+
+ area.sx = sx * vc->vc_font.width;
+ area.sy = sy * vc->vc_font.height;
+ area.dx = dx * vc->vc_font.width;
+ area.dy = dy * vc->vc_font.height;
+ area.height = height * vc->vc_font.height;
+ area.width = width * vc->vc_font.width;
+
+ info->fbops->fb_copyarea(info, &area);
+}
+
static void bit_clear(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int height, int width)
{
@@ -378,6 +393,7 @@ static int bit_update_start(struct fb_info *info)

void fbcon_set_bitops(struct fbcon_ops *ops)
{
+ ops->bmove = bit_bmove;
ops->clear = bit_clear;
ops->putcs = bit_putcs;
ops->clear_margins = bit_clear_margins;
diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 99ecd9a6d844..2ff90061c7f3 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -1125,6 +1125,14 @@ static void fbcon_init(struct vc_data *vc, int init)

ops->graphics = 0;

+ /*
+ * No more hw acceleration for fbcon.
+ *
+ * FIXME: Garbage collect all the now dead code after sufficient time
+ * has passed.
+ */
+ p->scrollmode = SCROLL_REDRAW;
+
/*
* ++guenther: console.c:vc_allocate() relies on initializing
* vc_{cols,rows}, but we must not set those if we are only
@@ -1211,13 +1219,14 @@ static void fbcon_deinit(struct vc_data *vc)
* This system is now divided into two levels because of complications
* caused by hardware scrolling. Top level functions:
*
- * fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
+ * fbcon_bmove(), fbcon_clear(), fbcon_putc(), fbcon_clear_margins()
*
* handles y values in range [0, scr_height-1] that correspond to real
* screen positions. y_wrap shift means that first line of bitmap may be
* anywhere on this display. These functions convert lineoffsets to
* bitmap offsets and deal with the wrap-around case by splitting blits.
*
+ * fbcon_bmove_physical_8() -- These functions fast implementations
* fbcon_clear_physical_8() -- of original fbcon_XXX fns.
* fbcon_putc_physical_8() -- (font width != 8) may be added later
*
@@ -1390,6 +1399,291 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
}
}

+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+static void fbcon_redraw_move(struct vc_data *vc, struct fbcon_display *p,
+ int line, int count, int dy)
+{
+ unsigned short *s = (unsigned short *)
+ (vc->vc_origin + vc->vc_size_row * line);
+
+ while (count--) {
+ unsigned short *start = s;
+ unsigned short *le = advance_row(s, 1);
+ unsigned short c;
+ int x = 0;
+ unsigned short attr = 1;
+
+ do {
+ c = scr_readw(s);
+ if (attr != (c & 0xff00)) {
+ attr = c & 0xff00;
+ if (s > start) {
+ fbcon_putcs(vc, start, s - start,
+ dy, x);
+ x += s - start;
+ start = s;
+ }
+ }
+ console_conditional_schedule();
+ s++;
+ } while (s < le);
+ if (s > start)
+ fbcon_putcs(vc, start, s - start, dy, x);
+ console_conditional_schedule();
+ dy++;
+ }
+}
+
+static __inline__ void ywrap_up(struct vc_data *vc, int count)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fbcon_display *p = &fb_display[vc->vc_num];
+
+ p->yscroll += count;
+ if (p->yscroll >= p->vrows) /* Deal with wrap */
+ p->yscroll -= p->vrows;
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode |= FB_VMODE_YWRAP;
+ ops->update_start(info);
+ scrollback_max += count;
+ if (scrollback_max > scrollback_phys_max)
+ scrollback_max = scrollback_phys_max;
+ scrollback_current = 0;
+}
+
+static __inline__ void ywrap_down(struct vc_data *vc, int count)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fbcon_display *p = &fb_display[vc->vc_num];
+
+ p->yscroll -= count;
+ if (p->yscroll < 0) /* Deal with wrap */
+ p->yscroll += p->vrows;
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode |= FB_VMODE_YWRAP;
+ ops->update_start(info);
+ scrollback_max -= count;
+ if (scrollback_max < 0)
+ scrollback_max = 0;
+ scrollback_current = 0;
+}
+
+static __inline__ void ypan_up(struct vc_data *vc, int count)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
+
+ p->yscroll += count;
+ if (p->yscroll > p->vrows - vc->vc_rows) {
+ ops->bmove(vc, info, p->vrows - vc->vc_rows,
+ 0, 0, 0, vc->vc_rows, vc->vc_cols);
+ p->yscroll -= p->vrows - vc->vc_rows;
+ }
+
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode &= ~FB_VMODE_YWRAP;
+ ops->update_start(info);
+ fbcon_clear_margins(vc, 1);
+ scrollback_max += count;
+ if (scrollback_max > scrollback_phys_max)
+ scrollback_max = scrollback_phys_max;
+ scrollback_current = 0;
+}
+
+static __inline__ void ypan_up_redraw(struct vc_data *vc, int t, int count)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fbcon_display *p = &fb_display[vc->vc_num];
+
+ p->yscroll += count;
+
+ if (p->yscroll > p->vrows - vc->vc_rows) {
+ p->yscroll -= p->vrows - vc->vc_rows;
+ fbcon_redraw_move(vc, p, t + count, vc->vc_rows - count, t);
+ }
+
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode &= ~FB_VMODE_YWRAP;
+ ops->update_start(info);
+ fbcon_clear_margins(vc, 1);
+ scrollback_max += count;
+ if (scrollback_max > scrollback_phys_max)
+ scrollback_max = scrollback_phys_max;
+ scrollback_current = 0;
+}
+
+static __inline__ void ypan_down(struct vc_data *vc, int count)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_display *p = &fb_display[vc->vc_num];
+ struct fbcon_ops *ops = info->fbcon_par;
+
+ p->yscroll -= count;
+ if (p->yscroll < 0) {
+ ops->bmove(vc, info, 0, 0, p->vrows - vc->vc_rows,
+ 0, vc->vc_rows, vc->vc_cols);
+ p->yscroll += p->vrows - vc->vc_rows;
+ }
+
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode &= ~FB_VMODE_YWRAP;
+ ops->update_start(info);
+ fbcon_clear_margins(vc, 1);
+ scrollback_max -= count;
+ if (scrollback_max < 0)
+ scrollback_max = 0;
+ scrollback_current = 0;
+}
+
+static __inline__ void ypan_down_redraw(struct vc_data *vc, int t, int count)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fbcon_display *p = &fb_display[vc->vc_num];
+
+ p->yscroll -= count;
+
+ if (p->yscroll < 0) {
+ p->yscroll += p->vrows - vc->vc_rows;
+ fbcon_redraw_move(vc, p, t, vc->vc_rows - count, t + count);
+ }
+
+ ops->var.xoffset = 0;
+ ops->var.yoffset = p->yscroll * vc->vc_font.height;
+ ops->var.vmode &= ~FB_VMODE_YWRAP;
+ ops->update_start(info);
+ fbcon_clear_margins(vc, 1);
+ scrollback_max -= count;
+ if (scrollback_max < 0)
+ scrollback_max = 0;
+ scrollback_current = 0;
+}
+
+static void fbcon_bmove_rec(struct vc_data *vc, struct fbcon_display *p, int sy, int sx,
+ int dy, int dx, int height, int width, u_int y_break)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_ops *ops = info->fbcon_par;
+ u_int b;
+
+ if (sy < y_break && sy + height > y_break) {
+ b = y_break - sy;
+ if (dy < sy) { /* Avoid trashing self */
+ fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+ y_break);
+ fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+ height - b, width, y_break);
+ } else {
+ fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+ height - b, width, y_break);
+ fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+ y_break);
+ }
+ return;
+ }
+
+ if (dy < y_break && dy + height > y_break) {
+ b = y_break - dy;
+ if (dy < sy) { /* Avoid trashing self */
+ fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+ y_break);
+ fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+ height - b, width, y_break);
+ } else {
+ fbcon_bmove_rec(vc, p, sy + b, sx, dy + b, dx,
+ height - b, width, y_break);
+ fbcon_bmove_rec(vc, p, sy, sx, dy, dx, b, width,
+ y_break);
+ }
+ return;
+ }
+ ops->bmove(vc, info, real_y(p, sy), sx, real_y(p, dy), dx,
+ height, width);
+}
+
+static void fbcon_bmove(struct vc_data *vc, int sy, int sx, int dy, int dx,
+ int height, int width)
+{
+ struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
+ struct fbcon_display *p = &fb_display[vc->vc_num];
+
+ if (fbcon_is_inactive(vc, info))
+ return;
+
+ if (!width || !height)
+ return;
+
+ /* Split blits that cross physical y_wrap case.
+ * Pathological case involves 4 blits, better to use recursive
+ * code rather than unrolled case
+ *
+ * Recursive invocations don't need to erase the cursor over and
+ * over again, so we use fbcon_bmove_rec()
+ */
+ fbcon_bmove_rec(vc, p, sy, sx, dy, dx, height, width,
+ p->vrows - p->yscroll);
+}
+
+static void fbcon_redraw_blit(struct vc_data *vc, struct fb_info *info,
+ struct fbcon_display *p, int line, int count, int ycount)
+{
+ int offset = ycount * vc->vc_cols;
+ unsigned short *d = (unsigned short *)
+ (vc->vc_origin + vc->vc_size_row * line);
+ unsigned short *s = d + offset;
+ struct fbcon_ops *ops = info->fbcon_par;
+
+ while (count--) {
+ unsigned short *start = s;
+ unsigned short *le = advance_row(s, 1);
+ unsigned short c;
+ int x = 0;
+
+ do {
+ c = scr_readw(s);
+
+ if (c == scr_readw(d)) {
+ if (s > start) {
+ ops->bmove(vc, info, line + ycount, x,
+ line, x, 1, s-start);
+ x += s - start + 1;
+ start = s + 1;
+ } else {
+ x++;
+ start++;
+ }
+ }
+
+ scr_writew(c, d);
+ console_conditional_schedule();
+ s++;
+ d++;
+ } while (s < le);
+ if (s > start)
+ ops->bmove(vc, info, line + ycount, x, line, x, 1,
+ s-start);
+ console_conditional_schedule();
+ if (ycount > 0)
+ line++;
+ else {
+ line--;
+ /* NOTE: We subtract two lines from these pointers */
+ s -= vc->vc_size_row;
+ d -= vc->vc_size_row;
+ }
+ }
+}
+#endif
+
static void fbcon_redraw(struct vc_data *vc, struct fbcon_display *p,
int line, int count, int offset)
{
@@ -1450,6 +1744,9 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
{
struct fb_info *info = registered_fb[con2fb_map[vc->vc_num]];
struct fbcon_display *p = &fb_display[vc->vc_num];
+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+ int scroll_partial = info->flags & FBINFO_PARTIAL_PAN_OK;
+#endif

if (fbcon_is_inactive(vc, info))
return true;
@@ -1466,6 +1763,7 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
case SM_UP:
if (count > vc->vc_rows) /* Maximum realistic size */
count = vc->vc_rows;
+#ifndef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
fbcon_redraw(vc, p, t, b - t - count,
count * vc->vc_cols);
fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
@@ -1475,10 +1773,99 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
vc->vc_video_erase_char,
vc->vc_size_row * count);
return true;
+#else
+ if (logo_shown >= 0)
+ goto redraw_up;
+ switch (p->scrollmode) {
+ case SCROLL_MOVE:
+ fbcon_redraw_blit(vc, info, p, t, b - t - count,
+ count);
+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+ scr_memsetw((unsigned short *) (vc->vc_origin +
+ vc->vc_size_row *
+ (b - count)),
+ vc->vc_video_erase_char,
+ vc->vc_size_row * count);
+ return true;
+
+ case SCROLL_WRAP_MOVE:
+ if (b - t - count > 3 * vc->vc_rows >> 2) {
+ if (t > 0)
+ fbcon_bmove(vc, 0, 0, count, 0, t,
+ vc->vc_cols);
+ ywrap_up(vc, count);
+ if (vc->vc_rows - b > 0)
+ fbcon_bmove(vc, b - count, 0, b, 0,
+ vc->vc_rows - b,
+ vc->vc_cols);
+ } else if (info->flags & FBINFO_READS_FAST)
+ fbcon_bmove(vc, t + count, 0, t, 0,
+ b - t - count, vc->vc_cols);
+ else
+ goto redraw_up;
+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+ break;
+
+ case SCROLL_PAN_REDRAW:
+ if ((p->yscroll + count <=
+ 2 * (p->vrows - vc->vc_rows))
+ && ((!scroll_partial && (b - t == vc->vc_rows))
+ || (scroll_partial
+ && (b - t - count >
+ 3 * vc->vc_rows >> 2)))) {
+ if (t > 0)
+ fbcon_redraw_move(vc, p, 0, t, count);
+ ypan_up_redraw(vc, t, count);
+ if (vc->vc_rows - b > 0)
+ fbcon_redraw_move(vc, p, b,
+ vc->vc_rows - b, b);
+ } else
+ fbcon_redraw_move(vc, p, t + count, b - t - count, t);
+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+ break;
+
+ case SCROLL_PAN_MOVE:
+ if ((p->yscroll + count <=
+ 2 * (p->vrows - vc->vc_rows))
+ && ((!scroll_partial && (b - t == vc->vc_rows))
+ || (scroll_partial
+ && (b - t - count >
+ 3 * vc->vc_rows >> 2)))) {
+ if (t > 0)
+ fbcon_bmove(vc, 0, 0, count, 0, t,
+ vc->vc_cols);
+ ypan_up(vc, count);
+ if (vc->vc_rows - b > 0)
+ fbcon_bmove(vc, b - count, 0, b, 0,
+ vc->vc_rows - b,
+ vc->vc_cols);
+ } else if (info->flags & FBINFO_READS_FAST)
+ fbcon_bmove(vc, t + count, 0, t, 0,
+ b - t - count, vc->vc_cols);
+ else
+ goto redraw_up;
+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+ break;
+
+ case SCROLL_REDRAW:
+ redraw_up:
+ fbcon_redraw(vc, p, t, b - t - count,
+ count * vc->vc_cols);
+ fbcon_clear(vc, b - count, 0, count, vc->vc_cols);
+ scr_memsetw((unsigned short *) (vc->vc_origin +
+ vc->vc_size_row *
+ (b - count)),
+ vc->vc_video_erase_char,
+ vc->vc_size_row * count);
+ return true;
+ }
+ break;
+#endif

case SM_DOWN:
if (count > vc->vc_rows) /* Maximum realistic size */
count = vc->vc_rows;
+#ifndef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
fbcon_redraw(vc, p, b - 1, b - t - count,
-count * vc->vc_cols);
fbcon_clear(vc, t, 0, count, vc->vc_cols);
@@ -1488,10 +1875,96 @@ static bool fbcon_scroll(struct vc_data *vc, unsigned int t, unsigned int b,
vc->vc_video_erase_char,
vc->vc_size_row * count);
return true;
+#else
+ if (logo_shown >= 0)
+ goto redraw_down;
+ switch (p->scrollmode) {
+ case SCROLL_MOVE:
+ fbcon_redraw_blit(vc, info, p, b - 1, b - t - count,
+ -count);
+ fbcon_clear(vc, t, 0, count, vc->vc_cols);
+ scr_memsetw((unsigned short *) (vc->vc_origin +
+ vc->vc_size_row *
+ t),
+ vc->vc_video_erase_char,
+ vc->vc_size_row * count);
+ return true;
+
+ case SCROLL_WRAP_MOVE:
+ if (b - t - count > 3 * vc->vc_rows >> 2) {
+ if (vc->vc_rows - b > 0)
+ fbcon_bmove(vc, b, 0, b - count, 0,
+ vc->vc_rows - b,
+ vc->vc_cols);
+ ywrap_down(vc, count);
+ if (t > 0)
+ fbcon_bmove(vc, count, 0, 0, 0, t,
+ vc->vc_cols);
+ } else if (info->flags & FBINFO_READS_FAST)
+ fbcon_bmove(vc, t, 0, t + count, 0,
+ b - t - count, vc->vc_cols);
+ else
+ goto redraw_down;
+ fbcon_clear(vc, t, 0, count, vc->vc_cols);
+ break;
+
+ case SCROLL_PAN_MOVE:
+ if ((count - p->yscroll <= p->vrows - vc->vc_rows)
+ && ((!scroll_partial && (b - t == vc->vc_rows))
+ || (scroll_partial
+ && (b - t - count >
+ 3 * vc->vc_rows >> 2)))) {
+ if (vc->vc_rows - b > 0)
+ fbcon_bmove(vc, b, 0, b - count, 0,
+ vc->vc_rows - b,
+ vc->vc_cols);
+ ypan_down(vc, count);
+ if (t > 0)
+ fbcon_bmove(vc, count, 0, 0, 0, t,
+ vc->vc_cols);
+ } else if (info->flags & FBINFO_READS_FAST)
+ fbcon_bmove(vc, t, 0, t + count, 0,
+ b - t - count, vc->vc_cols);
+ else
+ goto redraw_down;
+ fbcon_clear(vc, t, 0, count, vc->vc_cols);
+ break;
+
+ case SCROLL_PAN_REDRAW:
+ if ((count - p->yscroll <= p->vrows - vc->vc_rows)
+ && ((!scroll_partial && (b - t == vc->vc_rows))
+ || (scroll_partial
+ && (b - t - count >
+ 3 * vc->vc_rows >> 2)))) {
+ if (vc->vc_rows - b > 0)
+ fbcon_redraw_move(vc, p, b, vc->vc_rows - b,
+ b - count);
+ ypan_down_redraw(vc, t, count);
+ if (t > 0)
+ fbcon_redraw_move(vc, p, count, t, 0);
+ } else
+ fbcon_redraw_move(vc, p, t, b - t - count, t + count);
+ fbcon_clear(vc, t, 0, count, vc->vc_cols);
+ break;
+
+ case SCROLL_REDRAW:
+ redraw_down:
+ fbcon_redraw(vc, p, b - 1, b - t - count,
+ -count * vc->vc_cols);
+ fbcon_clear(vc, t, 0, count, vc->vc_cols);
+ scr_memsetw((unsigned short *) (vc->vc_origin +
+ vc->vc_size_row *
+ t),
+ vc->vc_video_erase_char,
+ vc->vc_size_row * count);
+ return true;
+ }
+#endif
}
return false;
}

+
static void updatescrollmode(struct fbcon_display *p,
struct fb_info *info,
struct vc_data *vc)
@@ -1664,7 +2137,21 @@ static int fbcon_switch(struct vc_data *vc)

updatescrollmode(p, info, vc);

- scrollback_phys_max = 0;
+ switch (p->scrollmode) {
+ case SCROLL_WRAP_MOVE:
+ scrollback_phys_max = p->vrows - vc->vc_rows;
+ break;
+ case SCROLL_PAN_MOVE:
+ case SCROLL_PAN_REDRAW:
+ scrollback_phys_max = p->vrows - 2 * vc->vc_rows;
+ if (scrollback_phys_max < 0)
+ scrollback_phys_max = 0;
+ break;
+ default:
+ scrollback_phys_max = 0;
+ break;
+ }
+
scrollback_max = 0;
scrollback_current = 0;

diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
index a00603b4451a..5246d0f2574b 100644
--- a/drivers/video/fbdev/core/fbcon.h
+++ b/drivers/video/fbdev/core/fbcon.h
@@ -29,6 +29,7 @@ struct fbcon_display {
/* Filled in by the low-level console driver */
const u_char *fontdata;
int userfont; /* != 0 if fontdata kmalloc()ed */
+ u_short scrollmode; /* Scroll Method */
u_short inverse; /* != 0 text black on white as default */
short yscroll; /* Hardware scrolling */
int vrows; /* number of virtual rows */
@@ -51,6 +52,8 @@ struct fbcon_display {
};

struct fbcon_ops {
+ void (*bmove)(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int dy, int dx, int height, int width);
void (*clear)(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int height, int width);
void (*putcs)(struct vc_data *vc, struct fb_info *info,
@@ -149,6 +152,62 @@ static inline int attr_col_ec(int shift, struct vc_data *vc,
#define attr_bgcol_ec(bgshift, vc, info) attr_col_ec(bgshift, vc, info, 0)
#define attr_fgcol_ec(fgshift, vc, info) attr_col_ec(fgshift, vc, info, 1)

+ /*
+ * Scroll Method
+ */
+
+/* There are several methods fbcon can use to move text around the screen:
+ *
+ * Operation Pan Wrap
+ *---------------------------------------------
+ * SCROLL_MOVE copyarea No No
+ * SCROLL_PAN_MOVE copyarea Yes No
+ * SCROLL_WRAP_MOVE copyarea No Yes
+ * SCROLL_REDRAW imageblit No No
+ * SCROLL_PAN_REDRAW imageblit Yes No
+ * SCROLL_WRAP_REDRAW imageblit No Yes
+ *
+ * (SCROLL_WRAP_REDRAW is not implemented yet)
+ *
+ * In general, fbcon will choose the best scrolling
+ * method based on the rule below:
+ *
+ * Pan/Wrap > accel imageblit > accel copyarea >
+ * soft imageblit > (soft copyarea)
+ *
+ * Exception to the rule: Pan + accel copyarea is
+ * preferred over Pan + accel imageblit.
+ *
+ * The above is typical for PCI/AGP cards. Unless
+ * overridden, fbcon will never use soft copyarea.
+ *
+ * If you need to override the above rule, set the
+ * appropriate flags in fb_info->flags. For example,
+ * to prefer copyarea over imageblit, set
+ * FBINFO_READS_FAST.
+ *
+ * Other notes:
+ * + use the hardware engine to move the text
+ * (hw-accelerated copyarea() and fillrect())
+ * + use hardware-supported panning on a large virtual screen
+ * + amifb can not only pan, but also wrap the display by N lines
+ * (i.e. visible line i = physical line (i+N) % yres).
+ * + read what's already rendered on the screen and
+ * write it in a different place (this is cfb_copyarea())
+ * + re-render the text to the screen
+ *
+ * Whether to use wrapping or panning can only be figured out at
+ * runtime (when we know whether our font height is a multiple
+ * of the pan/wrap step)
+ *
+ */
+
+#define SCROLL_MOVE 0x001
+#define SCROLL_PAN_MOVE 0x002
+#define SCROLL_WRAP_MOVE 0x003
+#define SCROLL_REDRAW 0x004
+#define SCROLL_PAN_REDRAW 0x005
+
#ifdef CONFIG_FB_TILEBLITTING
extern void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info);
#endif
diff --git a/drivers/video/fbdev/core/fbcon_ccw.c b/drivers/video/fbdev/core/fbcon_ccw.c
index ffa78936eaab..9cd2c4b05c32 100644
--- a/drivers/video/fbdev/core/fbcon_ccw.c
+++ b/drivers/video/fbdev/core/fbcon_ccw.c
@@ -59,12 +59,31 @@ static void ccw_update_attr(u8 *dst, u8 *src, int attribute,
}
}

+
+static void ccw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int dy, int dx, int height, int width)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fb_copyarea area;
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+
+ area.sx = sy * vc->vc_font.height;
+ area.sy = vyres - ((sx + width) * vc->vc_font.width);
+ area.dx = dy * vc->vc_font.height;
+ area.dy = vyres - ((dx + width) * vc->vc_font.width);
+ area.width = height * vc->vc_font.height;
+ area.height = width * vc->vc_font.width;
+
+ info->fbops->fb_copyarea(info, &area);
+}
+
static void ccw_clear(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int height, int width)
{
+ struct fbcon_ops *ops = info->fbcon_par;
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- u32 vyres = info->var.yres;
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);

region.color = attr_bgcol_ec(bgshift,vc,info);
region.dx = sy * vc->vc_font.height;
@@ -121,7 +140,7 @@ static void ccw_putcs(struct vc_data *vc, struct fb_info *info,
u32 cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
u8 *dst, *buf = NULL;
- u32 vyres = info->var.yres;
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);

if (!ops->fontbuffer)
return;
@@ -210,7 +229,7 @@ static void ccw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
char *src;
- u32 vyres = info->var.yres;
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);

if (!ops->fontbuffer)
return;
@@ -368,7 +387,7 @@ static int ccw_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
u32 yoffset;
- u32 vyres = info->var.yres;
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
int err;

yoffset = (vyres - info->var.yres) - ops->var.xoffset;
@@ -383,6 +402,7 @@ static int ccw_update_start(struct fb_info *info)

void fbcon_rotate_ccw(struct fbcon_ops *ops)
{
+ ops->bmove = ccw_bmove;
ops->clear = ccw_clear;
ops->putcs = ccw_putcs;
ops->clear_margins = ccw_clear_margins;
diff --git a/drivers/video/fbdev/core/fbcon_cw.c b/drivers/video/fbdev/core/fbcon_cw.c
index 92e5b7fb51ee..88d89fad3f05 100644
--- a/drivers/video/fbdev/core/fbcon_cw.c
+++ b/drivers/video/fbdev/core/fbcon_cw.c
@@ -44,12 +44,31 @@ static void cw_update_attr(u8 *dst, u8 *src, int attribute,
}
}

+
+static void cw_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int dy, int dx, int height, int width)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fb_copyarea area;
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
+
+ area.sx = vxres - ((sy + height) * vc->vc_font.height);
+ area.sy = sx * vc->vc_font.width;
+ area.dx = vxres - ((dy + height) * vc->vc_font.height);
+ area.dy = dx * vc->vc_font.width;
+ area.width = height * vc->vc_font.height;
+ area.height = width * vc->vc_font.width;
+
+ info->fbops->fb_copyarea(info, &area);
+}
+
static void cw_clear(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int height, int width)
{
+ struct fbcon_ops *ops = info->fbcon_par;
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- u32 vxres = info->var.xres;
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);

region.color = attr_bgcol_ec(bgshift,vc,info);
region.dx = vxres - ((sy + height) * vc->vc_font.height);
@@ -106,7 +125,7 @@ static void cw_putcs(struct vc_data *vc, struct fb_info *info,
u32 cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
u8 *dst, *buf = NULL;
- u32 vxres = info->var.xres;
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);

if (!ops->fontbuffer)
return;
@@ -193,7 +212,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
char *src;
- u32 vxres = info->var.xres;
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);

if (!ops->fontbuffer)
return;
@@ -350,7 +369,7 @@ static void cw_cursor(struct vc_data *vc, struct fb_info *info, int mode,
static int cw_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
- u32 vxres = info->var.xres;
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
u32 xoffset;
int err;

@@ -366,6 +385,7 @@ static int cw_update_start(struct fb_info *info)

void fbcon_rotate_cw(struct fbcon_ops *ops)
{
+ ops->bmove = cw_bmove;
ops->clear = cw_clear;
ops->putcs = cw_putcs;
ops->clear_margins = cw_clear_margins;
diff --git a/drivers/video/fbdev/core/fbcon_rotate.h b/drivers/video/fbdev/core/fbcon_rotate.h
index b528b2e54283..21cb81615883 100644
--- a/drivers/video/fbdev/core/fbcon_rotate.h
+++ b/drivers/video/fbdev/core/fbcon_rotate.h
@@ -11,6 +11,27 @@
#ifndef _FBCON_ROTATE_H
#define _FBCON_ROTATE_H

+#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
+#define GETVYRES(s,i) ({ \
+ (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \
+ (i)->var.yres : (i)->var.yres_virtual; })
+
+#define GETVXRES(s,i) ({ \
+ (s == SCROLL_REDRAW || s == SCROLL_MOVE || !(i)->fix.xpanstep) ? \
+ (i)->var.xres : (i)->var.xres_virtual; })
+#else
+static inline u32 GETVYRES(int s, struct fb_info *i)
+{
+ return i->var.yres;
+}
+
+static inline u32 GETVXRES(int s, struct fb_info *i)
+{
+ return i->var.xres;
+}
+#endif
+
+
static inline int pattern_test_bit(u32 x, u32 y, u32 pitch, const char *pat)
{
u32 tmp = (y * pitch) + x, index = tmp / 8, bit = tmp % 8;
diff --git a/drivers/video/fbdev/core/fbcon_ud.c b/drivers/video/fbdev/core/fbcon_ud.c
index 09619bd8e021..8d5e66b1bdfb 100644
--- a/drivers/video/fbdev/core/fbcon_ud.c
+++ b/drivers/video/fbdev/core/fbcon_ud.c
@@ -44,13 +44,33 @@ static void ud_update_attr(u8 *dst, u8 *src, int attribute,
}
}

+
+static void ud_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int dy, int dx, int height, int width)
+{
+ struct fbcon_ops *ops = info->fbcon_par;
+ struct fb_copyarea area;
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
+
+ area.sy = vyres - ((sy + height) * vc->vc_font.height);
+ area.sx = vxres - ((sx + width) * vc->vc_font.width);
+ area.dy = vyres - ((dy + height) * vc->vc_font.height);
+ area.dx = vxres - ((dx + width) * vc->vc_font.width);
+ area.height = height * vc->vc_font.height;
+ area.width = width * vc->vc_font.width;
+
+ info->fbops->fb_copyarea(info, &area);
+}
+
static void ud_clear(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int height, int width)
{
+ struct fbcon_ops *ops = info->fbcon_par;
struct fb_fillrect region;
int bgshift = (vc->vc_hi_font_mask) ? 13 : 12;
- u32 vyres = info->var.yres;
- u32 vxres = info->var.xres;
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);

region.color = attr_bgcol_ec(bgshift,vc,info);
region.dy = vyres - ((sy + height) * vc->vc_font.height);
@@ -142,8 +162,8 @@ static void ud_putcs(struct vc_data *vc, struct fb_info *info,
u32 mod = vc->vc_font.width % 8, cnt, pitch, size;
u32 attribute = get_attribute(info, scr_readw(s));
u8 *dst, *buf = NULL;
- u32 vyres = info->var.yres;
- u32 vxres = info->var.xres;
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);

if (!ops->fontbuffer)
return;
@@ -239,8 +259,8 @@ static void ud_cursor(struct vc_data *vc, struct fb_info *info, int mode,
int attribute, use_sw = vc->vc_cursor_type & CUR_SW;
int err = 1, dx, dy;
char *src;
- u32 vyres = info->var.yres;
- u32 vxres = info->var.xres;
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);

if (!ops->fontbuffer)
return;
@@ -390,8 +410,8 @@ static int ud_update_start(struct fb_info *info)
{
struct fbcon_ops *ops = info->fbcon_par;
int xoffset, yoffset;
- u32 vyres = info->var.yres;
- u32 vxres = info->var.xres;
+ u32 vyres = GETVYRES(ops->p->scrollmode, info);
+ u32 vxres = GETVXRES(ops->p->scrollmode, info);
int err;

xoffset = vxres - info->var.xres - ops->var.xoffset;
@@ -409,6 +429,7 @@ static int ud_update_start(struct fb_info *info)

void fbcon_rotate_ud(struct fbcon_ops *ops)
{
+ ops->bmove = ud_bmove;
ops->clear = ud_clear;
ops->putcs = ud_putcs;
ops->clear_margins = ud_clear_margins;
diff --git a/drivers/video/fbdev/core/tileblit.c b/drivers/video/fbdev/core/tileblit.c
index 72af95053bcb..2768eff247ba 100644
--- a/drivers/video/fbdev/core/tileblit.c
+++ b/drivers/video/fbdev/core/tileblit.c
@@ -16,6 +16,21 @@
#include <asm/types.h>
#include "fbcon.h"

+static void tile_bmove(struct vc_data *vc, struct fb_info *info, int sy,
+ int sx, int dy, int dx, int height, int width)
+{
+ struct fb_tilearea area;
+
+ area.sx = sx;
+ area.sy = sy;
+ area.dx = dx;
+ area.dy = dy;
+ area.height = height;
+ area.width = width;
+
+ info->tileops->fb_tilecopy(info, &area);
+}
+
static void tile_clear(struct vc_data *vc, struct fb_info *info, int sy,
int sx, int height, int width)
{
@@ -118,6 +133,7 @@ void fbcon_set_tileops(struct vc_data *vc, struct fb_info *info)
struct fb_tilemap map;
struct fbcon_ops *ops = info->fbcon_par;

+ ops->bmove = tile_bmove;
ops->clear = tile_clear;
ops->putcs = tile_putcs;
ops->clear_margins = tile_clear_margins;
diff --git a/drivers/video/fbdev/skeletonfb.c b/drivers/video/fbdev/skeletonfb.c
index 0fe922f726e9..bcacfb6934fa 100644
--- a/drivers/video/fbdev/skeletonfb.c
+++ b/drivers/video/fbdev/skeletonfb.c
@@ -505,15 +505,15 @@ void xxxfb_fillrect(struct fb_info *p, const struct fb_fillrect *region)
}

/**
- * xxxfb_copyarea - OBSOLETE function.
+ * xxxfb_copyarea - REQUIRED function. Can use generic routines if
+ * non acclerated hardware and packed pixel based.
* Copies one area of the screen to another area.
- * Will be deleted in a future version
*
* @info: frame buffer structure that represents a single frame buffer
* @area: Structure providing the data to copy the framebuffer contents
* from one region to another.
*
- * This drawing operation copied a rectangular area from one area of the
+ * This drawing operation copies a rectangular area from one area of the
* screen to another area.
*/
void xxxfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
@@ -645,9 +645,9 @@ static const struct fb_ops xxxfb_ops = {
.fb_setcolreg = xxxfb_setcolreg,
.fb_blank = xxxfb_blank,
.fb_pan_display = xxxfb_pan_display,
- .fb_fillrect = xxxfb_fillrect, /* Needed !!! */
- .fb_copyarea = xxxfb_copyarea, /* Obsolete */
- .fb_imageblit = xxxfb_imageblit, /* Needed !!! */
+ .fb_fillrect = xxxfb_fillrect, /* Needed !!! */
+ .fb_copyarea = xxxfb_copyarea, /* Needed !!! */
+ .fb_imageblit = xxxfb_imageblit, /* Needed !!! */
.fb_cursor = xxxfb_cursor, /* Optional !!! */
.fb_sync = xxxfb_sync,
.fb_ioctl = xxxfb_ioctl,
diff --git a/include/linux/fb.h b/include/linux/fb.h
index 3da95842b207..02f362c661c8 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -262,7 +262,7 @@ struct fb_ops {

/* Draws a rectangle */
void (*fb_fillrect) (struct fb_info *info, const struct fb_fillrect *rect);
- /* Copy data from area to another. Obsolete. */
+ /* Copy data from area to another */
void (*fb_copyarea) (struct fb_info *info, const struct fb_copyarea *region);
/* Draws a image to the display */
void (*fb_imageblit) (struct fb_info *info, const struct fb_image *image);
--
2.33.0

2022-02-01 20:51:27

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 21/21] fbdev: Make registered_fb[] private to fbmem.c

Well except when the olpc dcon fbdev driver is enabled, that thing
digs around in there in rather unfixable ways.

Cc oldc_dcon maintainers as fyi.

Cc: Jens Frederich <[email protected]>
Cc: Jon Nettleton <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: [email protected]
Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Helge Deller <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: Sam Ravnborg <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Zhen Lei <[email protected]>
Cc: Alex Deucher <[email protected]>
Cc: Xiyu Yang <[email protected]>
Cc: [email protected]
Cc: Zheyu Ma <[email protected]>
Cc: Guenter Roeck <[email protected]>
---
drivers/video/fbdev/core/fbmem.c | 8 ++++++--
include/linux/fb.h | 7 +++----
2 files changed, 9 insertions(+), 6 deletions(-)

diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index 904ef1250677..dad6572942fa 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -48,10 +48,14 @@
static DEFINE_MUTEX(registration_lock);

struct fb_info *registered_fb[FB_MAX] __read_mostly;
-EXPORT_SYMBOL(registered_fb);
-
int num_registered_fb __read_mostly;
+#if IS_ENABLED(CONFIG_OLPC_DCON)
+EXPORT_SYMBOL(registered_fb);
EXPORT_SYMBOL(num_registered_fb);
+#endif
+#define for_each_registered_fb(i) \
+ for (i = 0; i < FB_MAX; i++) \
+ if (!registered_fb[i]) {} else

bool fb_center_logo __read_mostly;

diff --git a/include/linux/fb.h b/include/linux/fb.h
index a8a00d2ba1f3..e236817502c2 100644
--- a/include/linux/fb.h
+++ b/include/linux/fb.h
@@ -622,16 +622,15 @@ extern int fb_get_color_depth(struct fb_var_screeninfo *var,
extern int fb_get_options(const char *name, char **option);
extern int fb_new_modelist(struct fb_info *info);

+#if IS_ENABLED(CONFIG_OLPC_DCON)
extern struct fb_info *registered_fb[FB_MAX];
+
extern int num_registered_fb;
+#endif
extern bool fb_center_logo;
extern int fb_logo_count;
extern struct class *fb_class;

-#define for_each_registered_fb(i) \
- for (i = 0; i < FB_MAX; i++) \
- if (!registered_fb[i]) {} else
-
static inline void lock_fb_info(struct fb_info *info)
{
mutex_lock(&info->lock);
--
2.33.0

2022-02-01 20:52:53

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 15/21] fbcon: Consistently protect deferred_takeover with console_lock()

This shouldn't be a problem in practice since until we've actually
taken over the console there's nothing we've registered with the
console/vt subsystem, so the exit/unbind path that check this can't
do the wrong thing. But it's confusing, so fix it by moving it a tad
later.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 5 +++--
1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 496bc5f2133e..11b9f962af6f 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -3247,6 +3247,9 @@ static void fbcon_register_existing_fbs(struct work_struct *work)

console_lock();

+ deferred_takeover = false;
+ logo_shown = FBCON_LOGO_DONTSHOW;
+
for_each_registered_fb(i)
fbcon_fb_registered(registered_fb[i]);

@@ -3264,8 +3267,6 @@ static int fbcon_output_notifier(struct notifier_block *nb,
pr_info("fbcon: Taking over console\n");

dummycon_unregister_output_notifier(&fbcon_output_nb);
- deferred_takeover = false;
- logo_shown = FBCON_LOGO_DONTSHOW;

/* We may get called in atomic context */
schedule_work(&fbcon_deferred_takeover_work);
--
2.33.0

2022-02-01 20:53:01

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 04/21] fbcon: delete a few unneeded forward decl

I didn't bother with any code movement to fix the others, these just
got a bit in the way.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Helge Deller <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 13 +------------
1 file changed, 1 insertion(+), 12 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 39dc18a5de86..2a575620ef59 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -163,18 +163,7 @@ static int fbcon_cursor_noblink;
* Interface used by the world
*/

-static const char *fbcon_startup(void);
-static void fbcon_init(struct vc_data *vc, int init);
-static void fbcon_deinit(struct vc_data *vc);
-static void fbcon_clear(struct vc_data *vc, int sy, int sx, int height,
- int width);
-static void fbcon_putc(struct vc_data *vc, int c, int ypos, int xpos);
-static void fbcon_putcs(struct vc_data *vc, const unsigned short *s,
- int count, int ypos, int xpos);
static void fbcon_clear_margins(struct vc_data *vc, int bottom_only);
-static void fbcon_cursor(struct vc_data *vc, int mode);
-static int fbcon_switch(struct vc_data *vc);
-static int fbcon_blank(struct vc_data *vc, int blank, int mode_switch);
static void fbcon_set_palette(struct vc_data *vc, const unsigned char *table);

/*
@@ -184,8 +173,8 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
int unit);
static void fbcon_modechanged(struct fb_info *info);
static void fbcon_set_all_vcs(struct fb_info *info);
-static void fbcon_start(void);
static void fbcon_exit(void);
+
static struct device *fbcon_device;

#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
--
2.33.0

2022-02-01 20:56:09

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 13/21] fbcon: move more common code into fb_open()

No idea why con2fb_acquire_newinfo() initializes much less than
fbcon_startup(), but so be it. From a quick look most of the
un-initialized stuff should be fairly harmless, but who knows.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Du Cheng <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 74 +++++++++++++-------------------
1 file changed, 31 insertions(+), 43 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index b83a5a77d8a8..5a3391ff038d 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -680,8 +680,18 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)

#endif /* CONFIG_MISC_TILEBLITTING */

+static void fbcon_release(struct fb_info *info)
+{
+ if (info->fbops->fb_release)
+ info->fbops->fb_release(info, 0);
+
+ module_put(info->fbops->owner);
+}
+
static int fbcon_open(struct fb_info *info)
{
+ struct fbcon_ops *ops;
+
if (!try_module_get(info->fbops->owner))
return -ENODEV;

@@ -691,19 +701,22 @@ static int fbcon_open(struct fb_info *info)
return -ENODEV;
}

- return 0;
-}
+ ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
+ if (!ops) {
+ fbcon_release(info);
+ return -ENOMEM;
+ }

-static void fbcon_release(struct fb_info *info)
-{
- if (info->fbops->fb_release)
- info->fbops->fb_release(info, 0);
+ INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
+ ops->info = info;
+ info->fbcon_par = ops;
+ ops->cur_blink_jiffies = HZ / 5;

- module_put(info->fbops->owner);
+ return 0;
}

static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
- int unit, int oldidx)
+ int unit)
{
struct fbcon_ops *ops = NULL;
int err;
@@ -712,27 +725,10 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
if (err)
return err;

- if (!err) {
- ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
- if (!ops)
- err = -ENOMEM;
-
- INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
- }
-
- if (!err) {
- ops->cur_blink_jiffies = HZ / 5;
- ops->info = info;
- info->fbcon_par = ops;
-
- if (vc)
- set_blitting_type(vc, info);
- }
+ ops = info->fbcon_par;

- if (err) {
- con2fb_map[unit] = oldidx;
- fbcon_release(info);
- }
+ if (vc)
+ set_blitting_type(vc, info);

return err;
}
@@ -840,9 +836,11 @@ static int set_con2fb_map(int unit, int newidx, int user)

found = search_fb_in_map(newidx);

- con2fb_map[unit] = newidx;
- if (!err && !found)
- err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
+ if (!err && !found) {
+ err = con2fb_acquire_newinfo(vc, info, unit);
+ if (!err)
+ con2fb_map[unit] = newidx;
+ }

/*
* If old fb is not mapped to any of the consoles,
@@ -939,20 +937,10 @@ static const char *fbcon_startup(void)
if (fbcon_open(info))
return NULL;

- ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
- if (!ops) {
- fbcon_release(info);
- return NULL;
- }
-
- INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
-
+ ops = info->fbcon_par;
ops->currcon = -1;
ops->graphics = 1;
ops->cur_rotate = -1;
- ops->cur_blink_jiffies = HZ / 5;
- ops->info = info;
- info->fbcon_par = ops;

p->con_rotate = initial_rotation;
if (p->con_rotate == -1)
@@ -1022,7 +1010,7 @@ static void fbcon_init(struct vc_data *vc, int init)
return;

if (!info->fbcon_par)
- con2fb_acquire_newinfo(vc, info, vc->vc_num, -1);
+ con2fb_acquire_newinfo(vc, info, vc->vc_num);

/* If we are not the first console on this
fb, copy the font from that console */
--
2.33.0

2022-02-01 20:56:53

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 16/21] fbcon: Move console_lock for register/unlink/unregister

Ideally console_lock becomes an implementation detail of fbcon.c and
doesn't show up anywhere in fbmem.c. We're still pretty far from that,
but at least the register/unregister code is there now.

With this the do_fb_ioctl() handler is the only code in fbmem.c still
calling console_lock().

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Thomas Zimmermann <[email protected]>
Cc: Du Cheng <[email protected]>
Cc: Claudio Suarez <[email protected]>
Cc: Greg Kroah-Hartman <[email protected]>
Cc: Tetsuo Handa <[email protected]>
Cc: Matthew Wilcox <[email protected]>
Cc: Sam Ravnborg <[email protected]>
Cc: Zheyu Ma <[email protected]>
Cc: Guenter Roeck <[email protected]>
Cc: Alex Deucher <[email protected]>
Cc: Zhen Lei <[email protected]>
Cc: Xiyu Yang <[email protected]>
---
drivers/video/fbdev/core/fbcon.c | 33 ++++++++++++++++++++++++++------
drivers/video/fbdev/core/fbmem.c | 23 ++--------------------
2 files changed, 29 insertions(+), 27 deletions(-)

diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
index 11b9f962af6f..e5e8aaf6f60d 100644
--- a/drivers/video/fbdev/core/fbcon.c
+++ b/drivers/video/fbdev/core/fbcon.c
@@ -2776,10 +2776,12 @@ void fbcon_fb_unbind(struct fb_info *info)
int i, new_idx = -1;
int idx = info->node;

- WARN_CONSOLE_UNLOCKED();
+ console_lock();

- if (!fbcon_has_console_bind)
+ if (!fbcon_has_console_bind) {
+ console_unlock();
return;
+ }

for (i = first_fb_vc; i <= last_fb_vc; i++) {
if (con2fb_map[i] != idx &&
@@ -2814,6 +2816,8 @@ void fbcon_fb_unbind(struct fb_info *info)
}
fbcon_unbind();
}
+
+ console_unlock();
}

/* called with console_lock held */
@@ -2821,10 +2825,12 @@ void fbcon_fb_unregistered(struct fb_info *info)
{
int i, idx;

- WARN_CONSOLE_UNLOCKED();
+ console_lock();

- if (deferred_takeover)
+ if (deferred_takeover) {
+ console_unlock();
return;
+ }

idx = info->node;
for (i = first_fb_vc; i <= last_fb_vc; i++) {
@@ -2853,6 +2859,7 @@ void fbcon_fb_unregistered(struct fb_info *info)

if (!num_registered_fb)
do_unregister_con_driver(&fb_con);
+ console_unlock();
}

void fbcon_remap_all(struct fb_info *info)
@@ -2910,19 +2917,27 @@ static inline void fbcon_select_primary(struct fb_info *info)
}
#endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */

+static bool lockless_register_fb;
+module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 0400);
+MODULE_PARM_DESC(lockless_register_fb,
+ "Lockless framebuffer registration for debugging [default=off]");
+
/* called with console_lock held */
int fbcon_fb_registered(struct fb_info *info)
{
int ret = 0, i, idx;

- WARN_CONSOLE_UNLOCKED();
+ if (!lockless_register_fb)
+ console_lock();
+ else
+ atomic_inc(&ignore_console_lock_warning);

idx = info->node;
fbcon_select_primary(info);

if (deferred_takeover) {
pr_info("fbcon: Deferring console take-over\n");
- return 0;
+ goto out;
}

if (info_idx == -1) {
@@ -2942,6 +2957,12 @@ int fbcon_fb_registered(struct fb_info *info)
}
}

+out:
+ if (!lockless_register_fb)
+ console_unlock();
+ else
+ atomic_dec(&ignore_console_lock_warning);
+
return ret;
}

diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
index fd51d12f2702..904ef1250677 100644
--- a/drivers/video/fbdev/core/fbmem.c
+++ b/drivers/video/fbdev/core/fbmem.c
@@ -1573,14 +1573,9 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
}
}

-static bool lockless_register_fb;
-module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 0400);
-MODULE_PARM_DESC(lockless_register_fb,
- "Lockless framebuffer registration for debugging [default=off]");
-
static int do_register_framebuffer(struct fb_info *fb_info)
{
- int i, ret;
+ int i;
struct fb_videomode mode;

if (fb_check_foreignness(fb_info))
@@ -1649,17 +1644,7 @@ static int do_register_framebuffer(struct fb_info *fb_info)
}
#endif

- if (!lockless_register_fb)
- console_lock();
- else
- atomic_inc(&ignore_console_lock_warning);
- ret = fbcon_fb_registered(fb_info);
-
- if (!lockless_register_fb)
- console_unlock();
- else
- atomic_dec(&ignore_console_lock_warning);
- return ret;
+ return fbcon_fb_registered(fb_info);
}

static void unbind_console(struct fb_info *fb_info)
@@ -1669,9 +1654,7 @@ static void unbind_console(struct fb_info *fb_info)
if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
return;

- console_lock();
fbcon_fb_unbind(fb_info);
- console_unlock();
}

static void unlink_framebuffer(struct fb_info *fb_info)
@@ -1714,9 +1697,7 @@ static void do_unregister_framebuffer(struct fb_info *fb_info)
fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
}
#endif
- console_lock();
fbcon_fb_unregistered(fb_info);
- console_unlock();

/* this may free fb info */
put_fb_info(fb_info);
--
2.33.0

2022-02-01 20:58:56

by Daniel Vetter

[permalink] [raw]
Subject: [PATCH 07/21] fbdev/sysfs: Fix locking

fb_set_var requires we hold the fb_info lock. Or at least this now
matches what the ioctl does ...

Note that ps3fb and sh_mobile_lcdcfb are busted in different ways here,
but I will not fix them up.

Also in practice this isn't a big deal, because really variable fbdev
state is actually protected by console_lock (because fbcon just
doesn't bother with lock_fb_info() at all), and lock_fb_info
protecting anything is really just a neat lie. But that's a much
bigger fish to fry.

Signed-off-by: Daniel Vetter <[email protected]>
Cc: Helge Deller <[email protected]>
Cc: Daniel Vetter <[email protected]>
Cc: Qing Wang <[email protected]>
Cc: Sam Ravnborg <[email protected]>
---
drivers/video/fbdev/core/fbsysfs.c | 2 ++
1 file changed, 2 insertions(+)

diff --git a/drivers/video/fbdev/core/fbsysfs.c b/drivers/video/fbdev/core/fbsysfs.c
index 26892940c213..8c1ee9ecec3d 100644
--- a/drivers/video/fbdev/core/fbsysfs.c
+++ b/drivers/video/fbdev/core/fbsysfs.c
@@ -91,9 +91,11 @@ static int activate(struct fb_info *fb_info, struct fb_var_screeninfo *var)

var->activate |= FB_ACTIVATE_FORCE;
console_lock();
+ lock_fb_info(fb_info);
err = fb_set_var(fb_info, var);
if (!err)
fbcon_update_vcs(fb_info, var->activate & FB_ACTIVATE_ALL);
+ unlock_fb_info(fb_info);
console_unlock();
if (err)
return err;
--
2.33.0

2022-02-02 06:52:54

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 03/21] fbcon: Restore fbcon scrolling acceleration

On Tue, Feb 1, 2022 at 11:16 AM Helge Deller <[email protected]> wrote:
>
> On 1/31/22 22:05, Daniel Vetter wrote:
> > This functionally undoes 39aead8373b3 ("fbcon: Disable accelerated
> > scrolling"), but behind the FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
> > option.
>
> you have two trivial copy-n-paste errors in this patch which still prevent the
> console acceleration.

Duh :-(

But before we dig into details I think the big picture would be
better. I honestly don't like the #ifdef pile here that much. I wonder
whether your approach, also with GETVX/YRES adjusted somehow, wouldn't
look cleaner? Like I said in the cover letter I got mostly distracted
with fbcon locking last week, not really with this one here at all, so
maybe going with your 4 (or 2 if we squash them like I did here)
patches is neater?

Cheers, Daniel

>
> > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > index 2ff90061c7f3..39dc18a5de86 100644
> > --- a/drivers/video/fbdev/core/fbcon.c
> > +++ b/drivers/video/fbdev/core/fbcon.c
> > @@ -1125,13 +1125,15 @@ static void fbcon_init(struct vc_data *vc, int init)
> >
> > ops->graphics = 0;
> >
> > - /*
> > - * No more hw acceleration for fbcon.
> > - *
> > - * FIXME: Garbage collect all the now dead code after sufficient time
> > - * has passed.
> > - */
> > +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
>
> should be:
> #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
>
>
> > + if ((info->flags & FBINFO_HWACCEL_COPYAREA) &&
> > + !(info->flags & FBINFO_HWACCEL_DISABLED))
> > + p->scrollmode = SCROLL_MOVE;
> > + else /* default to something safe */
> > + p->scrollmode = SCROLL_REDRAW;
> > +#else
> > p->scrollmode = SCROLL_REDRAW;
> > +#endif
> >
> > /*
> > * ++guenther: console.c:vc_allocate() relies on initializing
> > @@ -1971,15 +1973,49 @@ static void updatescrollmode(struct fbcon_display *p,
> > {
> > struct fbcon_ops *ops = info->fbcon_par;
> > int fh = vc->vc_font.height;
> > + int cap = info->flags;
> > + u16 t = 0;
> > + int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
> > + info->fix.xpanstep);
> > + int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
> > int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
> > int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
> > info->var.xres_virtual);
> > + int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
> > + divides(ypan, vc->vc_font.height) && vyres > yres;
> > + int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
> > + divides(ywrap, vc->vc_font.height) &&
> > + divides(vc->vc_font.height, vyres) &&
> > + divides(vc->vc_font.height, yres);
> > + int reading_fast = cap & FBINFO_READS_FAST;
> > + int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
> > + !(cap & FBINFO_HWACCEL_DISABLED);
> > + int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
> > + !(cap & FBINFO_HWACCEL_DISABLED);
> >
> > p->vrows = vyres/fh;
> > if (yres > (fh * (vc->vc_rows + 1)))
> > p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
> > if ((yres % fh) && (vyres % fh < yres % fh))
> > p->vrows--;
> > +
> > + if (good_wrap || good_pan) {
> > + if (reading_fast || fast_copyarea)
> > + p->scrollmode = good_wrap ?
> > + SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
> > + else
> > + p->scrollmode = good_wrap ? SCROLL_REDRAW :
> > + SCROLL_PAN_REDRAW;
> > + } else {
> > + if (reading_fast || (fast_copyarea && !fast_imageblit))
> > + p->scrollmode = SCROLL_MOVE;
> > + else
> > + p->scrollmode = SCROLL_REDRAW;
> > + }
> > +
> > +#ifndef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
>
> same here... it needs to be:
> #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
>
>
> > + p->scrollmode = SCROLL_REDRAW;
> > +#endif
> > }
> >
> > #define PITCH(w) (((w) + 7) >> 3)
> >
>
> still reviewing the other patches...
>
> Helge



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

2022-02-02 06:53:27

by Helge Deller

[permalink] [raw]
Subject: Re: [PATCH 03/21] fbcon: Restore fbcon scrolling acceleration

On 2/1/22 14:45, Daniel Vetter wrote:
> On Tue, Feb 1, 2022 at 12:01 PM Helge Deller <[email protected]> wrote:
>> On 2/1/22 11:36, Daniel Vetter wrote:
>>> On Tue, Feb 1, 2022 at 11:16 AM Helge Deller <[email protected]> wrote:
>>>>
>>>> On 1/31/22 22:05, Daniel Vetter wrote:
>>>>> This functionally undoes 39aead8373b3 ("fbcon: Disable accelerated
>>>>> scrolling"), but behind the FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
>>>>> option.
>>>>
>>>> you have two trivial copy-n-paste errors in this patch which still prevent the
>>>> console acceleration.
>>>
>>> Duh :-(
>>>
>>> But before we dig into details I think the big picture would be
>>> better. I honestly don't like the #ifdef pile here that much.
>>
>> Me neither.
>> The ifdefs give a better separation, but prevents that the compiler
>> checks the various paths when building.
>>
>>> I wonder whether your approach, also with GETVX/YRES adjusted
>>> somehow, wouldn't look cleaner?
>> I think so.
>> You wouldn't even need to touch GETVX/YRES because the compiler
>> will optimize/reduce it from
>>
>> #define GETVYRES(s,i) ({ \
>> (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \
>> (i)->var.yres : (i)->var.yres_virtual; })
>>
>> to just become:
>>
>> #define GETVYRES(s,i) ((i)->var.yres)
>
> Yeah, but you need to roll out your helper to all the callsites. But
> since you #ifdef out info->scrollmode we should catch them all I
> guess.

Right. That was the only reason why I ifdef'ed it out.
Technically we don't need that ifdef.

>>> Like I said in the cover letter I got mostly distracted with fbcon
>>> locking last week, not really with this one here at all, so maybe
>>> going with your 4 (or 2 if we squash them like I did here) patches is
>>> neater?
>>
>> The benefit of my patch series was, that it could be easily backported first,
>> and then cleaned up afterwards. Even a small additional backport patch to disable
>> the fbcon acceleration for DRM in the old releases would be easy.
>> But I'm not insisting on backporting the patches, if we find good way forward.
>>
>> So, either with the 4 (or 2) patches would be OK for me (or even your approach).
>
> The idea behind the squash was that it's then impossible to backport
> without the Kconfig,

Yes, my proposal was to simply revert the 2 patches and immediatly send
the Kconfig patch to disable it again.

> and so we'll only enable this code when people
> intentionally want it. Maybe I'm too paranoid?

I think you are too paranoid :-)
If all patches incl. the Kconfig patch are backported then people shouldn't
do it wrong.

> Anyway, you feel like finishing off your approach? Or should I send
> out v2 of this with the issues fixed you spotted? Like I said either
> is fine with me.

Ok, then let me try to finish my approach until tomorrow, and then you
check if you can and want to add your locking and other patches on top of it.
In the end I leave the decision which approach to take to you.
Ok?

Helge

2022-02-02 08:56:00

by Helge Deller

[permalink] [raw]
Subject: Re: [PATCH 03/21] fbcon: Restore fbcon scrolling acceleration

On 1/31/22 22:05, Daniel Vetter wrote:
> This functionally undoes 39aead8373b3 ("fbcon: Disable accelerated
> scrolling"), but behind the FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
> option.

you have two trivial copy-n-paste errors in this patch which still prevent the
console acceleration.

> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> index 2ff90061c7f3..39dc18a5de86 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -1125,13 +1125,15 @@ static void fbcon_init(struct vc_data *vc, int init)
>
> ops->graphics = 0;
>
> - /*
> - * No more hw acceleration for fbcon.
> - *
> - * FIXME: Garbage collect all the now dead code after sufficient time
> - * has passed.
> - */
> +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION

should be:
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION


> + if ((info->flags & FBINFO_HWACCEL_COPYAREA) &&
> + !(info->flags & FBINFO_HWACCEL_DISABLED))
> + p->scrollmode = SCROLL_MOVE;
> + else /* default to something safe */
> + p->scrollmode = SCROLL_REDRAW;
> +#else
> p->scrollmode = SCROLL_REDRAW;
> +#endif
>
> /*
> * ++guenther: console.c:vc_allocate() relies on initializing
> @@ -1971,15 +1973,49 @@ static void updatescrollmode(struct fbcon_display *p,
> {
> struct fbcon_ops *ops = info->fbcon_par;
> int fh = vc->vc_font.height;
> + int cap = info->flags;
> + u16 t = 0;
> + int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
> + info->fix.xpanstep);
> + int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
> int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
> int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
> info->var.xres_virtual);
> + int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
> + divides(ypan, vc->vc_font.height) && vyres > yres;
> + int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
> + divides(ywrap, vc->vc_font.height) &&
> + divides(vc->vc_font.height, vyres) &&
> + divides(vc->vc_font.height, yres);
> + int reading_fast = cap & FBINFO_READS_FAST;
> + int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
> + !(cap & FBINFO_HWACCEL_DISABLED);
> + int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
> + !(cap & FBINFO_HWACCEL_DISABLED);
>
> p->vrows = vyres/fh;
> if (yres > (fh * (vc->vc_rows + 1)))
> p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
> if ((yres % fh) && (vyres % fh < yres % fh))
> p->vrows--;
> +
> + if (good_wrap || good_pan) {
> + if (reading_fast || fast_copyarea)
> + p->scrollmode = good_wrap ?
> + SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
> + else
> + p->scrollmode = good_wrap ? SCROLL_REDRAW :
> + SCROLL_PAN_REDRAW;
> + } else {
> + if (reading_fast || (fast_copyarea && !fast_imageblit))
> + p->scrollmode = SCROLL_MOVE;
> + else
> + p->scrollmode = SCROLL_REDRAW;
> + }
> +
> +#ifndef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION

same here... it needs to be:
#ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION


> + p->scrollmode = SCROLL_REDRAW;
> +#endif
> }
>
> #define PITCH(w) (((w) + 7) >> 3)
>

still reviewing the other patches...

Helge

2022-02-02 09:58:00

by Dave Airlie

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

On Tue, 1 Feb 2022 at 07:06, Daniel Vetter <[email protected]> wrote:
>
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin

Acked-by: Dave Airlie <[email protected]>

2022-02-02 10:41:54

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

On Mon, Jan 31, 2022 at 10:06 PM Daniel Vetter <[email protected]> wrote:
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin
>
> I think ideally we'd also record that the various firmware fb drivers
> (efifb, vesafb, ...) are also maintained in drm-misc because for the
> past few years the patches have either been to fix handover issues
> with drm drivers, or caused handover issues with drm drivers. So any
> other tree just doesn't make sense. But also, there's plenty of
> outdated MAINTAINER entries for these with people and git trees that
> haven't been active in years, so maybe let's just leave them alone.
> And furthermore distros are now adopting simpledrm as the firmware fb
> driver, so hopefully the need to care about the fbdev firmware drivers
> will go down going forward.
>
> Note that drm-misc is group maintained, I expect that to continue like
> we've done before, so no new expectations that patches all go through
> my hands. That would be silly. This also means I'm happy to put any
> other volunteer's name in the M: line, but otherwise git log says I'm
> the one who's stuck with this.

> Signed-off-by: Daniel Vetter <[email protected]>

Acked-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

2022-02-02 10:53:30

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 03/21] fbcon: Restore fbcon scrolling acceleration

On Tue, Feb 1, 2022 at 12:01 PM Helge Deller <[email protected]> wrote:
> On 2/1/22 11:36, Daniel Vetter wrote:
> > On Tue, Feb 1, 2022 at 11:16 AM Helge Deller <[email protected]> wrote:
> >>
> >> On 1/31/22 22:05, Daniel Vetter wrote:
> >>> This functionally undoes 39aead8373b3 ("fbcon: Disable accelerated
> >>> scrolling"), but behind the FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
> >>> option.
> >>
> >> you have two trivial copy-n-paste errors in this patch which still prevent the
> >> console acceleration.
> >
> > Duh :-(
> >
> > But before we dig into details I think the big picture would be
> > better. I honestly don't like the #ifdef pile here that much.
>
> Me neither.
> The ifdefs give a better separation, but prevents that the compiler
> checks the various paths when building.
>
> > I wonder whether your approach, also with GETVX/YRES adjusted
> > somehow, wouldn't look cleaner?
> I think so.
> You wouldn't even need to touch GETVX/YRES because the compiler
> will optimize/reduce it from
>
> #define GETVYRES(s,i) ({ \
> (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \
> (i)->var.yres : (i)->var.yres_virtual; })
>
> to just become:
>
> #define GETVYRES(s,i) ((i)->var.yres)

Yeah, but you need to roll out your helper to all the callsites. But
since you #ifdef out info->scrollmode we should catch them all I
guess.

> > Like I said in the cover letter I got mostly distracted with fbcon
> > locking last week, not really with this one here at all, so maybe
> > going with your 4 (or 2 if we squash them like I did here) patches is
> > neater?
>
> The benefit of my patch series was, that it could be easily backported first,
> and then cleaned up afterwards. Even a small additional backport patch to disable
> the fbcon acceleration for DRM in the old releases would be easy.
> But I'm not insisting on backporting the patches, if we find good way forward.
>
> So, either with the 4 (or 2) patches would be OK for me (or even your approach).

The idea behind the squash was that it's then impossible to backport
without the Kconfig, and so we'll only enable this code when people
intentionally want it. Maybe I'm too paranoid?

Anyway, you feel like finishing off your approach? Or should I send
out v2 of this with the issues fixed you spotted? Like I said either
is fine with me.
-Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch

2022-02-02 13:29:36

by Thomas Zimmermann

[permalink] [raw]
Subject: Re: [PATCH 09/21] fbcon: Replace FBCON_FLAGS_INIT with a boolean



Am 31.01.22 um 22:05 schrieb Daniel Vetter:
> It's only one flag and slightly tidier code.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Tetsuo Handa <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Du Cheng <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Claudio Suarez <[email protected]>

Acked-by: Thomas Zimmermann <[email protected]>

> ---
> drivers/video/fbdev/core/fbcon.c | 11 +++++------
> drivers/video/fbdev/core/fbcon.h | 4 +---
> 2 files changed, 6 insertions(+), 9 deletions(-)
>
> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> index affb40658fee..fa30e1909164 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -773,7 +773,7 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
>
> ops->currcon = fg_console;
>
> - if (info->fbops->fb_set_par && !(ops->flags & FBCON_FLAGS_INIT)) {
> + if (info->fbops->fb_set_par && !ops->initialized) {
> ret = info->fbops->fb_set_par(info);
>
> if (ret)
> @@ -782,7 +782,7 @@ static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
> "error code %d\n", ret);
> }
>
> - ops->flags |= FBCON_FLAGS_INIT;
> + ops->initialized = true;
> ops->graphics = 0;
> fbcon_set_disp(info, &info->var, unit);
>
> @@ -1101,8 +1101,7 @@ static void fbcon_init(struct vc_data *vc, int init)
> * We need to do it in fbcon_init() to prevent screen corruption.
> */
> if (con_is_visible(vc) && vc->vc_mode == KD_TEXT) {
> - if (info->fbops->fb_set_par &&
> - !(ops->flags & FBCON_FLAGS_INIT)) {
> + if (info->fbops->fb_set_par && !ops->initialized) {
> ret = info->fbops->fb_set_par(info);
>
> if (ret)
> @@ -1111,7 +1110,7 @@ static void fbcon_init(struct vc_data *vc, int init)
> "error code %d\n", ret);
> }
>
> - ops->flags |= FBCON_FLAGS_INIT;
> + ops->initialized = true;
> }
>
> ops->graphics = 0;
> @@ -1186,7 +1185,7 @@ static void fbcon_deinit(struct vc_data *vc)
> if (con_is_visible(vc))
> fbcon_del_cursor_work(info);
>
> - ops->flags &= ~FBCON_FLAGS_INIT;
> + ops->initialized = false;
> finished:
>
> fbcon_free_font(p, free_font);
> diff --git a/drivers/video/fbdev/core/fbcon.h b/drivers/video/fbdev/core/fbcon.h
> index dce5ce41093e..b18d0cbf73b6 100644
> --- a/drivers/video/fbdev/core/fbcon.h
> +++ b/drivers/video/fbdev/core/fbcon.h
> @@ -18,8 +18,6 @@
>
> #include <asm/io.h>
>
> -#define FBCON_FLAGS_INIT 1
> -
> /*
> * This is the interface between the low-level console driver and the
> * low-level frame buffer device
> @@ -77,7 +75,7 @@ struct fbcon_ops {
> int blank_state;
> int graphics;
> int save_graphics; /* for debug enter/leave */
> - int flags;
> + bool initialized;

This will add 3 bytes of padding. Maybe you can put the bool elsewhere.

> int rotate;
> int cur_rotate;
> char *cursor_data;

--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev


Attachments:
OpenPGP_signature (855.00 B)
OpenPGP digital signature

2022-02-02 14:02:34

by kernel test robot

[permalink] [raw]
Subject: Re: [Intel-gfx] [PATCH 21/21] fbdev: Make registered_fb[] private to fbmem.c

Hi Daniel,

I love your patch! Yet something to improve:

[auto build test ERROR on tegra-drm/drm/tegra/for-next]
[also build test ERROR on drm/drm-next linus/master v5.17-rc2 next-20220131]
[cannot apply to airlied/drm-next]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch]

url: https://github.com/0day-ci/linux/commits/Daniel-Vetter/some-fbcon-patches-mostly-locking/20220201-050907
base: git://anongit.freedesktop.org/tegra/linux.git drm/tegra/for-next
config: i386-allyesconfig (https://download.01.org/0day-ci/archive/20220201/[email protected]/config)
compiler: gcc-9 (Debian 9.3.0-22) 9.3.0
reproduce (this is a W=1 build):
# https://github.com/0day-ci/linux/commit/245da5ab93b17c0cf1521713d5bde655a72efb65
git remote add linux-review https://github.com/0day-ci/linux
git fetch --no-tags linux-review Daniel-Vetter/some-fbcon-patches-mostly-locking/20220201-050907
git checkout 245da5ab93b17c0cf1521713d5bde655a72efb65
# save the config file to linux build tree
mkdir build_dir
make W=1 O=build_dir ARCH=i386 SHELL=/bin/bash

If you fix the issue, kindly add following tag as appropriate
Reported-by: kernel test robot <[email protected]>

All errors (new ones prefixed by >>):

drivers/staging/olpc_dcon/olpc_dcon.c: In function 'dcon_probe':
>> drivers/staging/olpc_dcon/olpc_dcon.c:605:6: error: 'num_registered_fb' undeclared (first use in this function); did you mean 'WB_registered'?
605 | if (num_registered_fb < 1) {
| ^~~~~~~~~~~~~~~~~
| WB_registered
drivers/staging/olpc_dcon/olpc_dcon.c:605:6: note: each undeclared identifier is reported only once for each function it appears in
>> drivers/staging/olpc_dcon/olpc_dcon.c:610:17: error: 'registered_fb' undeclared (first use in this function)
610 | dcon->fbinfo = registered_fb[0];
| ^~~~~~~~~~~~~


vim +605 drivers/staging/olpc_dcon/olpc_dcon.c

53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 584
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 585 static int dcon_probe(struct i2c_client *client, const struct i2c_device_id *id)
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 586 {
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 587 struct dcon_priv *dcon;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 588 int rc, i, j;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 589
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 590 if (!pdata)
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 591 return -ENXIO;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 592
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 593 dcon = kzalloc(sizeof(*dcon), GFP_KERNEL);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 594 if (!dcon)
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 595 return -ENOMEM;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 596
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 597 dcon->client = client;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 598 init_waitqueue_head(&dcon->waitq);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 599 INIT_WORK(&dcon->switch_source, dcon_source_switch);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 600 dcon->reboot_nb.notifier_call = dcon_reboot_notify;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 601 dcon->reboot_nb.priority = -1;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 602
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 603 i2c_set_clientdata(client, dcon);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 604
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 @605 if (num_registered_fb < 1) {
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 606 dev_err(&client->dev, "DCON driver requires a registered fb\n");
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 607 rc = -EIO;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 608 goto einit;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 609 }
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 @610 dcon->fbinfo = registered_fb[0];
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 611
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 612 rc = dcon_hw_init(dcon, 1);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 613 if (rc)
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 614 goto einit;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 615
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 616 /* Add the DCON device */
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 617
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 618 dcon_device = platform_device_alloc("dcon", -1);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 619
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 620 if (!dcon_device) {
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 621 pr_err("Unable to create the DCON device\n");
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 622 rc = -ENOMEM;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 623 goto eirq;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 624 }
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 625 rc = platform_device_add(dcon_device);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 626 platform_set_drvdata(dcon_device, dcon);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 627
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 628 if (rc) {
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 629 pr_err("Unable to add the DCON device\n");
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 630 goto edev;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 631 }
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 632
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 633 for (i = 0; i < ARRAY_SIZE(dcon_device_files); i++) {
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 634 rc = device_create_file(&dcon_device->dev,
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 635 &dcon_device_files[i]);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 636 if (rc) {
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 637 dev_err(&dcon_device->dev, "Cannot create sysfs file\n");
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 638 goto ecreate;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 639 }
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 640 }
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 641
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 642 dcon->bl_val = dcon_read(dcon, DCON_REG_BRIGHT) & 0x0F;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 643
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 644 /* Add the backlight device for the DCON */
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 645 dcon_bl_props.brightness = dcon->bl_val;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 646 dcon->bl_dev = backlight_device_register("dcon-bl", &dcon_device->dev,
848d9eabcaebf21 Zebulon McCorkle 2017-11-21 647 dcon, &dcon_bl_ops,
848d9eabcaebf21 Zebulon McCorkle 2017-11-21 648 &dcon_bl_props);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 649 if (IS_ERR(dcon->bl_dev)) {
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 650 dev_err(&client->dev, "cannot register backlight dev (%ld)\n",
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 651 PTR_ERR(dcon->bl_dev));
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 652 dcon->bl_dev = NULL;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 653 }
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 654
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 655 register_reboot_notifier(&dcon->reboot_nb);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 656 atomic_notifier_chain_register(&panic_notifier_list, &dcon_panic_nb);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 657
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 658 return 0;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 659
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 660 ecreate:
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 661 for (j = 0; j < i; j++)
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 662 device_remove_file(&dcon_device->dev, &dcon_device_files[j]);
4996b4610767064 Jing Xiangfeng 2020-11-20 663 platform_device_del(dcon_device);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 664 edev:
4996b4610767064 Jing Xiangfeng 2020-11-20 665 platform_device_put(dcon_device);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 666 dcon_device = NULL;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 667 eirq:
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 668 free_irq(DCON_IRQ, dcon);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 669 einit:
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 670 kfree(dcon);
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 671 return rc;
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 672 }
53c43c5ca13328a Greg Kroah-Hartman 2016-04-04 673

---
0-DAY CI Kernel Test Service, Intel Corporation
https://lists.01.org/hyperkitty/list/[email protected]

2022-02-02 14:23:53

by Helge Deller

[permalink] [raw]
Subject: Re: [PATCH 03/21] fbcon: Restore fbcon scrolling acceleration

On 2/1/22 11:16, Helge Deller wrote:
> On 1/31/22 22:05, Daniel Vetter wrote:
>> This functionally undoes 39aead8373b3 ("fbcon: Disable accelerated
>> scrolling"), but behind the FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
>> option.
>
> you have two trivial copy-n-paste errors in this patch which still prevent the
> console acceleration.
>
>> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
>> index 2ff90061c7f3..39dc18a5de86 100644
>> --- a/drivers/video/fbdev/core/fbcon.c
>> +++ b/drivers/video/fbdev/core/fbcon.c
>> @@ -1125,13 +1125,15 @@ static void fbcon_init(struct vc_data *vc, int init)
>>
>> ops->graphics = 0;
>>
>> - /*
>> - * No more hw acceleration for fbcon.
>> - *
>> - * FIXME: Garbage collect all the now dead code after sufficient time
>> - * has passed.
>> - */
>> +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
>
> should be:
> #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
>
>
>> + if ((info->flags & FBINFO_HWACCEL_COPYAREA) &&
>> + !(info->flags & FBINFO_HWACCEL_DISABLED))
>> + p->scrollmode = SCROLL_MOVE;
>> + else /* default to something safe */
>> + p->scrollmode = SCROLL_REDRAW;
>> +#else
>> p->scrollmode = SCROLL_REDRAW;
>> +#endif
>>
>> /*
>> * ++guenther: console.c:vc_allocate() relies on initializing
>> @@ -1971,15 +1973,49 @@ static void updatescrollmode(struct fbcon_display *p,
>> {
>> struct fbcon_ops *ops = info->fbcon_par;
>> int fh = vc->vc_font.height;
>> + int cap = info->flags;
>> + u16 t = 0;
>> + int ypan = FBCON_SWAP(ops->rotate, info->fix.ypanstep,
>> + info->fix.xpanstep);
>> + int ywrap = FBCON_SWAP(ops->rotate, info->fix.ywrapstep, t);
>> int yres = FBCON_SWAP(ops->rotate, info->var.yres, info->var.xres);
>> int vyres = FBCON_SWAP(ops->rotate, info->var.yres_virtual,
>> info->var.xres_virtual);
>> + int good_pan = (cap & FBINFO_HWACCEL_YPAN) &&
>> + divides(ypan, vc->vc_font.height) && vyres > yres;
>> + int good_wrap = (cap & FBINFO_HWACCEL_YWRAP) &&
>> + divides(ywrap, vc->vc_font.height) &&
>> + divides(vc->vc_font.height, vyres) &&
>> + divides(vc->vc_font.height, yres);
>> + int reading_fast = cap & FBINFO_READS_FAST;
>> + int fast_copyarea = (cap & FBINFO_HWACCEL_COPYAREA) &&
>> + !(cap & FBINFO_HWACCEL_DISABLED);
>> + int fast_imageblit = (cap & FBINFO_HWACCEL_IMAGEBLIT) &&
>> + !(cap & FBINFO_HWACCEL_DISABLED);
>>
>> p->vrows = vyres/fh;
>> if (yres > (fh * (vc->vc_rows + 1)))
>> p->vrows -= (yres - (fh * vc->vc_rows)) / fh;
>> if ((yres % fh) && (vyres % fh < yres % fh))
>> p->vrows--;
>> +
>> + if (good_wrap || good_pan) {
>> + if (reading_fast || fast_copyarea)
>> + p->scrollmode = good_wrap ?
>> + SCROLL_WRAP_MOVE : SCROLL_PAN_MOVE;
>> + else
>> + p->scrollmode = good_wrap ? SCROLL_REDRAW :
>> + SCROLL_PAN_REDRAW;
>> + } else {
>> + if (reading_fast || (fast_copyarea && !fast_imageblit))
>> + p->scrollmode = SCROLL_MOVE;
>> + else
>> + p->scrollmode = SCROLL_REDRAW;
>> + }
>> +
>> +#ifndef CONFIG_FRAMEBUFFER_CONSOLE_ROTATION
>
> same here... it needs to be:
> #ifdef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION

actually:
#ifndef CONFIG_FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION

>
>
>> + p->scrollmode = SCROLL_REDRAW;
>> +#endif
>> }
>>
>> #define PITCH(w) (((w) + 7) >> 3)
>>
>
> still reviewing the other patches...
>
> Helge
>

2022-02-02 15:37:14

by Alex Deucher

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

Acked-by: Alex Deucher <[email protected]>

On Wed, Feb 2, 2022 at 6:31 AM Maxime Ripard <[email protected]> wrote:
>
> On Mon, Jan 31, 2022 at 10:05:32PM +0100, Daniel Vetter wrote:
> > Ever since Tomi extracted the core code in 2014 it's been defacto me
> > maintaining this, with help from others from dri-devel and sometimes
> > Linus (but those are mostly merge conflicts):
> >
> > $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> > 35 Daniel Vetter
> > 23 Linus Torvalds
> > 10 Hans de Goede
> > 9 Dave Airlie
> > 6 Peter Rosin
> >
> > I think ideally we'd also record that the various firmware fb drivers
> > (efifb, vesafb, ...) are also maintained in drm-misc because for the
> > past few years the patches have either been to fix handover issues
> > with drm drivers, or caused handover issues with drm drivers. So any
> > other tree just doesn't make sense. But also, there's plenty of
> > outdated MAINTAINER entries for these with people and git trees that
> > haven't been active in years, so maybe let's just leave them alone.
> > And furthermore distros are now adopting simpledrm as the firmware fb
> > driver, so hopefully the need to care about the fbdev firmware drivers
> > will go down going forward.
> >
> > Note that drm-misc is group maintained, I expect that to continue like
> > we've done before, so no new expectations that patches all go through
> > my hands. That would be silly. This also means I'm happy to put any
> > other volunteer's name in the M: line, but otherwise git log says I'm
> > the one who's stuck with this.
> >
> > Cc: Dave Airlie <[email protected]>
> > Cc: Jani Nikula <[email protected]>
> > Cc: Linus Torvalds <[email protected]>
> > Cc: Linux Fbdev development list <[email protected]>
> > Cc: Pavel Machek <[email protected]>
> > Cc: Sam Ravnborg <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > Cc: Javier Martinez Canillas <[email protected]>
> > Cc: DRI Development <[email protected]>
> > Cc: Linux Kernel Mailing List <[email protected]>
> > Cc: Claudio Suarez <[email protected]>
> > Cc: Tomi Valkeinen <[email protected]>
> > Cc: Geert Uytterhoeven <[email protected]>
> > Cc: Thomas Zimmermann <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Sven Schnelle <[email protected]>
> > Cc: Gerd Hoffmann <[email protected]>
> > Signed-off-by: Daniel Vetter <[email protected]>
>
> Acked-by: Maxime Ripard <[email protected]>
>
> Maxime

2022-02-02 16:14:34

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 03/21] fbcon: Restore fbcon scrolling acceleration

On Tue, Feb 1, 2022 at 3:52 PM Helge Deller <[email protected]> wrote:
>
> On 2/1/22 14:45, Daniel Vetter wrote:
> > On Tue, Feb 1, 2022 at 12:01 PM Helge Deller <[email protected]> wrote:
> >> On 2/1/22 11:36, Daniel Vetter wrote:
> >>> On Tue, Feb 1, 2022 at 11:16 AM Helge Deller <[email protected]> wrote:
> >>>>
> >>>> On 1/31/22 22:05, Daniel Vetter wrote:
> >>>>> This functionally undoes 39aead8373b3 ("fbcon: Disable accelerated
> >>>>> scrolling"), but behind the FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
> >>>>> option.
> >>>>
> >>>> you have two trivial copy-n-paste errors in this patch which still prevent the
> >>>> console acceleration.
> >>>
> >>> Duh :-(
> >>>
> >>> But before we dig into details I think the big picture would be
> >>> better. I honestly don't like the #ifdef pile here that much.
> >>
> >> Me neither.
> >> The ifdefs give a better separation, but prevents that the compiler
> >> checks the various paths when building.
> >>
> >>> I wonder whether your approach, also with GETVX/YRES adjusted
> >>> somehow, wouldn't look cleaner?
> >> I think so.
> >> You wouldn't even need to touch GETVX/YRES because the compiler
> >> will optimize/reduce it from
> >>
> >> #define GETVYRES(s,i) ({ \
> >> (s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \
> >> (i)->var.yres : (i)->var.yres_virtual; })
> >>
> >> to just become:
> >>
> >> #define GETVYRES(s,i) ((i)->var.yres)
> >
> > Yeah, but you need to roll out your helper to all the callsites. But
> > since you #ifdef out info->scrollmode we should catch them all I
> > guess.
>
> Right. That was the only reason why I ifdef'ed it out.
> Technically we don't need that ifdef.
>
> >>> Like I said in the cover letter I got mostly distracted with fbcon
> >>> locking last week, not really with this one here at all, so maybe
> >>> going with your 4 (or 2 if we squash them like I did here) patches is
> >>> neater?
> >>
> >> The benefit of my patch series was, that it could be easily backported first,
> >> and then cleaned up afterwards. Even a small additional backport patch to disable
> >> the fbcon acceleration for DRM in the old releases would be easy.
> >> But I'm not insisting on backporting the patches, if we find good way forward.
> >>
> >> So, either with the 4 (or 2) patches would be OK for me (or even your approach).
> >
> > The idea behind the squash was that it's then impossible to backport
> > without the Kconfig,
>
> Yes, my proposal was to simply revert the 2 patches and immediatly send
> the Kconfig patch to disable it again.
>
> > and so we'll only enable this code when people
> > intentionally want it. Maybe I'm too paranoid?
>
> I think you are too paranoid :-)
> If all patches incl. the Kconfig patch are backported then people shouldn't
> do it wrong.
>
> > Anyway, you feel like finishing off your approach? Or should I send
> > out v2 of this with the issues fixed you spotted? Like I said either
> > is fine with me.
>
> Ok, then let me try to finish my approach until tomorrow, and then you
> check if you can and want to add your locking and other patches on top of it.
> In the end I leave the decision which approach to take to you.
> Ok?

Sounds good, and yeah rough idea is that the maintainers + revert +
Kconfig should go in for rc3 or rc4 if we hit another bump, and the
locking stuff then in for -next (since it needs a backmerge and is
defo tricky stuff).

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

2022-02-02 16:16:24

by Greg Kroah-Hartman

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

On Tue, Feb 01, 2022 at 11:19:54AM +0100, Thomas Zimmermann wrote:
>
>
> Am 31.01.22 um 22:05 schrieb Daniel Vetter:
> > Ever since Tomi extracted the core code in 2014 it's been defacto me
> > maintaining this, with help from others from dri-devel and sometimes
> > Linus (but those are mostly merge conflicts):
> >
> > $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> > 35 Daniel Vetter
> > 23 Linus Torvalds
> > 10 Hans de Goede
> > 9 Dave Airlie
> > 6 Peter Rosin
> >
> > I think ideally we'd also record that the various firmware fb drivers
> > (efifb, vesafb, ...) are also maintained in drm-misc because for the
> > past few years the patches have either been to fix handover issues
> > with drm drivers, or caused handover issues with drm drivers. So any
> > other tree just doesn't make sense. But also, there's plenty of
> > outdated MAINTAINER entries for these with people and git trees that
> > haven't been active in years, so maybe let's just leave them alone.
> > And furthermore distros are now adopting simpledrm as the firmware fb
> > driver, so hopefully the need to care about the fbdev firmware drivers
> > will go down going forward.
> >
> > Note that drm-misc is group maintained, I expect that to continue like
> > we've done before, so no new expectations that patches all go through
> > my hands. That would be silly. This also means I'm happy to put any
> > other volunteer's name in the M: line, but otherwise git log says I'm
> > the one who's stuck with this.
> >
> > Cc: Dave Airlie <[email protected]>
> > Cc: Jani Nikula <[email protected]>
> > Cc: Linus Torvalds <[email protected]>
> > Cc: Linux Fbdev development list <[email protected]>
> > Cc: Pavel Machek <[email protected]>
> > Cc: Sam Ravnborg <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > Cc: Javier Martinez Canillas <[email protected]>
> > Cc: DRI Development <[email protected]>
> > Cc: Linux Kernel Mailing List <[email protected]>
> > Cc: Claudio Suarez <[email protected]>
> > Cc: Tomi Valkeinen <[email protected]>
> > Cc: Geert Uytterhoeven <[email protected]>
> > Cc: Thomas Zimmermann <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Sven Schnelle <[email protected]>
> > Cc: Gerd Hoffmann <[email protected]>
> > Signed-off-by: Daniel Vetter <[email protected]>
>
> Acked-by: Thomas Zimmermann <[email protected]>

Acked-by: Greg Kroah-Hartman <[email protected]>

2022-02-02 18:57:10

by Helge Deller

[permalink] [raw]
Subject: Re: [PATCH 03/21] fbcon: Restore fbcon scrolling acceleration

On 2/1/22 11:36, Daniel Vetter wrote:
> On Tue, Feb 1, 2022 at 11:16 AM Helge Deller <[email protected]> wrote:
>>
>> On 1/31/22 22:05, Daniel Vetter wrote:
>>> This functionally undoes 39aead8373b3 ("fbcon: Disable accelerated
>>> scrolling"), but behind the FRAMEBUFFER_CONSOLE_LEGACY_ACCELERATION
>>> option.
>>
>> you have two trivial copy-n-paste errors in this patch which still prevent the
>> console acceleration.
>
> Duh :-(
>
> But before we dig into details I think the big picture would be
> better. I honestly don't like the #ifdef pile here that much.

Me neither.
The ifdefs give a better separation, but prevents that the compiler
checks the various paths when building.

> I wonder whether your approach, also with GETVX/YRES adjusted
> somehow, wouldn't look cleaner?
I think so.
You wouldn't even need to touch GETVX/YRES because the compiler
will optimize/reduce it from

#define GETVYRES(s,i) ({ \
(s == SCROLL_REDRAW || s == SCROLL_MOVE) ? \
(i)->var.yres : (i)->var.yres_virtual; })

to just become:

#define GETVYRES(s,i) ((i)->var.yres)

> Like I said in the cover letter I got mostly distracted with fbcon
> locking last week, not really with this one here at all, so maybe
> going with your 4 (or 2 if we squash them like I did here) patches is
> neater?

The benefit of my patch series was, that it could be easily backported first,
and then cleaned up afterwards. Even a small additional backport patch to disable
the fbcon acceleration for DRM in the old releases would be easy.
But I'm not insisting on backporting the patches, if we find good way forward.

So, either with the 4 (or 2) patches would be OK for me (or even your approach).

Helge

2022-02-02 19:20:27

by Helge Deller

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

On 1/31/22 22:05, Daniel Vetter wrote:
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin
>
> I think ideally we'd also record that the various firmware fb drivers
> (efifb, vesafb, ...) are also maintained in drm-misc because for the
> past few years the patches have either been to fix handover issues
> with drm drivers, or caused handover issues with drm drivers. So any
> other tree just doesn't make sense. But also, there's plenty of
> outdated MAINTAINER entries for these with people and git trees that
> haven't been active in years, so maybe let's just leave them alone.
> And furthermore distros are now adopting simpledrm as the firmware fb
> driver, so hopefully the need to care about the fbdev firmware drivers
> will go down going forward.
>
> Note that drm-misc is group maintained, I expect that to continue like
> we've done before, so no new expectations that patches all go through
> my hands. That would be silly. This also means I'm happy to put any
> other volunteer's name in the M: line, but otherwise git log says I'm
> the one who's stuck with this.

Yes, agreed.

Acked-by: Helge Deller <[email protected]>

Since the code is used by drm and existing fbdev drivers,
please just make sure to not break fbdev...

Thanks!
Helge

>
> Cc: Dave Airlie <[email protected]>
> Cc: Jani Nikula <[email protected]>
> Cc: Linus Torvalds <[email protected]>
> Cc: Linux Fbdev development list <[email protected]>
> Cc: Pavel Machek <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Javier Martinez Canillas <[email protected]>
> Cc: DRI Development <[email protected]>
> Cc: Linux Kernel Mailing List <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Geert Uytterhoeven <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Sven Schnelle <[email protected]>
> Cc: Gerd Hoffmann <[email protected]>
> Signed-off-by: Daniel Vetter <[email protected]>
> ---
> MAINTAINERS | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ea3e6c914384..49809eaa3096 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7573,6 +7573,12 @@ S: Maintained
> W: http://floatingpoint.sourceforge.net/emulator/index.html
> F: arch/x86/math-emu/
>
> +FRAMEBUFFER CORE
> +M: Daniel Vetter <[email protected]>
> +F: drivers/video/fbdev/core/
> +S: Odd Fixes
> +T: git git://anongit.freedesktop.org/drm/drm-misc
> +
> FRAMEBUFFER LAYER
> M: Helge Deller <[email protected]>
> L: [email protected]
>

2022-02-02 21:32:04

by Javier Martinez Canillas

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

On 1/31/22 22:05, Daniel Vetter wrote:
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin
>
> I think ideally we'd also record that the various firmware fb drivers
> (efifb, vesafb, ...) are also maintained in drm-misc because for the
> past few years the patches have either been to fix handover issues
> with drm drivers, or caused handover issues with drm drivers. So any
> other tree just doesn't make sense. But also, there's plenty of
> outdated MAINTAINER entries for these with people and git trees that
> haven't been active in years, so maybe let's just leave them alone.
> And furthermore distros are now adopting simpledrm as the firmware fb
> driver, so hopefully the need to care about the fbdev firmware drivers
> will go down going forward.
>
> Note that drm-misc is group maintained, I expect that to continue like
> we've done before, so no new expectations that patches all go through
> my hands. That would be silly. This also means I'm happy to put any
> other volunteer's name in the M: line, but otherwise git log says I'm
> the one who's stuck with this.
>
> Cc: Dave Airlie <[email protected]>
> Cc: Jani Nikula <[email protected]>
> Cc: Linus Torvalds <[email protected]>
> Cc: Linux Fbdev development list <[email protected]>
> Cc: Pavel Machek <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Javier Martinez Canillas <[email protected]>
> Cc: DRI Development <[email protected]>
> Cc: Linux Kernel Mailing List <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Geert Uytterhoeven <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Sven Schnelle <[email protected]>
> Cc: Gerd Hoffmann <[email protected]>
> Signed-off-by: Daniel Vetter <[email protected]>
> ---

Reviewed-by: Javier Martinez Canillas <[email protected]>

Best regards,
--
Javier Martinez Canillas
Linux Engineering
Red Hat

2022-02-03 13:38:35

by Jani Nikula

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

On Mon, 31 Jan 2022, Daniel Vetter <[email protected]> wrote:
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin
>
> I think ideally we'd also record that the various firmware fb drivers
> (efifb, vesafb, ...) are also maintained in drm-misc because for the
> past few years the patches have either been to fix handover issues
> with drm drivers, or caused handover issues with drm drivers. So any
> other tree just doesn't make sense. But also, there's plenty of
> outdated MAINTAINER entries for these with people and git trees that
> haven't been active in years, so maybe let's just leave them alone.
> And furthermore distros are now adopting simpledrm as the firmware fb
> driver, so hopefully the need to care about the fbdev firmware drivers
> will go down going forward.
>
> Note that drm-misc is group maintained, I expect that to continue like
> we've done before, so no new expectations that patches all go through
> my hands. That would be silly. This also means I'm happy to put any
> other volunteer's name in the M: line, but otherwise git log says I'm
> the one who's stuck with this.
>
> Cc: Dave Airlie <[email protected]>
> Cc: Jani Nikula <[email protected]>
> Cc: Linus Torvalds <[email protected]>
> Cc: Linux Fbdev development list <[email protected]>
> Cc: Pavel Machek <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Javier Martinez Canillas <[email protected]>
> Cc: DRI Development <[email protected]>
> Cc: Linux Kernel Mailing List <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Geert Uytterhoeven <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Sven Schnelle <[email protected]>
> Cc: Gerd Hoffmann <[email protected]>
> Signed-off-by: Daniel Vetter <[email protected]>

Acked-by: Jani Nikula <[email protected]>

> ---
> MAINTAINERS | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ea3e6c914384..49809eaa3096 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7573,6 +7573,12 @@ S: Maintained
> W: http://floatingpoint.sourceforge.net/emulator/index.html
> F: arch/x86/math-emu/
>
> +FRAMEBUFFER CORE
> +M: Daniel Vetter <[email protected]>
> +F: drivers/video/fbdev/core/
> +S: Odd Fixes
> +T: git git://anongit.freedesktop.org/drm/drm-misc
> +
> FRAMEBUFFER LAYER
> M: Helge Deller <[email protected]>
> L: [email protected]

--
Jani Nikula, Intel Open Source Graphics Center

2022-02-03 15:39:46

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 09/21] fbcon: Replace FBCON_FLAGS_INIT with a boolean

On Wed, Feb 2, 2022 at 10:25 AM Thomas Zimmermann <[email protected]> wrote:
> Am 31.01.22 um 22:05 schrieb Daniel Vetter:
> > It's only one flag and slightly tidier code.
> >
> > Signed-off-by: Daniel Vetter <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Tetsuo Handa <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > Cc: Du Cheng <[email protected]>
> > Cc: Thomas Zimmermann <[email protected]>
> > Cc: Claudio Suarez <[email protected]>
>
> Acked-by: Thomas Zimmermann <[email protected]>

> > +++ b/drivers/video/fbdev/core/fbcon.h
> > @@ -18,8 +18,6 @@
> >
> > #include <asm/io.h>
> >
> > -#define FBCON_FLAGS_INIT 1
> > -
> > /*
> > * This is the interface between the low-level console driver and the
> > * low-level frame buffer device
> > @@ -77,7 +75,7 @@ struct fbcon_ops {
> > int blank_state;
> > int graphics;
> > int save_graphics; /* for debug enter/leave */
> > - int flags;
> > + bool initialized;
>
> This will add 3 bytes of padding. Maybe you can put the bool elsewhere.

Several of the int variables are used as boolean flags, too.
Perhaps convert them all to bitfields?

unsigned int initialized : 1;
...

> > int rotate;
> > int cur_rotate;
> > char *cursor_data;

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

2022-02-03 16:40:29

by Thomas Zimmermann

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core



Am 31.01.22 um 22:05 schrieb Daniel Vetter:
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin
>
> I think ideally we'd also record that the various firmware fb drivers
> (efifb, vesafb, ...) are also maintained in drm-misc because for the
> past few years the patches have either been to fix handover issues
> with drm drivers, or caused handover issues with drm drivers. So any
> other tree just doesn't make sense. But also, there's plenty of
> outdated MAINTAINER entries for these with people and git trees that
> haven't been active in years, so maybe let's just leave them alone.
> And furthermore distros are now adopting simpledrm as the firmware fb
> driver, so hopefully the need to care about the fbdev firmware drivers
> will go down going forward.
>
> Note that drm-misc is group maintained, I expect that to continue like
> we've done before, so no new expectations that patches all go through
> my hands. That would be silly. This also means I'm happy to put any
> other volunteer's name in the M: line, but otherwise git log says I'm
> the one who's stuck with this.
>
> Cc: Dave Airlie <[email protected]>
> Cc: Jani Nikula <[email protected]>
> Cc: Linus Torvalds <[email protected]>
> Cc: Linux Fbdev development list <[email protected]>
> Cc: Pavel Machek <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Javier Martinez Canillas <[email protected]>
> Cc: DRI Development <[email protected]>
> Cc: Linux Kernel Mailing List <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Geert Uytterhoeven <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Sven Schnelle <[email protected]>
> Cc: Gerd Hoffmann <[email protected]>
> Signed-off-by: Daniel Vetter <[email protected]>

Acked-by: Thomas Zimmermann <[email protected]>

> ---
> MAINTAINERS | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ea3e6c914384..49809eaa3096 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7573,6 +7573,12 @@ S: Maintained
> W: http://floatingpoint.sourceforge.net/emulator/index.html
> F: arch/x86/math-emu/
>
> +FRAMEBUFFER CORE
> +M: Daniel Vetter <[email protected]>
> +F: drivers/video/fbdev/core/
> +S: Odd Fixes
> +T: git git://anongit.freedesktop.org/drm/drm-misc
> +
> FRAMEBUFFER LAYER
> M: Helge Deller <[email protected]>
> L: [email protected]

--
Thomas Zimmermann
Graphics Driver Developer
SUSE Software Solutions Germany GmbH
Maxfeldstr. 5, 90409 Nürnberg, Germany
(HRB 36809, AG Nürnberg)
Geschäftsführer: Ivo Totev


Attachments:
OpenPGP_signature (855.00 B)
OpenPGP digital signature

2022-02-03 18:21:49

by Maxime Ripard

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

On Mon, Jan 31, 2022 at 10:05:32PM +0100, Daniel Vetter wrote:
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin
>
> I think ideally we'd also record that the various firmware fb drivers
> (efifb, vesafb, ...) are also maintained in drm-misc because for the
> past few years the patches have either been to fix handover issues
> with drm drivers, or caused handover issues with drm drivers. So any
> other tree just doesn't make sense. But also, there's plenty of
> outdated MAINTAINER entries for these with people and git trees that
> haven't been active in years, so maybe let's just leave them alone.
> And furthermore distros are now adopting simpledrm as the firmware fb
> driver, so hopefully the need to care about the fbdev firmware drivers
> will go down going forward.
>
> Note that drm-misc is group maintained, I expect that to continue like
> we've done before, so no new expectations that patches all go through
> my hands. That would be silly. This also means I'm happy to put any
> other volunteer's name in the M: line, but otherwise git log says I'm
> the one who's stuck with this.
>
> Cc: Dave Airlie <[email protected]>
> Cc: Jani Nikula <[email protected]>
> Cc: Linus Torvalds <[email protected]>
> Cc: Linux Fbdev development list <[email protected]>
> Cc: Pavel Machek <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Javier Martinez Canillas <[email protected]>
> Cc: DRI Development <[email protected]>
> Cc: Linux Kernel Mailing List <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Geert Uytterhoeven <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Sven Schnelle <[email protected]>
> Cc: Gerd Hoffmann <[email protected]>
> Signed-off-by: Daniel Vetter <[email protected]>

Acked-by: Maxime Ripard <[email protected]>

Maxime

2022-02-04 10:31:14

by Daniel Stone

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

On Mon, 31 Jan 2022 at 21:06, Daniel Vetter <[email protected]> wrote:
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin
>
> I think ideally we'd also record that the various firmware fb drivers
> (efifb, vesafb, ...) are also maintained in drm-misc because for the
> past few years the patches have either been to fix handover issues
> with drm drivers, or caused handover issues with drm drivers. So any
> other tree just doesn't make sense. But also, there's plenty of
> outdated MAINTAINER entries for these with people and git trees that
> haven't been active in years, so maybe let's just leave them alone.
> And furthermore distros are now adopting simpledrm as the firmware fb
> driver, so hopefully the need to care about the fbdev firmware drivers
> will go down going forward.
>
> Note that drm-misc is group maintained, I expect that to continue like
> we've done before, so no new expectations that patches all go through
> my hands. That would be silly. This also means I'm happy to put any
> other volunteer's name in the M: line, but otherwise git log says I'm
> the one who's stuck with this.

Acked-by: Daniel Stone <[email protected]>

2022-02-05 08:55:36

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 21/21] fbdev: Make registered_fb[] private to fbmem.c

Hi Daniel,

Thanks for your patch!

On Tue, Feb 1, 2022 at 9:50 PM Daniel Vetter <[email protected]> wrote:
> Well except when the olpc dcon fbdev driver is enabled, that thing
> digs around in there in rather unfixable ways.

Can't the actual frame buffer driver (which one?) used on olpc export
a pointer to its fb_info?

> --- a/drivers/video/fbdev/core/fbmem.c
> +++ b/drivers/video/fbdev/core/fbmem.c
> @@ -48,10 +48,14 @@
> static DEFINE_MUTEX(registration_lock);
>
> struct fb_info *registered_fb[FB_MAX] __read_mostly;
> -EXPORT_SYMBOL(registered_fb);
> -
> int num_registered_fb __read_mostly;
> +#if IS_ENABLED(CONFIG_OLPC_DCON)

CONFIG_FB_OLPC_DCON (everywhere), cfr. the build failure reported
by the robot.

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

2022-02-06 00:47:44

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 07/21] fbdev/sysfs: Fix locking

On Mon, Jan 31, 2022 at 10:05:38PM +0100, Daniel Vetter wrote:
> fb_set_var requires we hold the fb_info lock. Or at least this now
> matches what the ioctl does ...
>
> Note that ps3fb and sh_mobile_lcdcfb are busted in different ways here,
> but I will not fix them up.
>
> Also in practice this isn't a big deal, because really variable fbdev
> state is actually protected by console_lock (because fbcon just
> doesn't bother with lock_fb_info() at all), and lock_fb_info
> protecting anything is really just a neat lie. But that's a much
> bigger fish to fry.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Helge Deller <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Qing Wang <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
Acked-by: Sam Ravnborg <[email protected]>

2022-02-06 14:33:28

by Geert Uytterhoeven

[permalink] [raw]
Subject: Re: [PATCH 04/21] fbcon: delete a few unneeded forward decl

On Tue, Feb 1, 2022 at 9:50 PM Daniel Vetter <[email protected]> wrote:
> I didn't bother with any code movement to fix the others, these just
> got a bit in the way.
>
> 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

2022-02-06 20:04:06

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 12/21] fbcon: Ditch error handling for con2fb_release_oldinfo

On Mon, Jan 31, 2022 at 10:05:43PM +0100, Daniel Vetter wrote:
> It doesn't ever fail anymore.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Du Cheng <[email protected]>
> Cc: Tetsuo Handa <[email protected]>
Acked-by: Sam Ravnborg <[email protected]>

2022-02-07 09:39:47

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 13/21] fbcon: move more common code into fb_open()

On Mon, Jan 31, 2022 at 10:05:44PM +0100, Daniel Vetter wrote:
> No idea why con2fb_acquire_newinfo() initializes much less than
> fbcon_startup(), but so be it. From a quick look most of the
> un-initialized stuff should be fairly harmless, but who knows.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Tetsuo Handa <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Du Cheng <[email protected]>
> ---
> drivers/video/fbdev/core/fbcon.c | 74 +++++++++++++-------------------
> 1 file changed, 31 insertions(+), 43 deletions(-)
>
> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> index b83a5a77d8a8..5a3391ff038d 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -680,8 +680,18 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
>
> #endif /* CONFIG_MISC_TILEBLITTING */
>
> +static void fbcon_release(struct fb_info *info)
> +{
> + if (info->fbops->fb_release)
> + info->fbops->fb_release(info, 0);
> +
> + module_put(info->fbops->owner);
> +}
> +
> static int fbcon_open(struct fb_info *info)
> {
> + struct fbcon_ops *ops;
> +
> if (!try_module_get(info->fbops->owner))
> return -ENODEV;
>
> @@ -691,19 +701,22 @@ static int fbcon_open(struct fb_info *info)
> return -ENODEV;
> }
>
> - return 0;
> -}
> + ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> + if (!ops) {
> + fbcon_release(info);
> + return -ENOMEM;
> + }
>
> -static void fbcon_release(struct fb_info *info)
> -{
> - if (info->fbops->fb_release)
> - info->fbops->fb_release(info, 0);
> + INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> + ops->info = info;
> + info->fbcon_par = ops;
> + ops->cur_blink_jiffies = HZ / 5;
>
> - module_put(info->fbops->owner);
> + return 0;
> }
>
> static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> - int unit, int oldidx)
> + int unit)
> {
> struct fbcon_ops *ops = NULL;
> int err;
> @@ -712,27 +725,10 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> if (err)
> return err;
>
> - if (!err) {
> - ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> - if (!ops)
> - err = -ENOMEM;
> -
> - INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> - }
> -
> - if (!err) {
> - ops->cur_blink_jiffies = HZ / 5;
> - ops->info = info;
> - info->fbcon_par = ops;
> -
> - if (vc)
> - set_blitting_type(vc, info);
> - }
> + ops = info->fbcon_par;
>
> - if (err) {
> - con2fb_map[unit] = oldidx;
> - fbcon_release(info);
> - }
> + if (vc)
> + set_blitting_type(vc, info);
>
> return err;
> }
> @@ -840,9 +836,11 @@ static int set_con2fb_map(int unit, int newidx, int user)
>
> found = search_fb_in_map(newidx);
>
> - con2fb_map[unit] = newidx;
> - if (!err && !found)
> - err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
> + if (!err && !found) {
> + err = con2fb_acquire_newinfo(vc, info, unit);
> + if (!err)
> + con2fb_map[unit] = newidx;
> + }
This looks like an unintentional change of functionality as con2fb_map[unit] is
only assigned when we do a con2fb_acquire_newinfo().

Staring at the code I could not say it is wrong, but not nice to hide
the change in this patch.

Sam


>
> /*
> * If old fb is not mapped to any of the consoles,
> @@ -939,20 +937,10 @@ static const char *fbcon_startup(void)
> if (fbcon_open(info))
> return NULL;
>
> - ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> - if (!ops) {
> - fbcon_release(info);
> - return NULL;
> - }
> -
> - INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> -
> + ops = info->fbcon_par;
> ops->currcon = -1;
> ops->graphics = 1;
> ops->cur_rotate = -1;
> - ops->cur_blink_jiffies = HZ / 5;
> - ops->info = info;
> - info->fbcon_par = ops;
>
> p->con_rotate = initial_rotation;
> if (p->con_rotate == -1)
> @@ -1022,7 +1010,7 @@ static void fbcon_init(struct vc_data *vc, int init)
> return;
>
> if (!info->fbcon_par)
> - con2fb_acquire_newinfo(vc, info, vc->vc_num, -1);
> + con2fb_acquire_newinfo(vc, info, vc->vc_num);
>
> /* If we are not the first console on this
> fb, copy the font from that console */
> --
> 2.33.0

2022-02-07 10:14:01

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 19/21] fbcon: Maintain a private array of fb_info

Hi Daniel,

On Mon, Jan 31, 2022 at 10:05:50PM +0100, Daniel Vetter wrote:
> Accessing the one in fbmem.c without taking the right locks is a bad
> idea. Instead maintain our own private copy, which is fully protected
> by console_lock() (like everything else in fbcon.c). That copy is
> serialized through fbcon_fb_registered/unregistered() calls.

I fail to see why we can make a private copy of registered_fb
just like that - are they not somehow shared between fbcon and fbmem.
So when fbmem updates it, then fbcon will use the entry or such?

I guess I am just ignorant of how registered_fb is used - but please
explain.

Sam

>
> Also this means we do not need to hold a full fb_info reference, which
> is nice because doing so would mean a refcount loop between the
> console and the fb_info. But it's also not nice since it means
> console_lock() must be held absolutely everywhere. Well strictly
> speaking we could still try to do some refcounting games again by
> calling get_fb_info before we drop the console_lock. But things will
> get tricky.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Tetsuo Handa <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Du Cheng <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> ---
> drivers/video/fbdev/core/fbcon.c | 82 +++++++++++++++++---------------
> 1 file changed, 43 insertions(+), 39 deletions(-)
>
> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> index 22581952b4fd..a0ca34b29615 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -86,10 +86,6 @@
> * - 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
> @@ -107,6 +103,13 @@ enum {
>
> static struct fbcon_display fb_display[MAX_NR_CONSOLES];
>
> +struct fb_info *fbcon_registered_fb[FB_MAX];
> +int fbcon_num_registered_fb;
> +
> +#define fbcon_for_each_registered_fb(i) \
> + for (i = 0; WARN_CONSOLE_UNLOCKED(), i < FB_MAX; i++) \
> + if (!fbcon_registered_fb[i]) {} else
> +
> static signed char con2fb_map[MAX_NR_CONSOLES];
> static signed char con2fb_map_boot[MAX_NR_CONSOLES];
>
> @@ -114,12 +117,7 @@ static struct fb_info *fbcon_info_from_console(int console)
> {
> WARN_CONSOLE_UNLOCKED();
>
> - /*
> - * Note that only con2fb_map is protected by the console lock,
> - * registered_fb is protected by a separate mutex. This lookup can
> - * therefore race.
> - */
> - return registered_fb[con2fb_map[console]];
> + return fbcon_registered_fb[con2fb_map[console]];
> }
>
> static int logo_lines;
> @@ -516,7 +514,7 @@ static int do_fbcon_takeover(int show_logo)
> {
> int err, i;
>
> - if (!num_registered_fb)
> + if (!fbcon_num_registered_fb)
> return -ENODEV;
>
> if (!show_logo)
> @@ -822,7 +820,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
> {
> struct vc_data *vc = vc_cons[unit].d;
> int oldidx = con2fb_map[unit];
> - struct fb_info *info = registered_fb[newidx];
> + struct fb_info *info = fbcon_registered_fb[newidx];
> struct fb_info *oldinfo = NULL;
> int found, err = 0, show_logo;
>
> @@ -840,7 +838,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
> }
>
> if (oldidx != -1)
> - oldinfo = registered_fb[oldidx];
> + oldinfo = fbcon_registered_fb[oldidx];
>
> found = search_fb_in_map(newidx);
>
> @@ -932,13 +930,13 @@ static const char *fbcon_startup(void)
> * If num_registered_fb is zero, this is a call for the dummy part.
> * The frame buffer devices weren't initialized yet.
> */
> - if (!num_registered_fb || info_idx == -1)
> + if (!fbcon_num_registered_fb || info_idx == -1)
> return display_desc;
> /*
> * Instead of blindly using registered_fb[0], we use info_idx, set by
> * fbcon_fb_registered();
> */
> - info = registered_fb[info_idx];
> + info = fbcon_registered_fb[info_idx];
> if (!info)
> return NULL;
>
> @@ -1153,9 +1151,9 @@ static void fbcon_release_all(void)
> struct fb_info *info;
> int i, j, mapped;
>
> - for_each_registered_fb(i) {
> + fbcon_for_each_registered_fb(i) {
> mapped = 0;
> - info = registered_fb[i];
> + info = fbcon_registered_fb[i];
>
> for (j = first_fb_vc; j <= last_fb_vc; j++) {
> if (con2fb_map[j] == i) {
> @@ -1182,7 +1180,7 @@ static void fbcon_deinit(struct vc_data *vc)
> if (idx == -1)
> goto finished;
>
> - info = registered_fb[idx];
> + info = fbcon_registered_fb[idx];
>
> if (!info)
> goto finished;
> @@ -2118,9 +2116,9 @@ static int fbcon_switch(struct vc_data *vc)
> *
> * info->currcon = vc->vc_num;
> */
> - for_each_registered_fb(i) {
> - if (registered_fb[i]->fbcon_par) {
> - struct fbcon_ops *o = registered_fb[i]->fbcon_par;
> + fbcon_for_each_registered_fb(i) {
> + if (fbcon_registered_fb[i]->fbcon_par) {
> + struct fbcon_ops *o = fbcon_registered_fb[i]->fbcon_par;
>
> o->currcon = vc->vc_num;
> }
> @@ -2765,7 +2763,7 @@ int fbcon_mode_deleted(struct fb_info *info,
> j = con2fb_map[i];
> if (j == -1)
> continue;
> - fb_info = registered_fb[j];
> + fb_info = fbcon_registered_fb[j];
> if (fb_info != info)
> continue;
> p = &fb_display[i];
> @@ -2821,7 +2819,7 @@ void fbcon_fb_unbind(struct fb_info *info)
> set_con2fb_map(i, new_idx, 0);
> }
> } else {
> - struct fb_info *info = registered_fb[idx];
> + struct fb_info *info = fbcon_registered_fb[idx];
>
> /* This is sort of like set_con2fb_map, except it maps
> * the consoles to no device and then releases the
> @@ -2851,6 +2849,9 @@ void fbcon_fb_unregistered(struct fb_info *info)
>
> console_lock();
>
> + fbcon_registered_fb[info->node] = NULL;
> + fbcon_num_registered_fb--;
> +
> if (deferred_takeover) {
> console_unlock();
> return;
> @@ -2865,7 +2866,7 @@ void fbcon_fb_unregistered(struct fb_info *info)
> if (idx == info_idx) {
> info_idx = -1;
>
> - for_each_registered_fb(i) {
> + fbcon_for_each_registered_fb(i) {
> info_idx = i;
> break;
> }
> @@ -2881,7 +2882,7 @@ void fbcon_fb_unregistered(struct fb_info *info)
> if (primary_device == idx)
> primary_device = -1;
>
> - if (!num_registered_fb)
> + if (!fbcon_num_registered_fb)
> do_unregister_con_driver(&fb_con);
> console_unlock();
> }
> @@ -2956,6 +2957,9 @@ int fbcon_fb_registered(struct fb_info *info)
> else
> atomic_inc(&ignore_console_lock_warning);
>
> + fbcon_registered_fb[info->node] = info;
> + fbcon_num_registered_fb++;
> +
> idx = info->node;
> fbcon_select_primary(info);
>
> @@ -3075,9 +3079,9 @@ int fbcon_set_con2fb_map_ioctl(void __user *argp)
> return -EINVAL;
> if (con2fb.framebuffer >= FB_MAX)
> return -EINVAL;
> - if (!registered_fb[con2fb.framebuffer])
> + if (!fbcon_registered_fb[con2fb.framebuffer])
> request_module("fb%d", con2fb.framebuffer);
> - if (!registered_fb[con2fb.framebuffer]) {
> + if (!fbcon_registered_fb[con2fb.framebuffer]) {
> return -EINVAL;
> }
>
> @@ -3144,10 +3148,10 @@ static ssize_t store_rotate(struct device *device,
> console_lock();
> idx = con2fb_map[fg_console];
>
> - if (idx == -1 || registered_fb[idx] == NULL)
> + if (idx == -1 || fbcon_registered_fb[idx] == NULL)
> goto err;
>
> - info = registered_fb[idx];
> + info = fbcon_registered_fb[idx];
> rotate = simple_strtoul(buf, last, 0);
> fbcon_rotate(info, rotate);
> err:
> @@ -3166,10 +3170,10 @@ static ssize_t store_rotate_all(struct device *device,
> console_lock();
> idx = con2fb_map[fg_console];
>
> - if (idx == -1 || registered_fb[idx] == NULL)
> + if (idx == -1 || fbcon_registered_fb[idx] == NULL)
> goto err;
>
> - info = registered_fb[idx];
> + info = fbcon_registered_fb[idx];
> rotate = simple_strtoul(buf, last, 0);
> fbcon_rotate_all(info, rotate);
> err:
> @@ -3186,10 +3190,10 @@ static ssize_t show_rotate(struct device *device,
> console_lock();
> idx = con2fb_map[fg_console];
>
> - if (idx == -1 || registered_fb[idx] == NULL)
> + if (idx == -1 || fbcon_registered_fb[idx] == NULL)
> goto err;
>
> - info = registered_fb[idx];
> + info = fbcon_registered_fb[idx];
> rotate = fbcon_get_rotate(info);
> err:
> console_unlock();
> @@ -3206,10 +3210,10 @@ static ssize_t show_cursor_blink(struct device *device,
> console_lock();
> idx = con2fb_map[fg_console];
>
> - if (idx == -1 || registered_fb[idx] == NULL)
> + if (idx == -1 || fbcon_registered_fb[idx] == NULL)
> goto err;
>
> - info = registered_fb[idx];
> + info = fbcon_registered_fb[idx];
> ops = info->fbcon_par;
>
> if (!ops)
> @@ -3232,10 +3236,10 @@ static ssize_t store_cursor_blink(struct device *device,
> console_lock();
> idx = con2fb_map[fg_console];
>
> - if (idx == -1 || registered_fb[idx] == NULL)
> + if (idx == -1 || fbcon_registered_fb[idx] == NULL)
> goto err;
>
> - info = registered_fb[idx];
> + info = fbcon_registered_fb[idx];
>
> if (!info->fbcon_par)
> goto err;
> @@ -3295,8 +3299,8 @@ static void fbcon_register_existing_fbs(struct work_struct *work)
> deferred_takeover = false;
> logo_shown = FBCON_LOGO_DONTSHOW;
>
> - for_each_registered_fb(i)
> - fbcon_fb_registered(registered_fb[i]);
> + fbcon_for_each_registered_fb(i)
> + fbcon_fb_registered(fbcon_registered_fb[i]);
>
> console_unlock();
> }
> --
> 2.33.0

2022-02-07 11:26:46

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 11/21] fbcon: Extract fbcon_open/release helpers

Hi Daniel,

>
> > + kfree(ops->cursor_state.mask);
> > + kfree(ops->cursor_data);
> > + kfree(ops->cursor_src);
> > + kfree(ops->fontbuffer);
> > + kfree(oldinfo->fbcon_par);
> > + oldinfo->fbcon_par = NULL;
> These all look like candidates to stuff into fbcon_release()
> That would drop the nice symmetry but make it more consistent.
>
> I think we miss freeing ops->cursor_data in fbcon_exit(),
> but I did not follow all the code.

We agree as I can see this was done in a later patch.

Sam

2022-02-07 16:33:39

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

Hi Daniel,

On Mon, Jan 31, 2022 at 10:05:32PM +0100, Daniel Vetter wrote:
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin
>
> I think ideally we'd also record that the various firmware fb drivers
> (efifb, vesafb, ...) are also maintained in drm-misc because for the
> past few years the patches have either been to fix handover issues
> with drm drivers, or caused handover issues with drm drivers. So any
> other tree just doesn't make sense. But also, there's plenty of
> outdated MAINTAINER entries for these with people and git trees that
> haven't been active in years, so maybe let's just leave them alone.
> And furthermore distros are now adopting simpledrm as the firmware fb
> driver, so hopefully the need to care about the fbdev firmware drivers
> will go down going forward.
>
> Note that drm-misc is group maintained, I expect that to continue like
> we've done before, so no new expectations that patches all go through
> my hands. That would be silly. This also means I'm happy to put any
> other volunteer's name in the M: line, but otherwise git log says I'm
> the one who's stuck with this.
>
> Cc: Dave Airlie <[email protected]>
> Cc: Jani Nikula <[email protected]>
> Cc: Linus Torvalds <[email protected]>
> Cc: Linux Fbdev development list <[email protected]>
> Cc: Pavel Machek <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Javier Martinez Canillas <[email protected]>
> Cc: DRI Development <[email protected]>
> Cc: Linux Kernel Mailing List <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Geert Uytterhoeven <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Sven Schnelle <[email protected]>
> Cc: Gerd Hoffmann <[email protected]>
> Signed-off-by: Daniel Vetter <[email protected]>
> ---
> MAINTAINERS | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ea3e6c914384..49809eaa3096 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7573,6 +7573,12 @@ S: Maintained
> W: http://floatingpoint.sourceforge.net/emulator/index.html
> F: arch/x86/math-emu/
>
> +FRAMEBUFFER CORE
> +M: Daniel Vetter <[email protected]>
> +F: drivers/video/fbdev/core/

Maybe add:
include/linux/fb.h
include/uapi/linux/fb.h

Both edited within some months - so they see a little changes.

With or without this:
Acked-by: Sam Ravnborg <[email protected]>

2022-02-07 17:34:43

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 17/21] fbcon: Move more code into fbcon_release

On Mon, Jan 31, 2022 at 10:05:48PM +0100, Daniel Vetter wrote:
> con2fb_release_oldinfo() has a bunch more kfree() calls than
> fbcon_exit(), but since kfree() on NULL is harmless doing that in both
> places should be ok. This is also a bit more symmetric now again with
> fbcon_open also allocating the fbcon_ops structure.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Tetsuo Handa <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Du Cheng <[email protected]>
> Cc: Claudio Suarez <[email protected]>

Thanks, like I wrote earlier this makes sense.
Acked-by: Sam Ravnborg <[email protected]>

2022-02-07 17:52:39

by Tomi Valkeinen

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

On 31/01/2022 23:05, Daniel Vetter wrote:
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin
>
> I think ideally we'd also record that the various firmware fb drivers
> (efifb, vesafb, ...) are also maintained in drm-misc because for the
> past few years the patches have either been to fix handover issues
> with drm drivers, or caused handover issues with drm drivers. So any
> other tree just doesn't make sense. But also, there's plenty of
> outdated MAINTAINER entries for these with people and git trees that
> haven't been active in years, so maybe let's just leave them alone.
> And furthermore distros are now adopting simpledrm as the firmware fb
> driver, so hopefully the need to care about the fbdev firmware drivers
> will go down going forward.
>
> Note that drm-misc is group maintained, I expect that to continue like
> we've done before, so no new expectations that patches all go through
> my hands. That would be silly. This also means I'm happy to put any
> other volunteer's name in the M: line, but otherwise git log says I'm
> the one who's stuck with this.

Acked-by: Tomi Valkeinen <[email protected]>

Tomi


2022-02-07 19:24:44

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 18/21] fbcon: untangle fbcon_exit

Hi Daniel,

On Mon, Jan 31, 2022 at 10:05:49PM +0100, Daniel Vetter wrote:
> There's a bunch of confusions going on here:
> - The deferred fbcon setup notifier should only be cleaned up from
> fb_console_exit(), to be symmetric with fb_console_init()
> - We also need to make sure we don't race with the work, which means
> temporarily dropping the console lock (or we can deadlock)
> - That also means no point in clearing deferred_takeover, we are
> unloading everything anyway.
> - Finally rename fbcon_exit to fbcon_release_all and move it, since
> that's what's it doing when being called from consw->con_deinit
> through fbcon_deinit.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Du Cheng <[email protected]>
> Cc: Tetsuo Handa <[email protected]>
> ---
> drivers/video/fbdev/core/fbcon.c | 63 ++++++++++++++++----------------
> 1 file changed, 32 insertions(+), 31 deletions(-)
>
> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> index 5c14e24d14a1..22581952b4fd 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -185,7 +185,6 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
> int unit);
> static void fbcon_modechanged(struct fb_info *info);
> static void fbcon_set_all_vcs(struct fb_info *info);
> -static void fbcon_exit(void);
>
> static struct device *fbcon_device;
>
> @@ -1149,6 +1148,27 @@ static void fbcon_free_font(struct fbcon_display *p, bool freefont)
>
> static void set_vc_hi_font(struct vc_data *vc, bool set);
>
> +static void fbcon_release_all(void)
> +{
> + struct fb_info *info;
> + int i, j, mapped;
> +
> + for_each_registered_fb(i) {
> + mapped = 0;
> + info = registered_fb[i];
> +
> + for (j = first_fb_vc; j <= last_fb_vc; j++) {
> + if (con2fb_map[j] == i) {
> + mapped = 1;
> + con2fb_map[j] = -1;
> + }
> + }
> +
> + if (mapped)
> + fbcon_release(info);
> + }
> +}
> +
> static void fbcon_deinit(struct vc_data *vc)
> {
> struct fbcon_display *p = &fb_display[vc->vc_num];
> @@ -1188,7 +1208,7 @@ static void fbcon_deinit(struct vc_data *vc)
> set_vc_hi_font(vc, false);
>
> if (!con_is_bound(&fb_con))
> - fbcon_exit();
> + fbcon_release_all();
>
> if (vc->vc_num == logo_shown)
> logo_shown = FBCON_LOGO_CANSHOW;
> @@ -3316,34 +3336,6 @@ static void fbcon_start(void)
> #endif
> }
>
> -static void fbcon_exit(void)
> -{
> - struct fb_info *info;
> - int i, j, mapped;
> -
> -#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
> - if (deferred_takeover) {
> - dummycon_unregister_output_notifier(&fbcon_output_nb);
> - deferred_takeover = false;
> - }
> -#endif
> -
> - for_each_registered_fb(i) {
> - mapped = 0;
> - info = registered_fb[i];
> -
> - for (j = first_fb_vc; j <= last_fb_vc; j++) {
> - if (con2fb_map[j] == i) {
> - mapped = 1;
> - con2fb_map[j] = -1;
> - }
> - }
> -
> - if (mapped)
> - fbcon_release(info);
> - }
> -}
> -
> void __init fb_console_init(void)
> {
> int i;
> @@ -3383,10 +3375,19 @@ static void __exit fbcon_deinit_device(void)
>
> void __exit fb_console_exit(void)
> {
> +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
> + console_lock();
> + if (deferred_takeover)
> + dummycon_unregister_output_notifier(&fbcon_output_nb);
> + console_unlock();
> +
> + cancel_work_sync(&fbcon_deferred_takeover_work);
> +#endif
> +
> console_lock();
> fbcon_deinit_device();
> device_destroy(fb_class, MKDEV(0, 0));
> - fbcon_exit();
> +
We loose the call to fbcon_release_all() here.
We have part of the old fbcon_exit() above, but miss the release parts.

Maybe I missed something obvious?

The rest looks fine.

Sam

> do_unregister_con_driver(&fb_con);
> console_unlock();
> }
> --
> 2.33.0

2022-02-07 20:29:09

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 05/21] fbcon: Introduce wrapper for console->fb_info lookup

On Mon, Jan 31, 2022 at 10:05:36PM +0100, Daniel Vetter wrote:
> Half of it is protected by console_lock, but the other half is a lot
> more awkward: Registration/deregistration of fbdev are serialized, but
> we don't really clear out anything in con2fb_map and so there's
> potential for use-after free mixups.
>
> First step is to encapsulate the lookup.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Helge Deller <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Tetsuo Handa <[email protected]>
> Cc: Du Cheng <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
Acked-by: Sam Ravnborg <[email protected]>

2022-02-08 05:34:42

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 16/21] fbcon: Move console_lock for register/unlink/unregister

Hi Daniel.

On Mon, Jan 31, 2022 at 10:05:47PM +0100, Daniel Vetter wrote:
> Ideally console_lock becomes an implementation detail of fbcon.c and
> doesn't show up anywhere in fbmem.c. We're still pretty far from that,
> but at least the register/unregister code is there now.
>
> With this the do_fb_ioctl() handler is the only code in fbmem.c still
> calling console_lock().
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Du Cheng <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Tetsuo Handa <[email protected]>
> Cc: Matthew Wilcox <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
> Cc: Zheyu Ma <[email protected]>
> Cc: Guenter Roeck <[email protected]>
> Cc: Alex Deucher <[email protected]>
> Cc: Zhen Lei <[email protected]>
> Cc: Xiyu Yang <[email protected]>

Like how lock_console is now almost local to fbcon.
Except the usage outside fbmem + fbcon taht is.

Acked-by: Sam Ravnborg <[email protected]>

> ---
> drivers/video/fbdev/core/fbcon.c | 33 ++++++++++++++++++++++++++------
> drivers/video/fbdev/core/fbmem.c | 23 ++--------------------
> 2 files changed, 29 insertions(+), 27 deletions(-)
>
> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> index 11b9f962af6f..e5e8aaf6f60d 100644
> --- a/drivers/video/fbdev/core/fbcon.c
> +++ b/drivers/video/fbdev/core/fbcon.c
> @@ -2776,10 +2776,12 @@ void fbcon_fb_unbind(struct fb_info *info)
> int i, new_idx = -1;
> int idx = info->node;
>
> - WARN_CONSOLE_UNLOCKED();
> + console_lock();
>
> - if (!fbcon_has_console_bind)
> + if (!fbcon_has_console_bind) {
> + console_unlock();
> return;
> + }
>
> for (i = first_fb_vc; i <= last_fb_vc; i++) {
> if (con2fb_map[i] != idx &&
> @@ -2814,6 +2816,8 @@ void fbcon_fb_unbind(struct fb_info *info)
> }
> fbcon_unbind();
> }
> +
> + console_unlock();
> }
>
> /* called with console_lock held */
> @@ -2821,10 +2825,12 @@ void fbcon_fb_unregistered(struct fb_info *info)
> {
> int i, idx;
>
> - WARN_CONSOLE_UNLOCKED();
> + console_lock();
>
> - if (deferred_takeover)
> + if (deferred_takeover) {
> + console_unlock();
> return;
> + }
>
> idx = info->node;
> for (i = first_fb_vc; i <= last_fb_vc; i++) {
> @@ -2853,6 +2859,7 @@ void fbcon_fb_unregistered(struct fb_info *info)
>
> if (!num_registered_fb)
> do_unregister_con_driver(&fb_con);
> + console_unlock();
> }
>
> void fbcon_remap_all(struct fb_info *info)
> @@ -2910,19 +2917,27 @@ static inline void fbcon_select_primary(struct fb_info *info)
> }
> #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
>
> +static bool lockless_register_fb;
> +module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 0400);
> +MODULE_PARM_DESC(lockless_register_fb,
> + "Lockless framebuffer registration for debugging [default=off]");
> +
> /* called with console_lock held */
> int fbcon_fb_registered(struct fb_info *info)
> {
> int ret = 0, i, idx;
>
> - WARN_CONSOLE_UNLOCKED();
> + if (!lockless_register_fb)
> + console_lock();
> + else
> + atomic_inc(&ignore_console_lock_warning);
>
> idx = info->node;
> fbcon_select_primary(info);
>
> if (deferred_takeover) {
> pr_info("fbcon: Deferring console take-over\n");
> - return 0;
> + goto out;
> }
>
> if (info_idx == -1) {
> @@ -2942,6 +2957,12 @@ int fbcon_fb_registered(struct fb_info *info)
> }
> }
>
> +out:
> + if (!lockless_register_fb)
> + console_unlock();
> + else
> + atomic_dec(&ignore_console_lock_warning);
> +
> return ret;
> }
>
> diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
> index fd51d12f2702..904ef1250677 100644
> --- a/drivers/video/fbdev/core/fbmem.c
> +++ b/drivers/video/fbdev/core/fbmem.c
> @@ -1573,14 +1573,9 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
> }
> }
>
> -static bool lockless_register_fb;
> -module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 0400);
> -MODULE_PARM_DESC(lockless_register_fb,
> - "Lockless framebuffer registration for debugging [default=off]");
> -
> static int do_register_framebuffer(struct fb_info *fb_info)
> {
> - int i, ret;
> + int i;
> struct fb_videomode mode;
>
> if (fb_check_foreignness(fb_info))
> @@ -1649,17 +1644,7 @@ static int do_register_framebuffer(struct fb_info *fb_info)
> }
> #endif
>
> - if (!lockless_register_fb)
> - console_lock();
> - else
> - atomic_inc(&ignore_console_lock_warning);
> - ret = fbcon_fb_registered(fb_info);
> -
> - if (!lockless_register_fb)
> - console_unlock();
> - else
> - atomic_dec(&ignore_console_lock_warning);
> - return ret;
> + return fbcon_fb_registered(fb_info);
> }
>
> static void unbind_console(struct fb_info *fb_info)
> @@ -1669,9 +1654,7 @@ static void unbind_console(struct fb_info *fb_info)
> if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
> return;
>
> - console_lock();
> fbcon_fb_unbind(fb_info);
> - console_unlock();
> }
>
> static void unlink_framebuffer(struct fb_info *fb_info)
> @@ -1714,9 +1697,7 @@ static void do_unregister_framebuffer(struct fb_info *fb_info)
> fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
> }
> #endif
> - console_lock();
> fbcon_fb_unregistered(fb_info);
> - console_unlock();
>
> /* this may free fb info */
> put_fb_info(fb_info);
> --
> 2.33.0

2022-02-08 06:48:55

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 09/21] fbcon: Replace FBCON_FLAGS_INIT with a boolean

On Mon, Jan 31, 2022 at 10:05:40PM +0100, Daniel Vetter wrote:
> It's only one flag and slightly tidier code.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Tetsuo Handa <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Du Cheng <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Claudio Suarez <[email protected]>
Acked-by: Sam Ravnborg <[email protected]>

Next step is to convert some of the int flags to bool - so it is obvious
this is bool and not an int.
I do not like bitfields for bools when there is no big win in memory
usage - so not fan of that suggestion.

Sam

2022-02-08 15:54:33

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 19/21] fbcon: Maintain a private array of fb_info

On Fri, Feb 04, 2022 at 09:15:40PM +0100, Sam Ravnborg wrote:
> Hi Daniel,
>
> On Mon, Jan 31, 2022 at 10:05:50PM +0100, Daniel Vetter wrote:
> > Accessing the one in fbmem.c without taking the right locks is a bad
> > idea. Instead maintain our own private copy, which is fully protected
> > by console_lock() (like everything else in fbcon.c). That copy is
> > serialized through fbcon_fb_registered/unregistered() calls.
>
> I fail to see why we can make a private copy of registered_fb
> just like that - are they not somehow shared between fbcon and fbmem.
> So when fbmem updates it, then fbcon will use the entry or such?
>
> I guess I am just ignorant of how registered_fb is used - but please
> explain.

The private copy is protected under console_lock, and hence safe to access
from fbcon.c code.

The main registered_fb array is protected by a different mutex, so we
could indeed end up with hilarious corruption because the value is
inconsistent while we try to access it (e.g. we check for !NULL, but later
on gcc decides to reload the value and now it's suddenly become NULL and
we blow up).

The two are synchronized by fbmem.c calling fbcon_register/unregister, so
aside from the different locks if there's no race going on, they will
always be identical.

Other option would be to roll out get_fb_info() to fbcon.c, but since
fbcon.c is fully protected by console_lock that would add complexity in
the code flow that we don't really need. And we'd have to wire fb_info
through all call chains, since the right way to use get_fb_info is to look
it up once and then only drop it when your callback has finished.

Since the current code just assume it's all protected by console_lock and
we never drop that during a callback this would mean major surgery and
essentially refactoring all of fbcon.c to only access the fbcon stuff
through fb_info, i.e. to get rid of _all_ the global arrays we have more
or less. I'm not volunteering for that (despite that really this would be
the right thing to do if we'd have infinite engineering time).

Ack with that explainer added to the commit message?
-Daniel

>
> Sam
>
> >
> > Also this means we do not need to hold a full fb_info reference, which
> > is nice because doing so would mean a refcount loop between the
> > console and the fb_info. But it's also not nice since it means
> > console_lock() must be held absolutely everywhere. Well strictly
> > speaking we could still try to do some refcounting games again by
> > calling get_fb_info before we drop the console_lock. But things will
> > get tricky.
> >
> > Signed-off-by: Daniel Vetter <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Tetsuo Handa <[email protected]>
> > Cc: Claudio Suarez <[email protected]>
> > Cc: Du Cheng <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > ---
> > drivers/video/fbdev/core/fbcon.c | 82 +++++++++++++++++---------------
> > 1 file changed, 43 insertions(+), 39 deletions(-)
> >
> > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > index 22581952b4fd..a0ca34b29615 100644
> > --- a/drivers/video/fbdev/core/fbcon.c
> > +++ b/drivers/video/fbdev/core/fbcon.c
> > @@ -86,10 +86,6 @@
> > * - 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
> > @@ -107,6 +103,13 @@ enum {
> >
> > static struct fbcon_display fb_display[MAX_NR_CONSOLES];
> >
> > +struct fb_info *fbcon_registered_fb[FB_MAX];
> > +int fbcon_num_registered_fb;
> > +
> > +#define fbcon_for_each_registered_fb(i) \
> > + for (i = 0; WARN_CONSOLE_UNLOCKED(), i < FB_MAX; i++) \
> > + if (!fbcon_registered_fb[i]) {} else
> > +
> > static signed char con2fb_map[MAX_NR_CONSOLES];
> > static signed char con2fb_map_boot[MAX_NR_CONSOLES];
> >
> > @@ -114,12 +117,7 @@ static struct fb_info *fbcon_info_from_console(int console)
> > {
> > WARN_CONSOLE_UNLOCKED();
> >
> > - /*
> > - * Note that only con2fb_map is protected by the console lock,
> > - * registered_fb is protected by a separate mutex. This lookup can
> > - * therefore race.
> > - */
> > - return registered_fb[con2fb_map[console]];
> > + return fbcon_registered_fb[con2fb_map[console]];
> > }
> >
> > static int logo_lines;
> > @@ -516,7 +514,7 @@ static int do_fbcon_takeover(int show_logo)
> > {
> > int err, i;
> >
> > - if (!num_registered_fb)
> > + if (!fbcon_num_registered_fb)
> > return -ENODEV;
> >
> > if (!show_logo)
> > @@ -822,7 +820,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
> > {
> > struct vc_data *vc = vc_cons[unit].d;
> > int oldidx = con2fb_map[unit];
> > - struct fb_info *info = registered_fb[newidx];
> > + struct fb_info *info = fbcon_registered_fb[newidx];
> > struct fb_info *oldinfo = NULL;
> > int found, err = 0, show_logo;
> >
> > @@ -840,7 +838,7 @@ static int set_con2fb_map(int unit, int newidx, int user)
> > }
> >
> > if (oldidx != -1)
> > - oldinfo = registered_fb[oldidx];
> > + oldinfo = fbcon_registered_fb[oldidx];
> >
> > found = search_fb_in_map(newidx);
> >
> > @@ -932,13 +930,13 @@ static const char *fbcon_startup(void)
> > * If num_registered_fb is zero, this is a call for the dummy part.
> > * The frame buffer devices weren't initialized yet.
> > */
> > - if (!num_registered_fb || info_idx == -1)
> > + if (!fbcon_num_registered_fb || info_idx == -1)
> > return display_desc;
> > /*
> > * Instead of blindly using registered_fb[0], we use info_idx, set by
> > * fbcon_fb_registered();
> > */
> > - info = registered_fb[info_idx];
> > + info = fbcon_registered_fb[info_idx];
> > if (!info)
> > return NULL;
> >
> > @@ -1153,9 +1151,9 @@ static void fbcon_release_all(void)
> > struct fb_info *info;
> > int i, j, mapped;
> >
> > - for_each_registered_fb(i) {
> > + fbcon_for_each_registered_fb(i) {
> > mapped = 0;
> > - info = registered_fb[i];
> > + info = fbcon_registered_fb[i];
> >
> > for (j = first_fb_vc; j <= last_fb_vc; j++) {
> > if (con2fb_map[j] == i) {
> > @@ -1182,7 +1180,7 @@ static void fbcon_deinit(struct vc_data *vc)
> > if (idx == -1)
> > goto finished;
> >
> > - info = registered_fb[idx];
> > + info = fbcon_registered_fb[idx];
> >
> > if (!info)
> > goto finished;
> > @@ -2118,9 +2116,9 @@ static int fbcon_switch(struct vc_data *vc)
> > *
> > * info->currcon = vc->vc_num;
> > */
> > - for_each_registered_fb(i) {
> > - if (registered_fb[i]->fbcon_par) {
> > - struct fbcon_ops *o = registered_fb[i]->fbcon_par;
> > + fbcon_for_each_registered_fb(i) {
> > + if (fbcon_registered_fb[i]->fbcon_par) {
> > + struct fbcon_ops *o = fbcon_registered_fb[i]->fbcon_par;
> >
> > o->currcon = vc->vc_num;
> > }
> > @@ -2765,7 +2763,7 @@ int fbcon_mode_deleted(struct fb_info *info,
> > j = con2fb_map[i];
> > if (j == -1)
> > continue;
> > - fb_info = registered_fb[j];
> > + fb_info = fbcon_registered_fb[j];
> > if (fb_info != info)
> > continue;
> > p = &fb_display[i];
> > @@ -2821,7 +2819,7 @@ void fbcon_fb_unbind(struct fb_info *info)
> > set_con2fb_map(i, new_idx, 0);
> > }
> > } else {
> > - struct fb_info *info = registered_fb[idx];
> > + struct fb_info *info = fbcon_registered_fb[idx];
> >
> > /* This is sort of like set_con2fb_map, except it maps
> > * the consoles to no device and then releases the
> > @@ -2851,6 +2849,9 @@ void fbcon_fb_unregistered(struct fb_info *info)
> >
> > console_lock();
> >
> > + fbcon_registered_fb[info->node] = NULL;
> > + fbcon_num_registered_fb--;
> > +
> > if (deferred_takeover) {
> > console_unlock();
> > return;
> > @@ -2865,7 +2866,7 @@ void fbcon_fb_unregistered(struct fb_info *info)
> > if (idx == info_idx) {
> > info_idx = -1;
> >
> > - for_each_registered_fb(i) {
> > + fbcon_for_each_registered_fb(i) {
> > info_idx = i;
> > break;
> > }
> > @@ -2881,7 +2882,7 @@ void fbcon_fb_unregistered(struct fb_info *info)
> > if (primary_device == idx)
> > primary_device = -1;
> >
> > - if (!num_registered_fb)
> > + if (!fbcon_num_registered_fb)
> > do_unregister_con_driver(&fb_con);
> > console_unlock();
> > }
> > @@ -2956,6 +2957,9 @@ int fbcon_fb_registered(struct fb_info *info)
> > else
> > atomic_inc(&ignore_console_lock_warning);
> >
> > + fbcon_registered_fb[info->node] = info;
> > + fbcon_num_registered_fb++;
> > +
> > idx = info->node;
> > fbcon_select_primary(info);
> >
> > @@ -3075,9 +3079,9 @@ int fbcon_set_con2fb_map_ioctl(void __user *argp)
> > return -EINVAL;
> > if (con2fb.framebuffer >= FB_MAX)
> > return -EINVAL;
> > - if (!registered_fb[con2fb.framebuffer])
> > + if (!fbcon_registered_fb[con2fb.framebuffer])
> > request_module("fb%d", con2fb.framebuffer);
> > - if (!registered_fb[con2fb.framebuffer]) {
> > + if (!fbcon_registered_fb[con2fb.framebuffer]) {
> > return -EINVAL;
> > }
> >
> > @@ -3144,10 +3148,10 @@ static ssize_t store_rotate(struct device *device,
> > console_lock();
> > idx = con2fb_map[fg_console];
> >
> > - if (idx == -1 || registered_fb[idx] == NULL)
> > + if (idx == -1 || fbcon_registered_fb[idx] == NULL)
> > goto err;
> >
> > - info = registered_fb[idx];
> > + info = fbcon_registered_fb[idx];
> > rotate = simple_strtoul(buf, last, 0);
> > fbcon_rotate(info, rotate);
> > err:
> > @@ -3166,10 +3170,10 @@ static ssize_t store_rotate_all(struct device *device,
> > console_lock();
> > idx = con2fb_map[fg_console];
> >
> > - if (idx == -1 || registered_fb[idx] == NULL)
> > + if (idx == -1 || fbcon_registered_fb[idx] == NULL)
> > goto err;
> >
> > - info = registered_fb[idx];
> > + info = fbcon_registered_fb[idx];
> > rotate = simple_strtoul(buf, last, 0);
> > fbcon_rotate_all(info, rotate);
> > err:
> > @@ -3186,10 +3190,10 @@ static ssize_t show_rotate(struct device *device,
> > console_lock();
> > idx = con2fb_map[fg_console];
> >
> > - if (idx == -1 || registered_fb[idx] == NULL)
> > + if (idx == -1 || fbcon_registered_fb[idx] == NULL)
> > goto err;
> >
> > - info = registered_fb[idx];
> > + info = fbcon_registered_fb[idx];
> > rotate = fbcon_get_rotate(info);
> > err:
> > console_unlock();
> > @@ -3206,10 +3210,10 @@ static ssize_t show_cursor_blink(struct device *device,
> > console_lock();
> > idx = con2fb_map[fg_console];
> >
> > - if (idx == -1 || registered_fb[idx] == NULL)
> > + if (idx == -1 || fbcon_registered_fb[idx] == NULL)
> > goto err;
> >
> > - info = registered_fb[idx];
> > + info = fbcon_registered_fb[idx];
> > ops = info->fbcon_par;
> >
> > if (!ops)
> > @@ -3232,10 +3236,10 @@ static ssize_t store_cursor_blink(struct device *device,
> > console_lock();
> > idx = con2fb_map[fg_console];
> >
> > - if (idx == -1 || registered_fb[idx] == NULL)
> > + if (idx == -1 || fbcon_registered_fb[idx] == NULL)
> > goto err;
> >
> > - info = registered_fb[idx];
> > + info = fbcon_registered_fb[idx];
> >
> > if (!info->fbcon_par)
> > goto err;
> > @@ -3295,8 +3299,8 @@ static void fbcon_register_existing_fbs(struct work_struct *work)
> > deferred_takeover = false;
> > logo_shown = FBCON_LOGO_DONTSHOW;
> >
> > - for_each_registered_fb(i)
> > - fbcon_fb_registered(registered_fb[i]);
> > + fbcon_for_each_registered_fb(i)
> > + fbcon_fb_registered(fbcon_registered_fb[i]);
> >
> > console_unlock();
> > }
> > --
> > 2.33.0

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

2022-02-08 22:54:04

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 21/21] fbdev: Make registered_fb[] private to fbmem.c

On Fri, Feb 04, 2022 at 09:30:56AM +0100, Geert Uytterhoeven wrote:
> Hi Daniel,
>
> Thanks for your patch!
>
> On Tue, Feb 1, 2022 at 9:50 PM Daniel Vetter <[email protected]> wrote:
> > Well except when the olpc dcon fbdev driver is enabled, that thing
> > digs around in there in rather unfixable ways.
>
> Can't the actual frame buffer driver (which one?) used on olpc export
> a pointer to its fb_info?

Yeah that might be the right thing to do, I'll add that as a stagin TODO
in the next iteration.

>
> > --- a/drivers/video/fbdev/core/fbmem.c
> > +++ b/drivers/video/fbdev/core/fbmem.c
> > @@ -48,10 +48,14 @@
> > static DEFINE_MUTEX(registration_lock);
> >
> > struct fb_info *registered_fb[FB_MAX] __read_mostly;
> > -EXPORT_SYMBOL(registered_fb);
> > -
> > int num_registered_fb __read_mostly;
> > +#if IS_ENABLED(CONFIG_OLPC_DCON)
>
> CONFIG_FB_OLPC_DCON (everywhere), cfr. the build failure reported
> by the robot.

Yeah realized that too and fixed it locally.

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
http://blog.ffwll.ch

2022-02-09 00:43:36

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 21/21] fbdev: Make registered_fb[] private to fbmem.c

On Tue, Feb 08, 2022 at 03:04:51PM +0100, Daniel Vetter wrote:
> On Fri, Feb 04, 2022 at 09:30:56AM +0100, Geert Uytterhoeven wrote:
> > Hi Daniel,
> >
> > Thanks for your patch!
> >
> > On Tue, Feb 1, 2022 at 9:50 PM Daniel Vetter <[email protected]> wrote:
> > > Well except when the olpc dcon fbdev driver is enabled, that thing
> > > digs around in there in rather unfixable ways.
> >
> > Can't the actual frame buffer driver (which one?) used on olpc export
> > a pointer to its fb_info?
>
> Yeah that might be the right thing to do, I'll add that as a stagin TODO
> in the next iteration.

Well I tried to do that and noticed I've done that already in 2019:

commit af1440368837f19ac7d5dec05d929d91308f5a90
Author: Daniel Vetter <[email protected]>
Date: Tue May 28 11:03:03 2019 +0200

staging/olpc_dcon: Add drm conversion to TODO

TODO already explains how this should be done correctly in drm. Well maybe
we should add that stitching the drivers together should be done with
component.c or something like that.
-Daniel

>
> >
> > > --- a/drivers/video/fbdev/core/fbmem.c
> > > +++ b/drivers/video/fbdev/core/fbmem.c
> > > @@ -48,10 +48,14 @@
> > > static DEFINE_MUTEX(registration_lock);
> > >
> > > struct fb_info *registered_fb[FB_MAX] __read_mostly;
> > > -EXPORT_SYMBOL(registered_fb);
> > > -
> > > int num_registered_fb __read_mostly;
> > > +#if IS_ENABLED(CONFIG_OLPC_DCON)
> >
> > CONFIG_FB_OLPC_DCON (everywhere), cfr. the build failure reported
> > by the robot.
>
> Yeah realized that too and fixed it locally.
>
> 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
> http://blog.ffwll.ch

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

2022-02-09 02:45:51

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 16/21] fbcon: Move console_lock for register/unlink/unregister

On Fri, Feb 04, 2022 at 08:54:24PM +0100, Sam Ravnborg wrote:
> Hi Daniel.
>
> On Mon, Jan 31, 2022 at 10:05:47PM +0100, Daniel Vetter wrote:
> > Ideally console_lock becomes an implementation detail of fbcon.c and
> > doesn't show up anywhere in fbmem.c. We're still pretty far from that,
> > but at least the register/unregister code is there now.
> >
> > With this the do_fb_ioctl() handler is the only code in fbmem.c still
> > calling console_lock().
> >
> > Signed-off-by: Daniel Vetter <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Thomas Zimmermann <[email protected]>
> > Cc: Du Cheng <[email protected]>
> > Cc: Claudio Suarez <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > Cc: Tetsuo Handa <[email protected]>
> > Cc: Matthew Wilcox <[email protected]>
> > Cc: Sam Ravnborg <[email protected]>
> > Cc: Zheyu Ma <[email protected]>
> > Cc: Guenter Roeck <[email protected]>
> > Cc: Alex Deucher <[email protected]>
> > Cc: Zhen Lei <[email protected]>
> > Cc: Xiyu Yang <[email protected]>
>
> Like how lock_console is now almost local to fbcon.
> Except the usage outside fbmem + fbcon taht is.

Yeah that's the goal. The problem is that moving console_lock for the
remaining fb_pan and fb_set_var calls will mean we need to put
lock_fbinfo() calls into fbcon.c, and right now that's just not
impossible. The FIXME update at the end of the series tries to explain
this a bit more.
-Daniel

>
> Acked-by: Sam Ravnborg <[email protected]>
>
> > ---
> > drivers/video/fbdev/core/fbcon.c | 33 ++++++++++++++++++++++++++------
> > drivers/video/fbdev/core/fbmem.c | 23 ++--------------------
> > 2 files changed, 29 insertions(+), 27 deletions(-)
> >
> > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > index 11b9f962af6f..e5e8aaf6f60d 100644
> > --- a/drivers/video/fbdev/core/fbcon.c
> > +++ b/drivers/video/fbdev/core/fbcon.c
> > @@ -2776,10 +2776,12 @@ void fbcon_fb_unbind(struct fb_info *info)
> > int i, new_idx = -1;
> > int idx = info->node;
> >
> > - WARN_CONSOLE_UNLOCKED();
> > + console_lock();
> >
> > - if (!fbcon_has_console_bind)
> > + if (!fbcon_has_console_bind) {
> > + console_unlock();
> > return;
> > + }
> >
> > for (i = first_fb_vc; i <= last_fb_vc; i++) {
> > if (con2fb_map[i] != idx &&
> > @@ -2814,6 +2816,8 @@ void fbcon_fb_unbind(struct fb_info *info)
> > }
> > fbcon_unbind();
> > }
> > +
> > + console_unlock();
> > }
> >
> > /* called with console_lock held */
> > @@ -2821,10 +2825,12 @@ void fbcon_fb_unregistered(struct fb_info *info)
> > {
> > int i, idx;
> >
> > - WARN_CONSOLE_UNLOCKED();
> > + console_lock();
> >
> > - if (deferred_takeover)
> > + if (deferred_takeover) {
> > + console_unlock();
> > return;
> > + }
> >
> > idx = info->node;
> > for (i = first_fb_vc; i <= last_fb_vc; i++) {
> > @@ -2853,6 +2859,7 @@ void fbcon_fb_unregistered(struct fb_info *info)
> >
> > if (!num_registered_fb)
> > do_unregister_con_driver(&fb_con);
> > + console_unlock();
> > }
> >
> > void fbcon_remap_all(struct fb_info *info)
> > @@ -2910,19 +2917,27 @@ static inline void fbcon_select_primary(struct fb_info *info)
> > }
> > #endif /* CONFIG_FRAMEBUFFER_DETECT_PRIMARY */
> >
> > +static bool lockless_register_fb;
> > +module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 0400);
> > +MODULE_PARM_DESC(lockless_register_fb,
> > + "Lockless framebuffer registration for debugging [default=off]");
> > +
> > /* called with console_lock held */
> > int fbcon_fb_registered(struct fb_info *info)
> > {
> > int ret = 0, i, idx;
> >
> > - WARN_CONSOLE_UNLOCKED();
> > + if (!lockless_register_fb)
> > + console_lock();
> > + else
> > + atomic_inc(&ignore_console_lock_warning);
> >
> > idx = info->node;
> > fbcon_select_primary(info);
> >
> > if (deferred_takeover) {
> > pr_info("fbcon: Deferring console take-over\n");
> > - return 0;
> > + goto out;
> > }
> >
> > if (info_idx == -1) {
> > @@ -2942,6 +2957,12 @@ int fbcon_fb_registered(struct fb_info *info)
> > }
> > }
> >
> > +out:
> > + if (!lockless_register_fb)
> > + console_unlock();
> > + else
> > + atomic_dec(&ignore_console_lock_warning);
> > +
> > return ret;
> > }
> >
> > diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
> > index fd51d12f2702..904ef1250677 100644
> > --- a/drivers/video/fbdev/core/fbmem.c
> > +++ b/drivers/video/fbdev/core/fbmem.c
> > @@ -1573,14 +1573,9 @@ static void do_remove_conflicting_framebuffers(struct apertures_struct *a,
> > }
> > }
> >
> > -static bool lockless_register_fb;
> > -module_param_named_unsafe(lockless_register_fb, lockless_register_fb, bool, 0400);
> > -MODULE_PARM_DESC(lockless_register_fb,
> > - "Lockless framebuffer registration for debugging [default=off]");
> > -
> > static int do_register_framebuffer(struct fb_info *fb_info)
> > {
> > - int i, ret;
> > + int i;
> > struct fb_videomode mode;
> >
> > if (fb_check_foreignness(fb_info))
> > @@ -1649,17 +1644,7 @@ static int do_register_framebuffer(struct fb_info *fb_info)
> > }
> > #endif
> >
> > - if (!lockless_register_fb)
> > - console_lock();
> > - else
> > - atomic_inc(&ignore_console_lock_warning);
> > - ret = fbcon_fb_registered(fb_info);
> > -
> > - if (!lockless_register_fb)
> > - console_unlock();
> > - else
> > - atomic_dec(&ignore_console_lock_warning);
> > - return ret;
> > + return fbcon_fb_registered(fb_info);
> > }
> >
> > static void unbind_console(struct fb_info *fb_info)
> > @@ -1669,9 +1654,7 @@ static void unbind_console(struct fb_info *fb_info)
> > if (WARN_ON(i < 0 || i >= FB_MAX || registered_fb[i] != fb_info))
> > return;
> >
> > - console_lock();
> > fbcon_fb_unbind(fb_info);
> > - console_unlock();
> > }
> >
> > static void unlink_framebuffer(struct fb_info *fb_info)
> > @@ -1714,9 +1697,7 @@ static void do_unregister_framebuffer(struct fb_info *fb_info)
> > fb_notifier_call_chain(FB_EVENT_FB_UNREGISTERED, &event);
> > }
> > #endif
> > - console_lock();
> > fbcon_fb_unregistered(fb_info);
> > - console_unlock();
> >
> > /* this may free fb info */
> > put_fb_info(fb_info);
> > --
> > 2.33.0

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

2022-02-09 06:27:55

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 21/21] fbdev: Make registered_fb[] private to fbmem.c

On Tue, Feb 08, 2022 at 08:00:38PM +0100, Sam Ravnborg wrote:
> Hi Daniel,
>
> On Mon, Jan 31, 2022 at 10:05:52PM +0100, Daniel Vetter wrote:
> > Well except when the olpc dcon fbdev driver is enabled, that thing
> > digs around in there in rather unfixable ways.
> >
> > Cc oldc_dcon maintainers as fyi.
> >
> > Cc: Jens Frederich <[email protected]>
> > Cc: Jon Nettleton <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > Cc: [email protected]
> > Signed-off-by: Daniel Vetter <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Helge Deller <[email protected]>
> > Cc: Matthew Wilcox <[email protected]>
> > Cc: Sam Ravnborg <[email protected]>
> > Cc: Tetsuo Handa <[email protected]>
> > Cc: Zhen Lei <[email protected]>
> > Cc: Alex Deucher <[email protected]>
> > Cc: Xiyu Yang <[email protected]>
> > Cc: [email protected]
> > Cc: Zheyu Ma <[email protected]>
> > Cc: Guenter Roeck <[email protected]>
>
> with the build thingy fixed:
> Acked-by: Sam Ravnborg <[email protected]>
>
> I do wonder if there is a more clean way to trigger a blank
> in the main fbdev driver from the olpc driver.
>
> The current hack is not nice and it would be good to see it gone.

Yeah this is just badly engineered. In drm we'd do this with the self
refresh helpers, which pretty much give you this exact functionality, but
in the helpers, while not randomly breaking actual visible behaviour of
the display driver.

Well ok the illusion is not perfect, since if the display is suspended the
next page flip will take a tad longer. But that's it.

I'll also add this to the TODO.
-Daniel

>
> Sam
>
> > ---
> > drivers/video/fbdev/core/fbmem.c | 8 ++++++--
> > include/linux/fb.h | 7 +++----
> > 2 files changed, 9 insertions(+), 6 deletions(-)
> >
> > diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
> > index 904ef1250677..dad6572942fa 100644
> > --- a/drivers/video/fbdev/core/fbmem.c
> > +++ b/drivers/video/fbdev/core/fbmem.c
> > @@ -48,10 +48,14 @@
> > static DEFINE_MUTEX(registration_lock);
> >
> > struct fb_info *registered_fb[FB_MAX] __read_mostly;
> > -EXPORT_SYMBOL(registered_fb);
> > -
> > int num_registered_fb __read_mostly;
> > +#if IS_ENABLED(CONFIG_OLPC_DCON)
> > +EXPORT_SYMBOL(registered_fb);
> > EXPORT_SYMBOL(num_registered_fb);
> > +#endif
> > +#define for_each_registered_fb(i) \
> > + for (i = 0; i < FB_MAX; i++) \
> > + if (!registered_fb[i]) {} else
> >
> > bool fb_center_logo __read_mostly;
> >
> > diff --git a/include/linux/fb.h b/include/linux/fb.h
> > index a8a00d2ba1f3..e236817502c2 100644
> > --- a/include/linux/fb.h
> > +++ b/include/linux/fb.h
> > @@ -622,16 +622,15 @@ extern int fb_get_color_depth(struct fb_var_screeninfo *var,
> > extern int fb_get_options(const char *name, char **option);
> > extern int fb_new_modelist(struct fb_info *info);
> >
> > +#if IS_ENABLED(CONFIG_OLPC_DCON)
> > extern struct fb_info *registered_fb[FB_MAX];
> > +
> > extern int num_registered_fb;
> > +#endif
> > extern bool fb_center_logo;
> > extern int fb_logo_count;
> > extern struct class *fb_class;
> >
> > -#define for_each_registered_fb(i) \
> > - for (i = 0; i < FB_MAX; i++) \
> > - if (!registered_fb[i]) {} else
> > -
> > static inline void lock_fb_info(struct fb_info *info)
> > {
> > mutex_lock(&info->lock);
> > --
> > 2.33.0

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

2022-02-09 06:49:55

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 01/21] MAINTAINERS: Add entry for fbdev core

On Mon, Jan 31, 2022 at 10:05:32PM +0100, Daniel Vetter wrote:
> Ever since Tomi extracted the core code in 2014 it's been defacto me
> maintaining this, with help from others from dri-devel and sometimes
> Linus (but those are mostly merge conflicts):
>
> $ git shortlog -ns drivers/video/fbdev/core/ | head -n5
> 35 Daniel Vetter
> 23 Linus Torvalds
> 10 Hans de Goede
> 9 Dave Airlie
> 6 Peter Rosin
>
> I think ideally we'd also record that the various firmware fb drivers
> (efifb, vesafb, ...) are also maintained in drm-misc because for the
> past few years the patches have either been to fix handover issues
> with drm drivers, or caused handover issues with drm drivers. So any
> other tree just doesn't make sense. But also, there's plenty of
> outdated MAINTAINER entries for these with people and git trees that
> haven't been active in years, so maybe let's just leave them alone.
> And furthermore distros are now adopting simpledrm as the firmware fb
> driver, so hopefully the need to care about the fbdev firmware drivers
> will go down going forward.
>
> Note that drm-misc is group maintained, I expect that to continue like
> we've done before, so no new expectations that patches all go through
> my hands. That would be silly. This also means I'm happy to put any
> other volunteer's name in the M: line, but otherwise git log says I'm
> the one who's stuck with this.
>
> Cc: Dave Airlie <[email protected]>
> Cc: Jani Nikula <[email protected]>
> Cc: Linus Torvalds <[email protected]>
> Cc: Linux Fbdev development list <[email protected]>
> Cc: Pavel Machek <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: Javier Martinez Canillas <[email protected]>
> Cc: DRI Development <[email protected]>
> Cc: Linux Kernel Mailing List <[email protected]>
> Cc: Claudio Suarez <[email protected]>
> Cc: Tomi Valkeinen <[email protected]>
> Cc: Geert Uytterhoeven <[email protected]>
> Cc: Thomas Zimmermann <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Sven Schnelle <[email protected]>
> Cc: Gerd Hoffmann <[email protected]>
> Signed-off-by: Daniel Vetter <[email protected]>

Merged to drm-misc-fixes with all the acks added.
-Daniel

> ---
> MAINTAINERS | 6 ++++++
> 1 file changed, 6 insertions(+)
>
> diff --git a/MAINTAINERS b/MAINTAINERS
> index ea3e6c914384..49809eaa3096 100644
> --- a/MAINTAINERS
> +++ b/MAINTAINERS
> @@ -7573,6 +7573,12 @@ S: Maintained
> W: http://floatingpoint.sourceforge.net/emulator/index.html
> F: arch/x86/math-emu/
>
> +FRAMEBUFFER CORE
> +M: Daniel Vetter <[email protected]>
> +F: drivers/video/fbdev/core/
> +S: Odd Fixes
> +T: git git://anongit.freedesktop.org/drm/drm-misc
> +
> FRAMEBUFFER LAYER
> M: Helge Deller <[email protected]>
> L: [email protected]
> --
> 2.33.0
>

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

2022-02-09 06:50:10

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 11/21] fbcon: Extract fbcon_open/release helpers

On Thu, Feb 03, 2022 at 10:15:14PM +0100, Sam Ravnborg wrote:
> Hi Daniel,
>
> On Mon, Jan 31, 2022 at 10:05:42PM +0100, Daniel Vetter wrote:
> > There's two minor behaviour changes in here:
> > - in error paths we now consistently call fb_ops->fb_release
> > - fb_release really can't fail (fbmem.c ignores it too) and there's no
> > reasonable cleanup we can do anyway.
> >
> > Signed-off-by: Daniel Vetter <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Claudio Suarez <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > Cc: Tetsuo Handa <[email protected]>
> > Cc: Du Cheng <[email protected]>
> > ---
> > drivers/video/fbdev/core/fbcon.c | 107 +++++++++++++++----------------
> > 1 file changed, 53 insertions(+), 54 deletions(-)
> >
> > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > index fa30e1909164..eea2ee14b64c 100644
> > --- a/drivers/video/fbdev/core/fbcon.c
> > +++ b/drivers/video/fbdev/core/fbcon.c
> > @@ -680,19 +680,37 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
> >
> > #endif /* CONFIG_MISC_TILEBLITTING */
> >
> > +static int fbcon_open(struct fb_info *info)
> > +{
> > + if (!try_module_get(info->fbops->owner))
> > + return -ENODEV;
> > +
> > + if (info->fbops->fb_open &&
> > + info->fbops->fb_open(info, 0)) {
> > + module_put(info->fbops->owner);
> > + return -ENODEV;
> > + }
> > +
> > + return 0;
> > +}
> > +
> > +static void fbcon_release(struct fb_info *info)
> > +{
> > + if (info->fbops->fb_release)
> > + info->fbops->fb_release(info, 0);
> > +
> > + module_put(info->fbops->owner);
> > +}
> >
> > static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> > int unit, int oldidx)
> > {
> > struct fbcon_ops *ops = NULL;
> > - int err = 0;
> > -
> > - if (!try_module_get(info->fbops->owner))
> > - err = -ENODEV;
> > + int err;
> >
> > - if (!err && info->fbops->fb_open &&
> > - info->fbops->fb_open(info, 0))
> > - err = -ENODEV;
> > + err = fbcon_open(info);
> > + if (err)
> > + return err;
> >
> > if (!err) {
> > ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> > @@ -713,7 +731,7 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> >
> > if (err) {
> > con2fb_map[unit] = oldidx;
> > - module_put(info->fbops->owner);
> > + fbcon_release(info);
> > }
> >
> > return err;
> > @@ -724,45 +742,34 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
> > int oldidx, int found)
> > {
> > struct fbcon_ops *ops = oldinfo->fbcon_par;
> > - int err = 0, ret;
> > + int ret;
> >
> > - if (oldinfo->fbops->fb_release &&
> > - oldinfo->fbops->fb_release(oldinfo, 0)) {
> > - con2fb_map[unit] = oldidx;
> The old code assigns con2fb_map[unit] before is calls
> newinfo->fbops->fb_release).
> I wonder if there can be any callback to fbcon where the value
> of con2fb_map[unit] matters?

It's all protected by console_lock, so other threads cannot see the
inconsistent state.

Essentially everything in fbcon.c is protected by console_lock().

Do you want me to hammer this in somewhere (maybe in the commit message),
or good enough for your ack?
-Daniel

>
>
> > - if (!found && newinfo->fbops->fb_release)
> > - newinfo->fbops->fb_release(newinfo, 0);
> > - if (!found)
> > - module_put(newinfo->fbops->owner);
> > - err = -ENODEV;
> > - }
> > + fbcon_release(oldinfo);
> >
> > - if (!err) {
> > - fbcon_del_cursor_work(oldinfo);
> > - kfree(ops->cursor_state.mask);
> > - kfree(ops->cursor_data);
> > - kfree(ops->cursor_src);
> > - kfree(ops->fontbuffer);
> > - kfree(oldinfo->fbcon_par);
> > - oldinfo->fbcon_par = NULL;
> > - module_put(oldinfo->fbops->owner);
> > - /*
> > - If oldinfo and newinfo are driving the same hardware,
> > - the fb_release() method of oldinfo may attempt to
> > - restore the hardware state. This will leave the
> > - newinfo in an undefined state. Thus, a call to
> > - fb_set_par() may be needed for the newinfo.
> > - */
> > - if (newinfo && newinfo->fbops->fb_set_par) {
> > - ret = newinfo->fbops->fb_set_par(newinfo);
> > + fbcon_del_cursor_work(oldinfo);
>
>
> > + kfree(ops->cursor_state.mask);
> > + kfree(ops->cursor_data);
> > + kfree(ops->cursor_src);
> > + kfree(ops->fontbuffer);
> > + kfree(oldinfo->fbcon_par);
> > + oldinfo->fbcon_par = NULL;
> These all look like candidates to stuff into fbcon_release()
> That would drop the nice symmetry but make it more consistent.
>
> I think we miss freeing ops->cursor_data in fbcon_exit(),
> but I did not follow all the code.
>
> With my ramblings considered the patch is
> Acked-by: Sam Ravnborg <[email protected]>
>
> Sam
>
> > + /*
> > + If oldinfo and newinfo are driving the same hardware,
> > + the fb_release() method of oldinfo may attempt to
> > + restore the hardware state. This will leave the
> > + newinfo in an undefined state. Thus, a call to
> > + fb_set_par() may be needed for the newinfo.
> > + */
> > + if (newinfo && newinfo->fbops->fb_set_par) {
> > + ret = newinfo->fbops->fb_set_par(newinfo);
> >
> > - if (ret)
> > - printk(KERN_ERR "con2fb_release_oldinfo: "
> > - "detected unhandled fb_set_par error, "
> > - "error code %d\n", ret);
> > - }
> > + if (ret)
> > + printk(KERN_ERR "con2fb_release_oldinfo: "
> > + "detected unhandled fb_set_par error, "
> > + "error code %d\n", ret);
> > }
> >
> > - return err;
> > + return 0;
> > }
> >
> > static void con2fb_init_display(struct vc_data *vc, struct fb_info *info,
> > @@ -917,7 +924,6 @@ static const char *fbcon_startup(void)
> > struct fbcon_display *p = &fb_display[fg_console];
> > struct vc_data *vc = vc_cons[fg_console].d;
> > const struct font_desc *font = NULL;
> > - struct module *owner;
> > struct fb_info *info = NULL;
> > struct fbcon_ops *ops;
> > int rows, cols;
> > @@ -936,17 +942,12 @@ static const char *fbcon_startup(void)
> > if (!info)
> > return NULL;
> >
> > - owner = info->fbops->owner;
> > - if (!try_module_get(owner))
> > + if (fbcon_open(info))
> > return NULL;
> > - if (info->fbops->fb_open && info->fbops->fb_open(info, 0)) {
> > - module_put(owner);
> > - return NULL;
> > - }
> >
> > ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> > if (!ops) {
> > - module_put(owner);
> > + fbcon_release(info);
> > return NULL;
> > }
> >
> > @@ -3331,10 +3332,6 @@ static void fbcon_exit(void)
> > }
> >
> > if (mapped) {
> > - if (info->fbops->fb_release)
> > - info->fbops->fb_release(info, 0);
> > - module_put(info->fbops->owner);
> > -
> > if (info->fbcon_par) {
> > struct fbcon_ops *ops = info->fbcon_par;
> >
> > @@ -3344,6 +3341,8 @@ static void fbcon_exit(void)
> > kfree(info->fbcon_par);
> > info->fbcon_par = NULL;
> > }
> > +
> > + fbcon_release(info);
> > }
> > }
> > }
> > --
> > 2.33.0

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

2022-02-09 07:07:44

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 06/21] fbcon: delete delayed loading code

Hi Daniel,

On Tue, Feb 08, 2022 at 02:42:25PM +0100, Daniel Vetter wrote:
> On Thu, Feb 03, 2022 at 09:45:29PM +0100, Sam Ravnborg wrote:
> > Hi Daniel,
> >
> > On Mon, Jan 31, 2022 at 10:05:37PM +0100, Daniel Vetter wrote:
> > > Before
> > >
> > > 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
> > >
> > > it was possible to load fbcon and fbdev drivers in any order, which
> > > means that fbcon init had to handle the case where fbdev drivers where
> > > already registered.
> > >
> > > This is no longer possible, hence delete that code.
> > >
> > > Note that the exit case is a bit more complex and will be done in a
> > > separate patch.
> > >
> > > Signed-off-by: Daniel Vetter <[email protected]>
> > > Cc: Helge Deller <[email protected]>
> > > Cc: Daniel Vetter <[email protected]>
> > > Cc: Claudio Suarez <[email protected]>
> > > Cc: Greg Kroah-Hartman <[email protected]>
> > > Cc: Tetsuo Handa <[email protected]>
> > > Cc: Du Cheng <[email protected]>
> > > ---
> > > drivers/video/fbdev/core/fbcon.c | 13 +------------
> > > 1 file changed, 1 insertion(+), 12 deletions(-)
> > >
> > > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > > index 8f971de35885..814b648e8f09 100644
> > > --- a/drivers/video/fbdev/core/fbcon.c
> > > +++ b/drivers/video/fbdev/core/fbcon.c
> > > @@ -942,7 +942,7 @@ static const char *fbcon_startup(void)
> > > return display_desc;
> > > /*
> > > * Instead of blindly using registered_fb[0], we use info_idx, set by
> > > - * fb_console_init();
> > > + * fbcon_fb_registered();
> > > */
> > This comment change looks like it does not belong in this patch.
> > Also, the comment is wrong as info_idx is set in several places.
> > Like set_con2fb_map(), fbcon_remap_all(), and more.
>
> Yeah I can split this out into a separate patch, but I spotted this wrong
> comment as part of reviewing this code change here - essentially you have
> to check how fb_info for fbcon are registered and fbcon init happens to
> validate that deleting the below code is correct.
>
> Ok if I put this explainer into the commit message, or do you want me to
> split this out fully?
Keep it and add my a-b

Sam

2022-02-09 07:16:35

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 18/21] fbcon: untangle fbcon_exit

On Tue, Feb 08, 2022 at 02:58:21PM +0100, Daniel Vetter wrote:
> On Fri, Feb 04, 2022 at 09:06:38PM +0100, Sam Ravnborg wrote:
> > Hi Daniel,
> >
> > On Mon, Jan 31, 2022 at 10:05:49PM +0100, Daniel Vetter wrote:
> > > There's a bunch of confusions going on here:
> > > - The deferred fbcon setup notifier should only be cleaned up from
> > > fb_console_exit(), to be symmetric with fb_console_init()
> > > - We also need to make sure we don't race with the work, which means
> > > temporarily dropping the console lock (or we can deadlock)
> > > - That also means no point in clearing deferred_takeover, we are
> > > unloading everything anyway.
> > > - Finally rename fbcon_exit to fbcon_release_all and move it, since
> > > that's what's it doing when being called from consw->con_deinit
> > > through fbcon_deinit.
> > >
> > > Signed-off-by: Daniel Vetter <[email protected]>
> > > Cc: Daniel Vetter <[email protected]>
> > > Cc: Greg Kroah-Hartman <[email protected]>
> > > Cc: Claudio Suarez <[email protected]>
> > > Cc: Du Cheng <[email protected]>
> > > Cc: Tetsuo Handa <[email protected]>
> > > ---
> > > drivers/video/fbdev/core/fbcon.c | 63 ++++++++++++++++----------------
> > > 1 file changed, 32 insertions(+), 31 deletions(-)
> > >
> > > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > > index 5c14e24d14a1..22581952b4fd 100644
> > > --- a/drivers/video/fbdev/core/fbcon.c
> > > +++ b/drivers/video/fbdev/core/fbcon.c
> > > @@ -185,7 +185,6 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
> > > int unit);
> > > static void fbcon_modechanged(struct fb_info *info);
> > > static void fbcon_set_all_vcs(struct fb_info *info);
> > > -static void fbcon_exit(void);
> > >
> > > static struct device *fbcon_device;
> > >
> > > @@ -1149,6 +1148,27 @@ static void fbcon_free_font(struct fbcon_display *p, bool freefont)
> > >
> > > static void set_vc_hi_font(struct vc_data *vc, bool set);
> > >
> > > +static void fbcon_release_all(void)
> > > +{
> > > + struct fb_info *info;
> > > + int i, j, mapped;
> > > +
> > > + for_each_registered_fb(i) {
> > > + mapped = 0;
> > > + info = registered_fb[i];
> > > +
> > > + for (j = first_fb_vc; j <= last_fb_vc; j++) {
> > > + if (con2fb_map[j] == i) {
> > > + mapped = 1;
> > > + con2fb_map[j] = -1;
> > > + }
> > > + }
> > > +
> > > + if (mapped)
> > > + fbcon_release(info);
> > > + }
> > > +}
> > > +
> > > static void fbcon_deinit(struct vc_data *vc)
> > > {
> > > struct fbcon_display *p = &fb_display[vc->vc_num];
> > > @@ -1188,7 +1208,7 @@ static void fbcon_deinit(struct vc_data *vc)
> > > set_vc_hi_font(vc, false);
> > >
> > > if (!con_is_bound(&fb_con))
> > > - fbcon_exit();
> > > + fbcon_release_all();
> > >
> > > if (vc->vc_num == logo_shown)
> > > logo_shown = FBCON_LOGO_CANSHOW;
> > > @@ -3316,34 +3336,6 @@ static void fbcon_start(void)
> > > #endif
> > > }
> > >
> > > -static void fbcon_exit(void)
> > > -{
> > > - struct fb_info *info;
> > > - int i, j, mapped;
> > > -
> > > -#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
> > > - if (deferred_takeover) {
> > > - dummycon_unregister_output_notifier(&fbcon_output_nb);
> > > - deferred_takeover = false;
> > > - }
> > > -#endif
> > > -
> > > - for_each_registered_fb(i) {
> > > - mapped = 0;
> > > - info = registered_fb[i];
> > > -
> > > - for (j = first_fb_vc; j <= last_fb_vc; j++) {
> > > - if (con2fb_map[j] == i) {
> > > - mapped = 1;
> > > - con2fb_map[j] = -1;
> > > - }
> > > - }
> > > -
> > > - if (mapped)
> > > - fbcon_release(info);
> > > - }
> > > -}
> > > -
> > > void __init fb_console_init(void)
> > > {
> > > int i;
> > > @@ -3383,10 +3375,19 @@ static void __exit fbcon_deinit_device(void)
> > >
> > > void __exit fb_console_exit(void)
> > > {
> > > +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
> > > + console_lock();
> > > + if (deferred_takeover)
> > > + dummycon_unregister_output_notifier(&fbcon_output_nb);
> > > + console_unlock();
> > > +
> > > + cancel_work_sync(&fbcon_deferred_takeover_work);
> > > +#endif
> > > +
> > > console_lock();
> > > fbcon_deinit_device();
> > > device_destroy(fb_class, MKDEV(0, 0));
> > > - fbcon_exit();
> > > +
> > We loose the call to fbcon_release_all() here.
> > We have part of the old fbcon_exit() above, but miss the release parts.
> >
> > Maybe I missed something obvious?
>
> Ah yes that's the entire point of this change. The release_all in the
> fbcon exit path was only needed when fbcon was a separate module
> indepedent from core fb.ko. Which means it was possible to unload fbcon
> while having fbdev drivers registered.
>
> But since we've merged them that has become impossible, so by the time the
> fb.ko module can be unloaded, there's guaranteed to be no fbdev drivers
> left. And hence removing them is pointless.
Makes sense, thanks for the explanation.

>
> Ack with that explainer added to the commit message?
Yes, then it is
Acked-by: Sam Ravnborg <[email protected]>

2022-02-09 08:45:59

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 10/21] fb: Delete fb_info->queue

On Thu, Feb 03, 2022 at 10:31:00PM +0100, Sam Ravnborg wrote:
> On Mon, Jan 31, 2022 at 10:05:41PM +0100, Daniel Vetter wrote:
> > It was only used by fbcon, and that now switched to its own,
> > private work.
> >
> > Signed-off-by: Daniel Vetter <[email protected]>
> > Cc: Helge Deller <[email protected]>
> > Cc: [email protected]
> I would merge this with the patch that drops the usage

Yeah, but I like to split these out so that if this does break something,
it's much easier to revert. In case I overlooked something somewhere.

It's imo different if the cleanup is directly related to the preceeding
prep work, but this is a generic workqueue, and the cursor logic is rather
unrelated. And if I remember my history digging right, there were actually
other uses of this.
-Daniel

>
> > ---
> > include/linux/fb.h | 1 -
> > 1 file changed, 1 deletion(-)
> >
> > diff --git a/include/linux/fb.h b/include/linux/fb.h
> > index 02f362c661c8..a8a00d2ba1f3 100644
> > --- a/include/linux/fb.h
> > +++ b/include/linux/fb.h
> > @@ -449,7 +449,6 @@ struct fb_info {
> > struct fb_var_screeninfo var; /* Current var */
> > struct fb_fix_screeninfo fix; /* Current fix */
> > struct fb_monspecs monspecs; /* Current Monitor specs */
> > - struct work_struct queue; /* Framebuffer event queue */
> > struct fb_pixmap pixmap; /* Image hardware mapper */
> > struct fb_pixmap sprite; /* Cursor hardware mapper */
> > struct fb_cmap cmap; /* Current cmap */
> > --
> > 2.33.0

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

2022-02-09 09:06:32

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 10/21] fb: Delete fb_info->queue

Hi Daniel,

On Tue, Feb 08, 2022 at 02:46:33PM +0100, Daniel Vetter wrote:
> On Thu, Feb 03, 2022 at 10:31:00PM +0100, Sam Ravnborg wrote:
> > On Mon, Jan 31, 2022 at 10:05:41PM +0100, Daniel Vetter wrote:
> > > It was only used by fbcon, and that now switched to its own,
> > > private work.
> > >
> > > Signed-off-by: Daniel Vetter <[email protected]>
> > > Cc: Helge Deller <[email protected]>
> > > Cc: [email protected]
> > I would merge this with the patch that drops the usage
>
> Yeah, but I like to split these out so that if this does break something,
> it's much easier to revert. In case I overlooked something somewhere.
>
> It's imo different if the cleanup is directly related to the preceeding
> prep work, but this is a generic workqueue, and the cursor logic is rather
> unrelated. And if I remember my history digging right, there were actually
> other uses of this.

So you basically say that because in the past there may have been other
users, this deserves a dedicated removal commit.

That works for me too.
Acked-by: Sam Ravnborg <[email protected]>

Sam

2022-02-09 09:35:45

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 10/21] fb: Delete fb_info->queue

On Mon, Jan 31, 2022 at 10:05:41PM +0100, Daniel Vetter wrote:
> It was only used by fbcon, and that now switched to its own,
> private work.
>
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Helge Deller <[email protected]>
> Cc: [email protected]
I would merge this with the patch that drops the usage

> ---
> include/linux/fb.h | 1 -
> 1 file changed, 1 deletion(-)
>
> diff --git a/include/linux/fb.h b/include/linux/fb.h
> index 02f362c661c8..a8a00d2ba1f3 100644
> --- a/include/linux/fb.h
> +++ b/include/linux/fb.h
> @@ -449,7 +449,6 @@ struct fb_info {
> struct fb_var_screeninfo var; /* Current var */
> struct fb_fix_screeninfo fix; /* Current fix */
> struct fb_monspecs monspecs; /* Current Monitor specs */
> - struct work_struct queue; /* Framebuffer event queue */
> struct fb_pixmap pixmap; /* Image hardware mapper */
> struct fb_pixmap sprite; /* Cursor hardware mapper */
> struct fb_cmap cmap; /* Current cmap */
> --
> 2.33.0

2022-02-09 09:52:08

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 13/21] fbcon: move more common code into fb_open()

On Fri, Feb 04, 2022 at 08:35:31PM +0100, Sam Ravnborg wrote:
> On Mon, Jan 31, 2022 at 10:05:44PM +0100, Daniel Vetter wrote:
> > No idea why con2fb_acquire_newinfo() initializes much less than
> > fbcon_startup(), but so be it. From a quick look most of the
> > un-initialized stuff should be fairly harmless, but who knows.
> >
> > Signed-off-by: Daniel Vetter <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > Cc: Tetsuo Handa <[email protected]>
> > Cc: Thomas Zimmermann <[email protected]>
> > Cc: Claudio Suarez <[email protected]>
> > Cc: Du Cheng <[email protected]>
> > ---
> > drivers/video/fbdev/core/fbcon.c | 74 +++++++++++++-------------------
> > 1 file changed, 31 insertions(+), 43 deletions(-)
> >
> > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > index b83a5a77d8a8..5a3391ff038d 100644
> > --- a/drivers/video/fbdev/core/fbcon.c
> > +++ b/drivers/video/fbdev/core/fbcon.c
> > @@ -680,8 +680,18 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
> >
> > #endif /* CONFIG_MISC_TILEBLITTING */
> >
> > +static void fbcon_release(struct fb_info *info)
> > +{
> > + if (info->fbops->fb_release)
> > + info->fbops->fb_release(info, 0);
> > +
> > + module_put(info->fbops->owner);
> > +}
> > +
> > static int fbcon_open(struct fb_info *info)
> > {
> > + struct fbcon_ops *ops;
> > +
> > if (!try_module_get(info->fbops->owner))
> > return -ENODEV;
> >
> > @@ -691,19 +701,22 @@ static int fbcon_open(struct fb_info *info)
> > return -ENODEV;
> > }
> >
> > - return 0;
> > -}
> > + ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> > + if (!ops) {
> > + fbcon_release(info);
> > + return -ENOMEM;
> > + }
> >
> > -static void fbcon_release(struct fb_info *info)
> > -{
> > - if (info->fbops->fb_release)
> > - info->fbops->fb_release(info, 0);
> > + INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> > + ops->info = info;
> > + info->fbcon_par = ops;
> > + ops->cur_blink_jiffies = HZ / 5;
> >
> > - module_put(info->fbops->owner);
> > + return 0;
> > }
> >
> > static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> > - int unit, int oldidx)
> > + int unit)
> > {
> > struct fbcon_ops *ops = NULL;
> > int err;
> > @@ -712,27 +725,10 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> > if (err)
> > return err;
> >
> > - if (!err) {
> > - ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> > - if (!ops)
> > - err = -ENOMEM;
> > -
> > - INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> > - }
> > -
> > - if (!err) {
> > - ops->cur_blink_jiffies = HZ / 5;
> > - ops->info = info;
> > - info->fbcon_par = ops;
> > -
> > - if (vc)
> > - set_blitting_type(vc, info);
> > - }
> > + ops = info->fbcon_par;
> >
> > - if (err) {
> > - con2fb_map[unit] = oldidx;
> > - fbcon_release(info);
> > - }
> > + if (vc)
> > + set_blitting_type(vc, info);
> >
> > return err;
> > }
> > @@ -840,9 +836,11 @@ static int set_con2fb_map(int unit, int newidx, int user)
> >
> > found = search_fb_in_map(newidx);
> >
> > - con2fb_map[unit] = newidx;
> > - if (!err && !found)
> > - err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
> > + if (!err && !found) {
> > + err = con2fb_acquire_newinfo(vc, info, unit);
> > + if (!err)
> > + con2fb_map[unit] = newidx;
> > + }
> This looks like an unintentional change of functionality as con2fb_map[unit] is
> only assigned when we do a con2fb_acquire_newinfo().
>
> Staring at the code I could not say it is wrong, but not nice to hide
> the change in this patch.

Nope, it's not an unintentional bugfix. The old con2fb_acquire_newinfo did
reset con2fb_map to oldidx upon failure, which I've found to be a most
bizarre calling convention. So this sorts this out.

The reason I smashed this into the same patch is that I had to remove the
fbcon_release call, and so the error handling in there looked even more
funny. But I indeed failed to explain this all in the commit message.

Ack with that explainer, or do you want me to split this out properly?
-Daniel

>
> Sam
>
>
> >
> > /*
> > * If old fb is not mapped to any of the consoles,
> > @@ -939,20 +937,10 @@ static const char *fbcon_startup(void)
> > if (fbcon_open(info))
> > return NULL;
> >
> > - ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> > - if (!ops) {
> > - fbcon_release(info);
> > - return NULL;
> > - }
> > -
> > - INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> > -
> > + ops = info->fbcon_par;
> > ops->currcon = -1;
> > ops->graphics = 1;
> > ops->cur_rotate = -1;
> > - ops->cur_blink_jiffies = HZ / 5;
> > - ops->info = info;
> > - info->fbcon_par = ops;
> >
> > p->con_rotate = initial_rotation;
> > if (p->con_rotate == -1)
> > @@ -1022,7 +1010,7 @@ static void fbcon_init(struct vc_data *vc, int init)
> > return;
> >
> > if (!info->fbcon_par)
> > - con2fb_acquire_newinfo(vc, info, vc->vc_num, -1);
> > + con2fb_acquire_newinfo(vc, info, vc->vc_num);
> >
> > /* If we are not the first console on this
> > fb, copy the font from that console */
> > --
> > 2.33.0

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

2022-02-09 09:59:38

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 19/21] fbcon: Maintain a private array of fb_info

Hi Daniel,

On Tue, Feb 08, 2022 at 03:03:28PM +0100, Daniel Vetter wrote:
> On Fri, Feb 04, 2022 at 09:15:40PM +0100, Sam Ravnborg wrote:
> > Hi Daniel,
> >
> > On Mon, Jan 31, 2022 at 10:05:50PM +0100, Daniel Vetter wrote:
> > > Accessing the one in fbmem.c without taking the right locks is a bad
> > > idea. Instead maintain our own private copy, which is fully protected
> > > by console_lock() (like everything else in fbcon.c). That copy is
> > > serialized through fbcon_fb_registered/unregistered() calls.
> >
> > I fail to see why we can make a private copy of registered_fb
> > just like that - are they not somehow shared between fbcon and fbmem.
> > So when fbmem updates it, then fbcon will use the entry or such?
> >
> > I guess I am just ignorant of how registered_fb is used - but please
> > explain.
>
> The private copy is protected under console_lock, and hence safe to access
> from fbcon.c code.
>
> The main registered_fb array is protected by a different mutex, so we
> could indeed end up with hilarious corruption because the value is
> inconsistent while we try to access it (e.g. we check for !NULL, but later
> on gcc decides to reload the value and now it's suddenly become NULL and
> we blow up).
>
> The two are synchronized by fbmem.c calling fbcon_register/unregister, so
> aside from the different locks if there's no race going on, they will
> always be identical.
IT was this part that I missed, and it is already spelled out in the
commit message.

>
> Other option would be to roll out get_fb_info() to fbcon.c, but since
> fbcon.c is fully protected by console_lock that would add complexity in
> the code flow that we don't really need. And we'd have to wire fb_info
> through all call chains, since the right way to use get_fb_info is to look
> it up once and then only drop it when your callback has finished.
>
> Since the current code just assume it's all protected by console_lock and
> we never drop that during a callback this would mean major surgery and
> essentially refactoring all of fbcon.c to only access the fbcon stuff
> through fb_info, i.e. to get rid of _all_ the global arrays we have more
> or less. I'm not volunteering for that (despite that really this would be
> the right thing to do if we'd have infinite engineering time).
>
> Ack with that explainer added to the commit message?

I consider the current commit message fine - it helps when you actually
read it.

Acked-by: Sam Ravnborg <[email protected]>

2022-02-09 10:14:57

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 18/21] fbcon: untangle fbcon_exit

On Fri, Feb 04, 2022 at 09:06:38PM +0100, Sam Ravnborg wrote:
> Hi Daniel,
>
> On Mon, Jan 31, 2022 at 10:05:49PM +0100, Daniel Vetter wrote:
> > There's a bunch of confusions going on here:
> > - The deferred fbcon setup notifier should only be cleaned up from
> > fb_console_exit(), to be symmetric with fb_console_init()
> > - We also need to make sure we don't race with the work, which means
> > temporarily dropping the console lock (or we can deadlock)
> > - That also means no point in clearing deferred_takeover, we are
> > unloading everything anyway.
> > - Finally rename fbcon_exit to fbcon_release_all and move it, since
> > that's what's it doing when being called from consw->con_deinit
> > through fbcon_deinit.
> >
> > Signed-off-by: Daniel Vetter <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > Cc: Claudio Suarez <[email protected]>
> > Cc: Du Cheng <[email protected]>
> > Cc: Tetsuo Handa <[email protected]>
> > ---
> > drivers/video/fbdev/core/fbcon.c | 63 ++++++++++++++++----------------
> > 1 file changed, 32 insertions(+), 31 deletions(-)
> >
> > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > index 5c14e24d14a1..22581952b4fd 100644
> > --- a/drivers/video/fbdev/core/fbcon.c
> > +++ b/drivers/video/fbdev/core/fbcon.c
> > @@ -185,7 +185,6 @@ static void fbcon_set_disp(struct fb_info *info, struct fb_var_screeninfo *var,
> > int unit);
> > static void fbcon_modechanged(struct fb_info *info);
> > static void fbcon_set_all_vcs(struct fb_info *info);
> > -static void fbcon_exit(void);
> >
> > static struct device *fbcon_device;
> >
> > @@ -1149,6 +1148,27 @@ static void fbcon_free_font(struct fbcon_display *p, bool freefont)
> >
> > static void set_vc_hi_font(struct vc_data *vc, bool set);
> >
> > +static void fbcon_release_all(void)
> > +{
> > + struct fb_info *info;
> > + int i, j, mapped;
> > +
> > + for_each_registered_fb(i) {
> > + mapped = 0;
> > + info = registered_fb[i];
> > +
> > + for (j = first_fb_vc; j <= last_fb_vc; j++) {
> > + if (con2fb_map[j] == i) {
> > + mapped = 1;
> > + con2fb_map[j] = -1;
> > + }
> > + }
> > +
> > + if (mapped)
> > + fbcon_release(info);
> > + }
> > +}
> > +
> > static void fbcon_deinit(struct vc_data *vc)
> > {
> > struct fbcon_display *p = &fb_display[vc->vc_num];
> > @@ -1188,7 +1208,7 @@ static void fbcon_deinit(struct vc_data *vc)
> > set_vc_hi_font(vc, false);
> >
> > if (!con_is_bound(&fb_con))
> > - fbcon_exit();
> > + fbcon_release_all();
> >
> > if (vc->vc_num == logo_shown)
> > logo_shown = FBCON_LOGO_CANSHOW;
> > @@ -3316,34 +3336,6 @@ static void fbcon_start(void)
> > #endif
> > }
> >
> > -static void fbcon_exit(void)
> > -{
> > - struct fb_info *info;
> > - int i, j, mapped;
> > -
> > -#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
> > - if (deferred_takeover) {
> > - dummycon_unregister_output_notifier(&fbcon_output_nb);
> > - deferred_takeover = false;
> > - }
> > -#endif
> > -
> > - for_each_registered_fb(i) {
> > - mapped = 0;
> > - info = registered_fb[i];
> > -
> > - for (j = first_fb_vc; j <= last_fb_vc; j++) {
> > - if (con2fb_map[j] == i) {
> > - mapped = 1;
> > - con2fb_map[j] = -1;
> > - }
> > - }
> > -
> > - if (mapped)
> > - fbcon_release(info);
> > - }
> > -}
> > -
> > void __init fb_console_init(void)
> > {
> > int i;
> > @@ -3383,10 +3375,19 @@ static void __exit fbcon_deinit_device(void)
> >
> > void __exit fb_console_exit(void)
> > {
> > +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
> > + console_lock();
> > + if (deferred_takeover)
> > + dummycon_unregister_output_notifier(&fbcon_output_nb);
> > + console_unlock();
> > +
> > + cancel_work_sync(&fbcon_deferred_takeover_work);
> > +#endif
> > +
> > console_lock();
> > fbcon_deinit_device();
> > device_destroy(fb_class, MKDEV(0, 0));
> > - fbcon_exit();
> > +
> We loose the call to fbcon_release_all() here.
> We have part of the old fbcon_exit() above, but miss the release parts.
>
> Maybe I missed something obvious?

Ah yes that's the entire point of this change. The release_all in the
fbcon exit path was only needed when fbcon was a separate module
indepedent from core fb.ko. Which means it was possible to unload fbcon
while having fbdev drivers registered.

But since we've merged them that has become impossible, so by the time the
fb.ko module can be unloaded, there's guaranteed to be no fbdev drivers
left. And hence removing them is pointless.

Ack with that explainer added to the commit message?
-Daniel

>
> The rest looks fine.
>
> Sam
>
> > do_unregister_con_driver(&fb_con);
> > console_unlock();
> > }
> > --
> > 2.33.0

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

2022-02-09 10:21:55

by Daniel Vetter

[permalink] [raw]
Subject: Re: [PATCH 06/21] fbcon: delete delayed loading code

On Thu, Feb 03, 2022 at 09:45:29PM +0100, Sam Ravnborg wrote:
> Hi Daniel,
>
> On Mon, Jan 31, 2022 at 10:05:37PM +0100, Daniel Vetter wrote:
> > Before
> >
> > 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
> >
> > it was possible to load fbcon and fbdev drivers in any order, which
> > means that fbcon init had to handle the case where fbdev drivers where
> > already registered.
> >
> > This is no longer possible, hence delete that code.
> >
> > Note that the exit case is a bit more complex and will be done in a
> > separate patch.
> >
> > Signed-off-by: Daniel Vetter <[email protected]>
> > Cc: Helge Deller <[email protected]>
> > Cc: Daniel Vetter <[email protected]>
> > Cc: Claudio Suarez <[email protected]>
> > Cc: Greg Kroah-Hartman <[email protected]>
> > Cc: Tetsuo Handa <[email protected]>
> > Cc: Du Cheng <[email protected]>
> > ---
> > drivers/video/fbdev/core/fbcon.c | 13 +------------
> > 1 file changed, 1 insertion(+), 12 deletions(-)
> >
> > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > index 8f971de35885..814b648e8f09 100644
> > --- a/drivers/video/fbdev/core/fbcon.c
> > +++ b/drivers/video/fbdev/core/fbcon.c
> > @@ -942,7 +942,7 @@ static const char *fbcon_startup(void)
> > return display_desc;
> > /*
> > * Instead of blindly using registered_fb[0], we use info_idx, set by
> > - * fb_console_init();
> > + * fbcon_fb_registered();
> > */
> This comment change looks like it does not belong in this patch.
> Also, the comment is wrong as info_idx is set in several places.
> Like set_con2fb_map(), fbcon_remap_all(), and more.

Yeah I can split this out into a separate patch, but I spotted this wrong
comment as part of reviewing this code change here - essentially you have
to check how fb_info for fbcon are registered and fbcon init happens to
validate that deleting the below code is correct.

Ok if I put this explainer into the commit message, or do you want me to
split this out fully?
-Daniel

>
> Though it is not set by fb_console_init - so partly OK.
>
> With the comment adjustment dropped.
> Acked-by: Sam Ravnborg <[email protected]>
>
> at least the code deletion looked OK, I failed to follow all the logic.
> So would be good if someone else could ack it too.
>
> Sam
>
>
>
> > info = registered_fb[info_idx];
> > if (!info)
> > @@ -3316,17 +3316,6 @@ static void fbcon_start(void)
> > return;
> > }
> > #endif
> > -
> > - if (num_registered_fb) {
> > - int i;
> > -
> > - for_each_registered_fb(i) {
> > - info_idx = i;
> > - break;
> > - }
> > -
> > - do_fbcon_takeover(0);
> > - }
> > }
> >
> > static void fbcon_exit(void)
> > --
> > 2.33.0

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

2022-02-09 10:35:28

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 21/21] fbdev: Make registered_fb[] private to fbmem.c

Hi Daniel,

On Mon, Jan 31, 2022 at 10:05:52PM +0100, Daniel Vetter wrote:
> Well except when the olpc dcon fbdev driver is enabled, that thing
> digs around in there in rather unfixable ways.
>
> Cc oldc_dcon maintainers as fyi.
>
> Cc: Jens Frederich <[email protected]>
> Cc: Jon Nettleton <[email protected]>
> Cc: Greg Kroah-Hartman <[email protected]>
> Cc: [email protected]
> Signed-off-by: Daniel Vetter <[email protected]>
> Cc: Daniel Vetter <[email protected]>
> Cc: Helge Deller <[email protected]>
> Cc: Matthew Wilcox <[email protected]>
> Cc: Sam Ravnborg <[email protected]>
> Cc: Tetsuo Handa <[email protected]>
> Cc: Zhen Lei <[email protected]>
> Cc: Alex Deucher <[email protected]>
> Cc: Xiyu Yang <[email protected]>
> Cc: [email protected]
> Cc: Zheyu Ma <[email protected]>
> Cc: Guenter Roeck <[email protected]>

with the build thingy fixed:
Acked-by: Sam Ravnborg <[email protected]>

I do wonder if there is a more clean way to trigger a blank
in the main fbdev driver from the olpc driver.

The current hack is not nice and it would be good to see it gone.

Sam

> ---
> drivers/video/fbdev/core/fbmem.c | 8 ++++++--
> include/linux/fb.h | 7 +++----
> 2 files changed, 9 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/video/fbdev/core/fbmem.c b/drivers/video/fbdev/core/fbmem.c
> index 904ef1250677..dad6572942fa 100644
> --- a/drivers/video/fbdev/core/fbmem.c
> +++ b/drivers/video/fbdev/core/fbmem.c
> @@ -48,10 +48,14 @@
> static DEFINE_MUTEX(registration_lock);
>
> struct fb_info *registered_fb[FB_MAX] __read_mostly;
> -EXPORT_SYMBOL(registered_fb);
> -
> int num_registered_fb __read_mostly;
> +#if IS_ENABLED(CONFIG_OLPC_DCON)
> +EXPORT_SYMBOL(registered_fb);
> EXPORT_SYMBOL(num_registered_fb);
> +#endif
> +#define for_each_registered_fb(i) \
> + for (i = 0; i < FB_MAX; i++) \
> + if (!registered_fb[i]) {} else
>
> bool fb_center_logo __read_mostly;
>
> diff --git a/include/linux/fb.h b/include/linux/fb.h
> index a8a00d2ba1f3..e236817502c2 100644
> --- a/include/linux/fb.h
> +++ b/include/linux/fb.h
> @@ -622,16 +622,15 @@ extern int fb_get_color_depth(struct fb_var_screeninfo *var,
> extern int fb_get_options(const char *name, char **option);
> extern int fb_new_modelist(struct fb_info *info);
>
> +#if IS_ENABLED(CONFIG_OLPC_DCON)
> extern struct fb_info *registered_fb[FB_MAX];
> +
> extern int num_registered_fb;
> +#endif
> extern bool fb_center_logo;
> extern int fb_logo_count;
> extern struct class *fb_class;
>
> -#define for_each_registered_fb(i) \
> - for (i = 0; i < FB_MAX; i++) \
> - if (!registered_fb[i]) {} else
> -
> static inline void lock_fb_info(struct fb_info *info)
> {
> mutex_lock(&info->lock);
> --
> 2.33.0

2022-02-09 11:48:29

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 11/21] fbcon: Extract fbcon_open/release helpers

Hi Daniel,

On Tue, Feb 08, 2022 at 02:48:29PM +0100, Daniel Vetter wrote:
> On Thu, Feb 03, 2022 at 10:15:14PM +0100, Sam Ravnborg wrote:
> > Hi Daniel,
> >
> > On Mon, Jan 31, 2022 at 10:05:42PM +0100, Daniel Vetter wrote:
> > > There's two minor behaviour changes in here:
> > > - in error paths we now consistently call fb_ops->fb_release
> > > - fb_release really can't fail (fbmem.c ignores it too) and there's no
> > > reasonable cleanup we can do anyway.
> > >
> > > Signed-off-by: Daniel Vetter <[email protected]>
> > > Cc: Daniel Vetter <[email protected]>
> > > Cc: Claudio Suarez <[email protected]>
> > > Cc: Greg Kroah-Hartman <[email protected]>
> > > Cc: Tetsuo Handa <[email protected]>
> > > Cc: Du Cheng <[email protected]>
> > > ---
> > > drivers/video/fbdev/core/fbcon.c | 107 +++++++++++++++----------------
> > > 1 file changed, 53 insertions(+), 54 deletions(-)
> > >
> > > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > > index fa30e1909164..eea2ee14b64c 100644
> > > --- a/drivers/video/fbdev/core/fbcon.c
> > > +++ b/drivers/video/fbdev/core/fbcon.c
> > > @@ -680,19 +680,37 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
> > >
> > > #endif /* CONFIG_MISC_TILEBLITTING */
> > >
> > > +static int fbcon_open(struct fb_info *info)
> > > +{
> > > + if (!try_module_get(info->fbops->owner))
> > > + return -ENODEV;
> > > +
> > > + if (info->fbops->fb_open &&
> > > + info->fbops->fb_open(info, 0)) {
> > > + module_put(info->fbops->owner);
> > > + return -ENODEV;
> > > + }
> > > +
> > > + return 0;
> > > +}
> > > +
> > > +static void fbcon_release(struct fb_info *info)
> > > +{
> > > + if (info->fbops->fb_release)
> > > + info->fbops->fb_release(info, 0);
> > > +
> > > + module_put(info->fbops->owner);
> > > +}
> > >
> > > static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> > > int unit, int oldidx)
> > > {
> > > struct fbcon_ops *ops = NULL;
> > > - int err = 0;
> > > -
> > > - if (!try_module_get(info->fbops->owner))
> > > - err = -ENODEV;
> > > + int err;
> > >
> > > - if (!err && info->fbops->fb_open &&
> > > - info->fbops->fb_open(info, 0))
> > > - err = -ENODEV;
> > > + err = fbcon_open(info);
> > > + if (err)
> > > + return err;
> > >
> > > if (!err) {
> > > ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> > > @@ -713,7 +731,7 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> > >
> > > if (err) {
> > > con2fb_map[unit] = oldidx;
> > > - module_put(info->fbops->owner);
> > > + fbcon_release(info);
> > > }
> > >
> > > return err;
> > > @@ -724,45 +742,34 @@ static int con2fb_release_oldinfo(struct vc_data *vc, struct fb_info *oldinfo,
> > > int oldidx, int found)
> > > {
> > > struct fbcon_ops *ops = oldinfo->fbcon_par;
> > > - int err = 0, ret;
> > > + int ret;
> > >
> > > - if (oldinfo->fbops->fb_release &&
> > > - oldinfo->fbops->fb_release(oldinfo, 0)) {
> > > - con2fb_map[unit] = oldidx;
> > The old code assigns con2fb_map[unit] before is calls
> > newinfo->fbops->fb_release).
> > I wonder if there can be any callback to fbcon where the value
> > of con2fb_map[unit] matters?
>
> It's all protected by console_lock, so other threads cannot see the
> inconsistent state.
>
> Essentially everything in fbcon.c is protected by console_lock().
>
> Do you want me to hammer this in somewhere (maybe in the commit message),
> or good enough for your ack?

No need to spell it out more.
Add my a-b and apply it.

Sam

2022-02-09 11:49:07

by Sam Ravnborg

[permalink] [raw]
Subject: Re: [PATCH 13/21] fbcon: move more common code into fb_open()

On Tue, Feb 08, 2022 at 02:53:59PM +0100, Daniel Vetter wrote:
> On Fri, Feb 04, 2022 at 08:35:31PM +0100, Sam Ravnborg wrote:
> > On Mon, Jan 31, 2022 at 10:05:44PM +0100, Daniel Vetter wrote:
> > > No idea why con2fb_acquire_newinfo() initializes much less than
> > > fbcon_startup(), but so be it. From a quick look most of the
> > > un-initialized stuff should be fairly harmless, but who knows.
> > >
> > > Signed-off-by: Daniel Vetter <[email protected]>
> > > Cc: Daniel Vetter <[email protected]>
> > > Cc: Greg Kroah-Hartman <[email protected]>
> > > Cc: Tetsuo Handa <[email protected]>
> > > Cc: Thomas Zimmermann <[email protected]>
> > > Cc: Claudio Suarez <[email protected]>
> > > Cc: Du Cheng <[email protected]>
> > > ---
> > > drivers/video/fbdev/core/fbcon.c | 74 +++++++++++++-------------------
> > > 1 file changed, 31 insertions(+), 43 deletions(-)
> > >
> > > diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
> > > index b83a5a77d8a8..5a3391ff038d 100644
> > > --- a/drivers/video/fbdev/core/fbcon.c
> > > +++ b/drivers/video/fbdev/core/fbcon.c
> > > @@ -680,8 +680,18 @@ static int fbcon_invalid_charcount(struct fb_info *info, unsigned charcount)
> > >
> > > #endif /* CONFIG_MISC_TILEBLITTING */
> > >
> > > +static void fbcon_release(struct fb_info *info)
> > > +{
> > > + if (info->fbops->fb_release)
> > > + info->fbops->fb_release(info, 0);
> > > +
> > > + module_put(info->fbops->owner);
> > > +}
> > > +
> > > static int fbcon_open(struct fb_info *info)
> > > {
> > > + struct fbcon_ops *ops;
> > > +
> > > if (!try_module_get(info->fbops->owner))
> > > return -ENODEV;
> > >
> > > @@ -691,19 +701,22 @@ static int fbcon_open(struct fb_info *info)
> > > return -ENODEV;
> > > }
> > >
> > > - return 0;
> > > -}
> > > + ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> > > + if (!ops) {
> > > + fbcon_release(info);
> > > + return -ENOMEM;
> > > + }
> > >
> > > -static void fbcon_release(struct fb_info *info)
> > > -{
> > > - if (info->fbops->fb_release)
> > > - info->fbops->fb_release(info, 0);
> > > + INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> > > + ops->info = info;
> > > + info->fbcon_par = ops;
> > > + ops->cur_blink_jiffies = HZ / 5;
> > >
> > > - module_put(info->fbops->owner);
> > > + return 0;
> > > }
> > >
> > > static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> > > - int unit, int oldidx)
> > > + int unit)
> > > {
> > > struct fbcon_ops *ops = NULL;
> > > int err;
> > > @@ -712,27 +725,10 @@ static int con2fb_acquire_newinfo(struct vc_data *vc, struct fb_info *info,
> > > if (err)
> > > return err;
> > >
> > > - if (!err) {
> > > - ops = kzalloc(sizeof(struct fbcon_ops), GFP_KERNEL);
> > > - if (!ops)
> > > - err = -ENOMEM;
> > > -
> > > - INIT_DELAYED_WORK(&ops->cursor_work, fb_flashcursor);
> > > - }
> > > -
> > > - if (!err) {
> > > - ops->cur_blink_jiffies = HZ / 5;
> > > - ops->info = info;
> > > - info->fbcon_par = ops;
> > > -
> > > - if (vc)
> > > - set_blitting_type(vc, info);
> > > - }
> > > + ops = info->fbcon_par;
> > >
> > > - if (err) {
> > > - con2fb_map[unit] = oldidx;
> > > - fbcon_release(info);
> > > - }
> > > + if (vc)
> > > + set_blitting_type(vc, info);
> > >
> > > return err;
> > > }
> > > @@ -840,9 +836,11 @@ static int set_con2fb_map(int unit, int newidx, int user)
> > >
> > > found = search_fb_in_map(newidx);
> > >
> > > - con2fb_map[unit] = newidx;
> > > - if (!err && !found)
> > > - err = con2fb_acquire_newinfo(vc, info, unit, oldidx);
> > > + if (!err && !found) {
> > > + err = con2fb_acquire_newinfo(vc, info, unit);
> > > + if (!err)
> > > + con2fb_map[unit] = newidx;
> > > + }
> > This looks like an unintentional change of functionality as con2fb_map[unit] is
> > only assigned when we do a con2fb_acquire_newinfo().
> >
> > Staring at the code I could not say it is wrong, but not nice to hide
> > the change in this patch.
>
> Nope, it's not an unintentional bugfix. The old con2fb_acquire_newinfo did
> reset con2fb_map to oldidx upon failure, which I've found to be a most
> bizarre calling convention. So this sorts this out.
>
> The reason I smashed this into the same patch is that I had to remove the
> fbcon_release call, and so the error handling in there looked even more
> funny. But I indeed failed to explain this all in the commit message.
>
> Ack with that explainer, or do you want me to split this out properly?

Please update the commit message, then this patch has my:
Acked-by: Sam Ravnborg <[email protected]>