On Monday, 31 October 2016 12:14:55 GMT Paul Burton wrote: > If a device tree specified a preferred device for kernel console output > via the stdout-path or linux,stdout-path chosen node properties there's > no guarantee that it will have specified a device for which we have a > driver. It may also be the case that we do have a driver but it doesn't > call of_console_check() to register as a preferred console (eg. offb > driver as used on powermac systems). In these cases try to ensure that > we provide some console output by enabling the first usable registered > console, which we keep track of with the of_fallback_console variable. > > Tested in QEMU with a PowerPC pseries_defconfig kernel. Actually whilst this fixes the output in QEMU it has other problems. I'm still digging... Thanks, Paul > > Signed-off-by: Paul Burton > Fixes: 05fd007e4629 ("console: don't prefer first registered if DT specifies > stdout-path") Reported-by: Andreas Schwab > Reported-by: Larry Finger > Reported-by: Michael Ellerman > Cc: Andreas Schwab > Cc: Andrew Morton > Cc: Borislav Petkov > Cc: Larry Finger > Cc: Michael Ellerman > Cc: Petr Mladek > Cc: Sergey Senozhatsky > Cc: Tejun Heo > Cc: linux-kernel@vger.kernel.org > Cc: linuxppc-dev@lists.ozlabs.org > > --- > > Changes in v2: > - Split enable_console() out of register_console() & call in the fallback > case. - Track the console we would have enabled as of_fallback_console. > > kernel/printk/printk.c | 60 > +++++++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 55 > insertions(+), 5 deletions(-) > > diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c > index de08fc9..b02c00a 100644 > --- a/kernel/printk/printk.c > +++ b/kernel/printk/printk.c > @@ -264,6 +264,13 @@ void console_set_by_of(void) > # define of_specified_console false > #endif > > +/* > + * The first usable console, which we'll fall back to using if the system > + * uses a device tree which indicates a stdout-path device for which we > + * have no driver, or for which our driver doesn't call of_console_check(). > + */ > +static struct console *of_fallback_console; > + > /* Flag: console code may call schedule() */ > static int console_may_schedule; > > @@ -2598,6 +2605,8 @@ static int __init keep_bootcon_setup(char *str) > > early_param("keep_bootcon", keep_bootcon_setup); > > +static void enable_console(struct console *newcon); > + > /* > * The console driver calls this routine during kernel initialization > * to register the console printing procedure with printk() and to > @@ -2620,7 +2629,6 @@ early_param("keep_bootcon", keep_bootcon_setup); > void register_console(struct console *newcon) > { > int i; > - unsigned long flags; > struct console *bcon = NULL; > struct console_cmdline *c; > > @@ -2657,7 +2665,9 @@ void register_console(struct console *newcon) > * didn't select a console we take the first one > * that registers here. > */ > - if (preferred_console < 0 && !of_specified_console) { > + if (preferred_console < 0 && of_specified_console) { > + of_fallback_console = of_fallback_console ?: newcon; > + } else if (preferred_console < 0) { > if (newcon->index < 0) > newcon->index = 0; > if (newcon->setup == NULL || > @@ -2705,8 +2715,18 @@ void register_console(struct console *newcon) > break; > } > > - if (!(newcon->flags & CON_ENABLED)) > - return; > + if (newcon->flags & CON_ENABLED) > + enable_console(newcon); > +} > +EXPORT_SYMBOL(register_console); > + > +static void enable_console(struct console *newcon) > +{ > + struct console *bcon = NULL; > + unsigned long flags; > + > + if (console_drivers && console_drivers->flags & CON_BOOT) > + bcon = console_drivers; > > /* > * If we have a bootconsole, and are switching to a real console, > @@ -2777,7 +2797,6 @@ void register_console(struct console *newcon) > unregister_console(bcon); > } > } > -EXPORT_SYMBOL(register_console); > > int unregister_console(struct console *console) > { > @@ -2839,10 +2858,41 @@ EXPORT_SYMBOL(unregister_console); > * intersects with the init section. Note that code exists elsewhere to get > * rid of the boot console as soon as the proper console shows up, so there > * won't be side-effects from postponing the removal. > + * > + * Additionally we may be using a device tree which specifies valid > + * stdout-path referencing a device for which we don't have a driver, or > for + * which we have a driver that doesn't register itself as preferred > console + * using of_console_check(). In these cases we attempt here to > enable the + * first usable registered console, which we assigned to > of_fallback_console. */ > static int __init printk_late_init(void) > { > struct console *con; > + bool any_enabled = false; > + > + for_each_console(con) { > + if (!(con->flags & CON_ENABLED)) > + continue; > + > + any_enabled = true; > + break; > + } > + > + if (!any_enabled && of_fallback_console) { > + if (of_fallback_console->index < 0) > + of_fallback_console->index = 0; > + > + if (!of_fallback_console->setup || > + !of_fallback_console->setup(of_fallback_console, NULL)) { > + of_fallback_console->flags |= CON_ENABLED; > + if (of_fallback_console->device) { > + of_fallback_console->flags |= CON_CONSDEV; > + preferred_console = 0; > + } > + } > + > + enable_console(of_fallback_console); > + } > > for_each_console(con) { > if (!keep_bootcon && con->flags & CON_BOOT) {