Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S941369AbcJaMP0 (ORCPT ); Mon, 31 Oct 2016 08:15:26 -0400 Received: from mailapp01.imgtec.com ([195.59.15.196]:25424 "EHLO mailapp01.imgtec.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1764472AbcJaMPY (ORCPT ); Mon, 31 Oct 2016 08:15:24 -0400 From: Paul Burton To: Michael Ellerman CC: Paul Burton , Andreas Schwab , Andrew Morton , Borislav Petkov , Larry Finger , Petr Mladek , Sergey Senozhatsky , Tejun Heo , , Subject: [PATCH v2] console: use first console if stdout-path device doesn't appear Date: Mon, 31 Oct 2016 12:14:55 +0000 Message-ID: <20161031121455.23280-1-paul.burton@imgtec.com> X-Mailer: git-send-email 2.10.1 In-Reply-To: <87zill13z8.fsf@concordia.ellerman.id.au> References: <87zill13z8.fsf@concordia.ellerman.id.au> MIME-Version: 1.0 Content-Type: text/plain X-Originating-IP: [10.100.200.177] Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 5307 Lines: 155 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. 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) { -- 2.10.1