Subject: [PATCH] earlycon: Fix earlycon/console handover without options commit c7cef0a84912 ("console: Add extensible console matching") broke the earlycon/handover when booting console=uart8250,io,0x3f8 the bootloader is using 115200, and the earlycon continue use 115200, but console revert back to 9600. Before the commit, probed baud rate is passed via console_cmdline from earlycon to normal console. That commit remove that and only check boot command line. This patch use port match to get hold earlycon, and use earlycon device options to update options for console. Fixes: commit c7cef0a84912 ("console: Add extensible console matching") Signed-off-by: Yinghai Lu --- drivers/tty/serial/8250/8250_core.c | 14 ++++++++++++-- drivers/tty/serial/8250/8250_early.c | 19 +++++++++++++++++++ include/linux/console.h | 2 +- include/linux/serial_8250.h | 1 + kernel/printk/printk.c | 2 +- 5 files changed, 34 insertions(+), 4 deletions(-) Index: linux-2.6/drivers/tty/serial/8250/8250_core.c =================================================================== --- linux-2.6.orig/drivers/tty/serial/8250/8250_core.c +++ linux-2.6/drivers/tty/serial/8250/8250_core.c @@ -3452,7 +3452,7 @@ static int univ8250_console_setup(struct * @co: registering console * @name: name from console command line * @idx: index from console command line - * @options: ptr to option string from console command line + * @options_p: ptr to ptr to option string from console command line * * Only attempts to match console command lines of the form: * console=uart<>,io|mmio|mmio32,, @@ -3465,11 +3465,12 @@ static int univ8250_console_setup(struct * Returns 0 if console matches; otherwise non-zero to use default matching */ static int univ8250_console_match(struct console *co, char *name, int idx, - char *options) + char **options_p) { char match[] = "uart"; /* 8250-specific earlycon name */ unsigned char iotype; unsigned long addr; + char *options = *options_p; int i; if (strncmp(name, match, 4) != 0) @@ -3491,6 +3492,15 @@ static int univ8250_console_match(struct continue; co->index = i; + + if (!options || !options[0]) { + char *new_options = NULL; + + if (!serial8250_get_earlycon_options(port, + &new_options)) + options = *options_p = new_options; + } + return univ8250_console_setup(co, options); } Index: linux-2.6/drivers/tty/serial/8250/8250_early.c =================================================================== --- linux-2.6.orig/drivers/tty/serial/8250/8250_early.c +++ linux-2.6/drivers/tty/serial/8250/8250_early.c @@ -105,6 +105,24 @@ static void __init early_serial8250_writ serial8250_early_out(port, UART_IER, ier); } +static struct earlycon_device *early_device; + +int serial8250_get_earlycon_options(struct uart_port *up, char **options_p) +{ + struct earlycon_device *device = early_device; + struct uart_port *port = device ? &device->port : NULL; + + if (!port || (!port->membase && !port->iobase)) + return -ENODEV; + + if (!uart_match_port(up, port)) + return -ENODEV; + + *options_p = device->options; + + return 0; +} + static unsigned int __init probe_baud(struct uart_port *port) { unsigned char lcr, dll, dlm; @@ -161,6 +179,7 @@ static int __init early_serial8250_setup } else init_port(device); + early_device = device; device->con->write = early_serial8250_write; return 0; } Index: linux-2.6/include/linux/serial_8250.h =================================================================== --- linux-2.6.orig/include/linux/serial_8250.h +++ linux-2.6/include/linux/serial_8250.h @@ -135,6 +135,7 @@ void serial8250_resume_port(int line); extern int early_serial_setup(struct uart_port *port); +extern int serial8250_get_earlycon_options(struct uart_port *up, char **p); extern unsigned int serial8250_early_in(struct uart_port *port, int offset); extern void serial8250_early_out(struct uart_port *port, int offset, int value); extern void serial8250_do_set_termios(struct uart_port *port, Index: linux-2.6/kernel/printk/printk.c =================================================================== --- linux-2.6.orig/kernel/printk/printk.c +++ linux-2.6/kernel/printk/printk.c @@ -2444,7 +2444,7 @@ void register_console(struct console *ne i < MAX_CMDLINECONSOLES && c->name[0]; i++, c++) { if (!newcon->match || - newcon->match(newcon, c->name, c->index, c->options) != 0) { + !newcon->match(newcon, c->name, c->index, &c->options)) { /* default matching */ BUILD_BUG_ON(sizeof(c->name) != sizeof(newcon->name)); if (strcmp(c->name, newcon->name) != 0) Index: linux-2.6/include/linux/console.h =================================================================== --- linux-2.6.orig/include/linux/console.h +++ linux-2.6/include/linux/console.h @@ -123,7 +123,7 @@ struct console { struct tty_driver *(*device)(struct console *, int *); void (*unblank)(void); int (*setup)(struct console *, char *); - int (*match)(struct console *, char *name, int idx, char *options); + int (*match)(struct console *, char *name, int idx, char **p); short flags; short index; int cflag;