Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

tty: serial: sh-sci: use setup() callback for early console

When setting up the early console, the setup() callback of the
regular console is used. It is called manually before registering
the early console instead of providing a setup() callback for the
early console. This is probably because the early setup needs a
different @options during the early stage.

The issue here is that the setup() callback is called without the
console_list_lock held and functions such as uart_set_options()
expect that.

Rather than manually calling the setup() function before registering,
provide an early console setup() callback that will use the different
early options. This ensures that the error checking, ordering, and
locking context when setting up the early console are correct.

Since this early console can only be registered via the earlyprintk=
parameter, the @options argument of the setup() callback will always
be NULL. Rather than simply ignoring the argument, add a WARN_ON()
to get our attention in case the setup() callback semantics should
change in the future.

Note that technically the current implementation works because it is
only used in early boot. And since the early console setup is
performed before registering, it cannot race with anything and thus
does not need any locking. However, longterm maintenance is easier
when drivers rely on the subsystem API rather than manually
implementing steps that could cause breakage in the future.

Signed-off-by: John Ogness <john.ogness@linutronix.de>
Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>
Reviewed-by: Petr Mladek <pmladek@suse.com>
Signed-off-by: Petr Mladek <pmladek@suse.com>
Link: https://lore.kernel.org/r/20221116162152.193147-41-john.ogness@linutronix.de

authored by

John Ogness and committed by
Petr Mladek
ff707dfd 848a9c10

+16 -4
+16 -4
drivers/tty/serial/sh-sci.c
··· 3054 3054 }; 3055 3055 3056 3056 #ifdef CONFIG_SUPERH 3057 + static char early_serial_buf[32]; 3058 + 3059 + static int early_serial_console_setup(struct console *co, char *options) 3060 + { 3061 + /* 3062 + * This early console is always registered using the earlyprintk= 3063 + * parameter, which does not call add_preferred_console(). Thus 3064 + * @options is always NULL and the options for this early console 3065 + * are passed using a custom buffer. 3066 + */ 3067 + WARN_ON(options); 3068 + 3069 + return serial_console_setup(co, early_serial_buf); 3070 + } 3071 + 3057 3072 static struct console early_serial_console = { 3058 3073 .name = "early_ttySC", 3059 3074 .write = serial_console_write, 3075 + .setup = early_serial_console_setup, 3060 3076 .flags = CON_PRINTBUFFER, 3061 3077 .index = -1, 3062 3078 }; 3063 - 3064 - static char early_serial_buf[32]; 3065 3079 3066 3080 static int sci_probe_earlyprintk(struct platform_device *pdev) 3067 3081 { ··· 3087 3073 early_serial_console.index = pdev->id; 3088 3074 3089 3075 sci_init_single(pdev, &sci_ports[pdev->id], pdev->id, cfg, true); 3090 - 3091 - serial_console_setup(&early_serial_console, early_serial_buf); 3092 3076 3093 3077 if (!strstr(early_serial_buf, "keep")) 3094 3078 early_serial_console.flags |= CON_BOOT;