lkml.org 
[lkml]   [2018]   [Jun]   [28]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    /
    SubjectRe: [PATCH v3 3/3] console/fbcon: Add support for deferred console takeover
    From
    Date
    Hi,

    On 28-06-18 09:55, Daniel Vetter wrote:
    > On Tue, Jun 26, 2018 at 08:36:12PM +0200, Hans de Goede wrote:
    >> Currently fbcon claims fbdevs as soon as they are registered and takes over
    >> the console as soon as the first fbdev gets registered.
    >>
    >> This behavior is undesirable in cases where a smooth graphical bootup is
    >> desired, in such cases we typically want the contents of the framebuffer
    >> (typically a vendor logo) to stay in place as is.
    >>
    >> The current solution for this problem (on embedded systems) is to not
    >> enable fbcon.
    >>
    >> This commit adds a new FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER config option,
    >> which when enabled defers fbcon taking over the console from the dummy
    >> console until the first text is displayed on the console. Together with the
    >> "quiet" kernel commandline option, this allows fbcon to still be used
    >> together with a smooth graphical bootup, having it take over the console as
    >> soon as e.g. an error message is logged.
    >>
    >> Reviewed-by: Daniel Vetter <daniel.vetter@ffwll.ch>
    >> Signed-off-by: Hans de Goede <hdegoede@redhat.com>
    >
    > A bit a late comment, and feel free to reject: Have you considered
    > registering the fbcon driver, but not doing any modesets until the very
    > first real message shows up?

    I have tried something like that, but it did not work out, this patch-set
    actually is my 3th attempt at this (the other 2 were never posted
    because they did not work).

    The fbcon code is woven quite tightly into the console code, so this was
    the only clean way I could find to achieve what I want.

    Regards,

    Hans


    >> ---
    >> Changes in v2:
    >> -Check the whole string when checking for erases in putcs, instead of just
    >> the first char
    >> -Make dummycon_blank return 1, so that a redraw gets triggered and any text
    >> rendered while blanked gets output so that it can trigger a deferred
    >> takeover if one is pending
    >>
    >> Changes in v3:
    >> -Call WARN_CONSOLE_UNLOCKED() from fbcon_output_notifier()
    >> -Unregister the notifier on fbcon_exit()
    >> -Document the fbcon=nodefer commandline option in Documentation/fb/fbcon.txt
    >> ---
    >> Documentation/fb/fbcon.txt | 7 ++++
    >> drivers/video/console/Kconfig | 11 +++++
    >> drivers/video/console/dummycon.c | 67 +++++++++++++++++++++++++----
    >> drivers/video/fbdev/core/fbcon.c | 72 ++++++++++++++++++++++++++++++++
    >> include/linux/console.h | 5 +++
    >> 5 files changed, 154 insertions(+), 8 deletions(-)
    >>
    >> diff --git a/Documentation/fb/fbcon.txt b/Documentation/fb/fbcon.txt
    >> index 79c22d096bbc..d4d642e1ce9c 100644
    >> --- a/Documentation/fb/fbcon.txt
    >> +++ b/Documentation/fb/fbcon.txt
    >> @@ -155,6 +155,13 @@ C. Boot options
    >> used by text. By default, this area will be black. The 'color' value
    >> is an integer number that depends on the framebuffer driver being used.
    >>
    >> +6. fbcon=nodefer
    >> +
    >> + If the kernel is compiled with deferred fbcon takeover support, normally
    >> + the framebuffer contents, left in place by the firmware/bootloader, will
    >> + be preserved until there actually is some text is output to the console.
    >> + This option causes fbcon to bind immediately to the fbdev device.
    >> +
    >> C. Attaching, Detaching and Unloading
    >>
    >> Before going on how to attach, detach and unload the framebuffer console, an
    >> diff --git a/drivers/video/console/Kconfig b/drivers/video/console/Kconfig
    >> index 4110ba7d7ca9..e91edef98633 100644
    >> --- a/drivers/video/console/Kconfig
    >> +++ b/drivers/video/console/Kconfig
    >> @@ -150,6 +150,17 @@ config FRAMEBUFFER_CONSOLE_ROTATION
    >> such that other users of the framebuffer will remain normally
    >> oriented.
    >>
    >> +config FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
    >> + bool "Framebuffer Console Deferred Takeover"
    >> + depends on FRAMEBUFFER_CONSOLE=y && DUMMY_CONSOLE=y
    >> + help
    >> + If enabled this defers the framebuffer console taking over the
    >> + console from the dummy console until the first text is displayed on
    >> + the console. This is useful in combination with the "quiet" kernel
    >> + commandline option to keep the framebuffer contents initially put up
    >> + by the firmware in place, rather then replacing the contents with a
    >> + black screen as soon as fbcon loads.
    >> +
    >> config STI_CONSOLE
    >> bool "STI text console"
    >> depends on PARISC && HAS_IOMEM
    >> diff --git a/drivers/video/console/dummycon.c b/drivers/video/console/dummycon.c
    >> index f2eafe2ed980..45ad925ad5f8 100644
    >> --- a/drivers/video/console/dummycon.c
    >> +++ b/drivers/video/console/dummycon.c
    >> @@ -26,6 +26,65 @@
    >> #define DUMMY_ROWS CONFIG_DUMMY_CONSOLE_ROWS
    >> #endif
    >>
    >> +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
    >> +/* These are both protected by the console_lock */
    >> +static RAW_NOTIFIER_HEAD(dummycon_output_nh);
    >> +static bool dummycon_putc_called;
    >> +
    >> +void dummycon_register_output_notifier(struct notifier_block *nb)
    >> +{
    >> + raw_notifier_chain_register(&dummycon_output_nh, nb);
    >> +
    >> + if (dummycon_putc_called)
    >> + nb->notifier_call(nb, 0, NULL);
    >> +}
    >> +
    >> +void dummycon_unregister_output_notifier(struct notifier_block *nb)
    >> +{
    >> + raw_notifier_chain_unregister(&dummycon_output_nh, nb);
    >> +}
    >> +
    >> +static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos)
    >> +{
    >> + dummycon_putc_called = true;
    >> + raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
    >> +}
    >> +
    >> +static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
    >> + int count, int ypos, int xpos)
    >> +{
    >> + int i;
    >> +
    >> + if (!dummycon_putc_called) {
    >> + /* Ignore erases */
    >> + for (i = 0 ; i < count; i++) {
    >> + if (s[i] != vc->vc_video_erase_char)
    >> + break;
    >> + }
    >> + if (i == count)
    >> + return;
    >> +
    >> + dummycon_putc_called = true;
    >> + }
    >> +
    >> + raw_notifier_call_chain(&dummycon_output_nh, 0, NULL);
    >> +}
    >> +
    >> +static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
    >> +{
    >> + /* Redraw, so that we get putc(s) for output done while blanked */
    >> + return 1;
    >> +}
    >> +#else
    >> +static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
    >> +static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
    >> + int count, int ypos, int xpos) { }
    >> +static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
    >> +{
    >> + return 0;
    >> +}
    >> +#endif
    >> +
    >> static const char *dummycon_startup(void)
    >> {
    >> return "dummy device";
    >> @@ -44,9 +103,6 @@ static void dummycon_init(struct vc_data *vc, int init)
    >> static void dummycon_deinit(struct vc_data *vc) { }
    >> static void dummycon_clear(struct vc_data *vc, int sy, int sx, int height,
    >> int width) { }
    >> -static void dummycon_putc(struct vc_data *vc, int c, int ypos, int xpos) { }
    >> -static void dummycon_putcs(struct vc_data *vc, const unsigned short *s,
    >> - int count, int ypos, int xpos) { }
    >> static void dummycon_cursor(struct vc_data *vc, int mode) { }
    >>
    >> static bool dummycon_scroll(struct vc_data *vc, unsigned int top,
    >> @@ -61,11 +117,6 @@ static int dummycon_switch(struct vc_data *vc)
    >> return 0;
    >> }
    >>
    >> -static int dummycon_blank(struct vc_data *vc, int blank, int mode_switch)
    >> -{
    >> - return 0;
    >> -}
    >> -
    >> static int dummycon_font_set(struct vc_data *vc, struct console_font *font,
    >> unsigned int flags)
    >> {
    >> diff --git a/drivers/video/fbdev/core/fbcon.c b/drivers/video/fbdev/core/fbcon.c
    >> index cd8d52a967aa..5fb156bdcf4e 100644
    >> --- a/drivers/video/fbdev/core/fbcon.c
    >> +++ b/drivers/video/fbdev/core/fbcon.c
    >> @@ -129,6 +129,12 @@ static inline void fbcon_map_override(void)
    >> }
    >> #endif /* CONFIG_FRAMEBUFFER_CONSOLE_DETECT_PRIMARY */
    >>
    >> +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
    >> +static bool deferred_takeover = true;
    >> +#else
    >> +#define deferred_takeover false
    >> +#endif
    >> +
    >> /* font data */
    >> static char fontname[40];
    >>
    >> @@ -499,6 +505,12 @@ static int __init fb_console_setup(char *this_opt)
    >> margin_color = simple_strtoul(options, &options, 0);
    >> continue;
    >> }
    >> +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
    >> + if (!strcmp(options, "nodefer")) {
    >> + deferred_takeover = false;
    >> + continue;
    >> + }
    >> +#endif
    >> }
    >> return 1;
    >> }
    >> @@ -3100,6 +3112,9 @@ static int fbcon_fb_unregistered(struct fb_info *info)
    >>
    >> WARN_CONSOLE_UNLOCKED();
    >>
    >> + if (deferred_takeover)
    >> + return 0;
    >> +
    >> idx = info->node;
    >> for (i = first_fb_vc; i <= last_fb_vc; i++) {
    >> if (con2fb_map[i] == idx)
    >> @@ -3140,6 +3155,13 @@ static void fbcon_remap_all(int idx)
    >>
    >> WARN_CONSOLE_UNLOCKED();
    >>
    >> + if (deferred_takeover) {
    >> + for (i = first_fb_vc; i <= last_fb_vc; i++)
    >> + con2fb_map_boot[i] = idx;
    >> + fbcon_map_override();
    >> + return;
    >> + }
    >> +
    >> for (i = first_fb_vc; i <= last_fb_vc; i++)
    >> set_con2fb_map(i, idx, 0);
    >>
    >> @@ -3191,6 +3213,11 @@ static int fbcon_fb_registered(struct fb_info *info)
    >> idx = info->node;
    >> fbcon_select_primary(info);
    >>
    >> + if (deferred_takeover) {
    >> + pr_info("fbcon: Deferring console take-over\n");
    >> + return 0;
    >> + }
    >> +
    >> if (info_idx == -1) {
    >> for (i = first_fb_vc; i <= last_fb_vc; i++) {
    >> if (con2fb_map_boot[i] == idx) {
    >> @@ -3566,8 +3593,46 @@ static int fbcon_init_device(void)
    >> return 0;
    >> }
    >>
    >> +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
    >> +static struct notifier_block fbcon_output_nb;
    >> +
    >> +static int fbcon_output_notifier(struct notifier_block *nb,
    >> + unsigned long action, void *data)
    >> +{
    >> + int i;
    >> +
    >> + WARN_CONSOLE_UNLOCKED();
    >> +
    >> + pr_info("fbcon: Taking over console\n");
    >> +
    >> + dummycon_unregister_output_notifier(&fbcon_output_nb);
    >> + deferred_takeover = false;
    >> + logo_shown = FBCON_LOGO_DONTSHOW;
    >> +
    >> + for (i = 0; i < FB_MAX; i++) {
    >> + if (registered_fb[i])
    >> + fbcon_fb_registered(registered_fb[i]);
    >> + }
    >> +
    >> + return NOTIFY_OK;
    >> +}
    >> +
    >> +static void fbcon_register_output_notifier(void)
    >> +{
    >> + fbcon_output_nb.notifier_call = fbcon_output_notifier;
    >> + dummycon_register_output_notifier(&fbcon_output_nb);
    >> +}
    >> +#else
    >> +static inline void fbcon_register_output_notifier(void) {}
    >> +#endif
    >> +
    >> static void fbcon_start(void)
    >> {
    >> + if (deferred_takeover) {
    >> + fbcon_register_output_notifier();
    >> + return;
    >> + }
    >> +
    >> if (num_registered_fb) {
    >> int i;
    >>
    >> @@ -3594,6 +3659,13 @@ static void fbcon_exit(void)
    >> if (fbcon_has_exited)
    >> return;
    >>
    >> +#ifdef CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER
    >> + if (deferred_takeover) {
    >> + dummycon_unregister_output_notifier(&fbcon_output_nb);
    >> + deferred_takeover = false;
    >> + }
    >> +#endif
    >> +
    >> kfree((void *)softback_buf);
    >> softback_buf = 0UL;
    >>
    >> diff --git a/include/linux/console.h b/include/linux/console.h
    >> index dfd6b0e97855..f59f3dbca65c 100644
    >> --- a/include/linux/console.h
    >> +++ b/include/linux/console.h
    >> @@ -21,6 +21,7 @@ struct console_font_op;
    >> struct console_font;
    >> struct module;
    >> struct tty_struct;
    >> +struct notifier_block;
    >>
    >> /*
    >> * this is what the terminal answers to a ESC-Z or csi0c query.
    >> @@ -220,4 +221,8 @@ static inline bool vgacon_text_force(void) { return false; }
    >>
    >> extern void console_init(void);
    >>
    >> +/* For deferred console takeover */
    >> +void dummycon_register_output_notifier(struct notifier_block *nb);
    >> +void dummycon_unregister_output_notifier(struct notifier_block *nb);
    >> +
    >> #endif /* _LINUX_CONSOLE_H */
    >> --
    >> 2.17.1
    >>
    >> _______________________________________________
    >> dri-devel mailing list
    >> dri-devel@lists.freedesktop.org
    >> https://lists.freedesktop.org/mailman/listinfo/dri-devel
    >

    \
     
     \ /
      Last update: 2018-06-28 10:21    [W:4.274 / U:0.056 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site