On Wed, Apr 1, 2015 at 8:22 PM, Peter Hurley <peter@xxxxxxxxxxxxxxxxxx> wrote: > The documented behavior of console=ttyS options, to which your > quote refers, clearly states: > > Default is "9600n8". drivers/tty/serial/8250/8250_early.c:early_serial8250_setup still have calling to probe_baud, but it is not triggered. Here is root cause. The gap between entries in earlycon_table cause iteration fail to find next entry, so uart8250 handler is not called proplerly. attached patch fix the problem. Thanks Yinghai
Subject: [PATCH] serial: Fix earlycon section iteration Found when booting with console=uart8250,io,0x3f8 the kernel will revert baud rate to 9600 instead of keeping 115200. root causes: The gap between entries in earlycon_table cause iteration fail to find next entry, so uart8250 handler is not called proplerly. commit d2fd6810a823 ("tty/serial: convert 8250 to generic earlycon") add two entries into earlycon_table. EARLYCON_DECLARE(uart8250, early_serial8250_setup); EARLYCON_DECLARE(uart, early_serial8250_setup); and according to System.map, earlycon_uart is before earlycon_uart8250. ffffffff832049a0 t __earlycon_uart ffffffff832049c0 t __earlycon_uart8250 And offset between two entries is 0x20. commit 470ca0de69fe ("serial: earlycon: Enable earlycon without command line param") setup_earlycon() will loop __earlycon_table with pointer to earlycon_id, for (match = __earlycon_table; match->name[0]; match++) { size_t len = strlen(match->name); if (strncmp(buf, match->name, len)) continue; but match size (size of struct earlycon_id) is only 0x18. so will point to wrong place for next match and will get random result. Make the earlycon_table section have pointer to earlycon_id struct instead. Fixes: commit 470ca0de69fe ("serial: earlycon: Enable earlycon without command line param") Signed-off-by: Yinghai Lu <yinghai@xxxxxxxxxx> --- drivers/tty/serial/earlycon.c | 13 +++++++------ include/asm-generic/vmlinux.lds.h | 8 ++++---- include/linux/serial_core.h | 8 +++++--- 3 files changed, 16 insertions(+), 13 deletions(-) Index: linux-2.6/include/linux/serial_core.h =================================================================== --- linux-2.6.orig/include/linux/serial_core.h +++ linux-2.6/include/linux/serial_core.h @@ -349,10 +349,12 @@ extern int of_setup_earlycon(unsigned lo int (*setup)(struct earlycon_device *, const char *)); #define EARLYCON_DECLARE(_name, func) \ - static const struct earlycon_id __earlycon_##_name \ - __used __section(__earlycon_table) \ + static struct earlycon_id __earlycon_##_name __initdata \ = { .name = __stringify(_name), \ - .setup = func } + .setup = func }; \ + static struct earlycon_id *__p_earlycon_##_name __used \ + __aligned(sizeof(struct earlycon_id *)) \ + __section(__earlycon_table) = { &__earlycon_##_name } #define OF_EARLYCON_DECLARE(name, compat, fn) \ _OF_DECLARE(earlycon, name, compat, fn, void *) Index: linux-2.6/drivers/tty/serial/earlycon.c =================================================================== --- linux-2.6.orig/drivers/tty/serial/earlycon.c +++ linux-2.6/drivers/tty/serial/earlycon.c @@ -37,9 +37,8 @@ static struct earlycon_device early_cons .con = &early_con, }; -extern struct earlycon_id __earlycon_table[]; -static const struct earlycon_id __earlycon_table_sentinel - __used __section(__earlycon_table_end); +extern struct earlycon_id *__start_earlycon_table[]; +extern struct earlycon_id *__stop_earlycon_table[]; static const struct of_device_id __earlycon_of_table_sentinel __used __section(__earlycon_of_table_end); @@ -103,7 +102,7 @@ static int __init parse_options(struct e return 0; } -static int __init register_earlycon(char *buf, const struct earlycon_id *match) +static int __init register_earlycon(char *buf, struct earlycon_id *match) { int err; struct uart_port *port = &early_console_dev.port; @@ -147,7 +146,7 @@ static int __init register_earlycon(char */ int __init setup_earlycon(char *buf) { - const struct earlycon_id *match; + struct earlycon_id **pmatch; if (!buf || !buf[0]) return -EINVAL; @@ -155,7 +154,9 @@ int __init setup_earlycon(char *buf) if (early_con.flags & CON_ENABLED) return -EALREADY; - for (match = __earlycon_table; match->name[0]; match++) { + for (pmatch = __start_earlycon_table; pmatch < __stop_earlycon_table; + pmatch++) { + struct earlycon_id *match = *pmatch; size_t len = strlen(match->name); if (strncmp(buf, match->name, len)) Index: linux-2.6/include/asm-generic/vmlinux.lds.h =================================================================== --- linux-2.6.orig/include/asm-generic/vmlinux.lds.h +++ linux-2.6/include/asm-generic/vmlinux.lds.h @@ -151,10 +151,10 @@ #endif #ifdef CONFIG_SERIAL_EARLYCON -#define EARLYCON_TABLE() . = ALIGN(8); \ - VMLINUX_SYMBOL(__earlycon_table) = .; \ - *(__earlycon_table) \ - *(__earlycon_table_end) +#define EARLYCON_TABLE() . = ALIGN(8); \ + VMLINUX_SYMBOL(__start_earlycon_table) = .; \ + *(__earlycon_table) \ + VMLINUX_SYMBOL(__stop_earlycon_table) = .; #else #define EARLYCON_TABLE() #endif