Extensible console matching & direct earlycon
Subsystems (6)
v2 cover Extensible console matching & direct earlycon
Changes from v1:
* rebased on and requires "console: Fix console name size mismatch"
Hi Greg & Andrew,
This patch series implements:
1. console-definable (aka extensible) matching
2. generic earlycon-to-console handoff via extensible matching
3. arch/prom support for direct earlycon
Extensible console matching
Extensible console matching enables the console itself to define the conditions for a "command line" match. This mimics the design of device matching in the driver model. Two important use-cases which this feature enables are generic earlycon-to-console handoff and support for driver migration.
Earlycon-to-console handoff was implemented in 2007. Console command lines of the form:
console=uart,io,0x3f8,115200n8
start an earlycon and later allow the 8250 driver console to takeover. Unfortunately this implementation requires direct coupling between the earlycon and the console and is facilitated by ugly hacks like editing the console command line in-place.
Extensible console matching allows the 8250 driver to directly match that console command line instead, and enables other serial drivers to trivially support console handoff themselves.
In addition, extensible console matching allows a new driver to provide support for a different driver's console. This requirement stems from needing to minimize breakage when migrating serial drivers. Since many devices are based on the original 8250/16550 designs but sometimes have features incompatible with the existing 8250 driver support, the initial driver is often standalone. When/if the standalone driver is migrated to the 8250 driver, the problem of console names in the command line remains. Extensible console matching enables a simple migration path.
Direct earlycon
This feature enables arches and proms to start an earlycon directly, rather than requiring an "earlycon=" command line parameter. Devicetree can already do this via the 'linux,stdout-path' property, but arch and prom code requires direct coupling to the serial driver.
This support is implemented by judicious refactoring and the same construct that devicetree and early_param use: a link table containing the necessary information (name and setup() function) to find and bind the appropriate earlycon "driver".
NB: I combined these two features in this series because their implementations heavily overlap in the same source files.
Regards,
Peter Hurley (13):
serial: earlycon: Refactor parse_options into serial core
console: Preserve index after console setup()
console: Add extensible console matching
serial: core: Fix kernel doc for uart_console_write()
serial: 8250_early: Remove early_device variable
serial: earlycon: Move ->uartclk initialize
serial: 8250_early: Assume uart already initialized if no baud option
serial: 8250_early: Fix setup() error code
serial: earlycon: Ignore parse_options() error code
serial: earlycon: Allow earlycon params with name only
serial: earlycon: Refactor earlycon registration
serial: earlycon: Enable earlycon without command line param
serial: 8250_early: Remove setup_early_serial8250_console()
arch/mips/mti-malta/malta-init.c | 4 +- drivers/firmware/pcdp.c | 4 +- drivers/tty/serial/8250/8250_core.c | 64 ++++++++++++---- drivers/tty/serial/8250/8250_early.c | 51 +++---------- drivers/tty/serial/earlycon.c | 140 ++++++++++++++++++++++++----------- drivers/tty/serial/serial_core.c | 48 +++++++++++- include/asm-generic/vmlinux.lds.h | 9 +++ include/linux/console.h | 3 +- include/linux/serial_8250.h | 3 - include/linux/serial_core.h | 21 ++++-- kernel/printk/printk.c | 53 +++++-------- 11 files changed, 246 insertions(+), 154 deletions(-)
Signature · 1 line
2.3.0
PATCH v2 1/13 serial: earlycon: Refactor parse_options into serial core
Prepare to support console-defined matching; refactor the command line parameter string processing from parse_options() into a new core function, uart_parse_earlycon(), which decodes command line parameters of the form:
earlycon=<name>,io|mmio|mmio32,<addr>,<options> console=<name>,io|mmio|mmio32,<addr>,<options> earlycon=<name>,0x<addr>,<options> console=<name>,0x<addr>,<options>
--- drivers/tty/serial/earlycon.c | 39 ++++++++++++---------------------- drivers/tty/serial/serial_core.c | 46 ++++++++++++++++++++++++++++++++++++++++ include/linux/serial_core.h | 2 ++ 3 files changed, 61 insertions(+), 26 deletions(-)
drivers/tty/serial/earlycon.c +13 -26
@@ -54,44 +54,31 @@ static void __iomem * __init earlycon_map(unsigned long paddr, size_t size)return base; } -static int __init parse_options (struct earlycon_device *device, -char *options) +static int __init parse_options (struct earlycon_device *device,char *options) {struct uart_port *port = &device->port; -int mmio, mmio32, length; +int length;unsigned long addr; -if (!options) -return -ENODEV ; +if (uart_parse_earlycon (options, &port->iotype, &addr, &options)) +return -EINVAL ; - mmio = !strncmp (options,"mmio," ,5 ); - mmio32 = !strncmp (options,"mmio32," ,7 ); -if (mmio || mmio32) { - port->iotype = (mmio ?UPIO_MEM :UPIO_MEM32 ); - options += mmio ?5 :7 ; - addr =simple_strtoul (options,NULL ,0 ); +switch (port->iotype) { +case UPIO_MEM32 : + port->regshift =2 ;/* fall-through */ +case UPIO_MEM : port->mapbase = addr; -if (mmio32) - port->regshift =2 ; - }else if (!strncmp (options,"io," ,3 )) { - port->iotype =UPIO_PORT ; - options +=3 ; - addr =simple_strtoul (options,NULL ,0 ); +break ; +case UPIO_PORT : port->iobase = addr; - mmio =0 ; - }else if (!strncmp (options,"0x" ,2 )) { - port->iotype =UPIO_MEM ; - addr =simple_strtoul (options,NULL ,0 ); - port->mapbase = addr; - }else { +break ; +default :return -EINVAL ; } port->uartclk =BASE_BAUD *16 ; - options =strchr (options,',' );if (options) { - options++; device->baud =simple_strtoul (options,NULL ,0 ); length =min (strcspn (options," " ) +1 , (size_t )(sizeof (device->options)));
@@ -100,7 +87,7 @@ static int __init parse_options(struct earlycon_device *device,if (port->iotype ==UPIO_MEM || port->iotype ==UPIO_MEM32 )pr_info ("Early serial console at MMIO%s 0x%llx (options '%s')\n" , - mmio32 ?"32" :"" , + (port->iotype ==UPIO_MEM32 ) ?"32" :"" , (unsigned long long )port->mapbase, device->options);else
drivers/tty/serial/serial_core.c +46 -0
52 lines not on this page · raw message
include/linux/serial_core.h +2 -0
@@ -354,6 +354,8 @@ early_param("earlycon", name ## _setup_earlycon);struct uart_port *uart_get_console (struct uart_port *ports,int nr,struct console *c); +int uart_parse_earlycon (char *p,unsigned char *iotype,unsigned long *addr, +char **options);void uart_parse_options (char *options,int *baud,int *parity,int *bits,int *flow); int uart_set_options(struct uart_port *port, struct console *co, int baud,
Signature · 1 line
2.3.0
PATCH v2 2/13 console: Preserve index after console setup()
In reply to Peter HurleyBefore register_console() calls the setup() method of the matched console, the registering console index is already equal to the index from the console command line; ie. newcon->index == c->index.
This change is also required to support extensible console matching; (the command line index may have no relation to the console index assigned by the console-defined match() function).
--- kernel/printk/printk.c | 1 - 1 file changed, 1 deletion(-)
kernel/printk/printk.c +0 -1
@@ -2480,7 +2480,6 @@ void register_console(struct console *newcon) newcon->setup(newcon, console_cmdline[i].options) != 0)break ; newcon->flags |=CON_ENABLED ; - newcon->index = c->index;if (i == selected_console) { newcon->flags |=CON_CONSDEV ; preferred_console = selected_console;
Signature · 1 line
2.3.0
PATCH v2 3/13 console: Add extensible console matching
In reply to Peter HurleyAdd match() method to struct console which allows the console to perform console command line matching instead of (or in addition to) default console matching (ie., by fixed name and index).
The match() method returns 0 to indicate a successful match; normal console matching occurs if no match() method is defined or the match() method returns non-zero. The match() method is expected to set the console index if required.
Re-implement earlycon-to-console-handoff with direct matching of "console=uart|uart8250,..." to the 8250 ttyS console.
--- drivers/tty/serial/8250/8250_core.c | 64 +++++++++++++++++++++++++++--------- drivers/tty/serial/8250/8250_early.c | 23 ------------- include/linux/console.h | 3 +- include/linux/serial_8250.h | 2 -- kernel/printk/printk.c | 52 ++++++++++------------------- 5 files changed, 67 insertions(+), 77 deletions(-)
drivers/tty/serial/8250/8250_core.c +48 -16
@@ -3337,9 +3337,54 @@ static int serial8250_console_setup(struct console *co, char *options)return uart_set_options (port, co, baud, parity, bits, flow); } -static int serial8250_console_early_setup (void ) +/** +* serial8250_console_match - non-standard console matching +* @co: registering console +* @name: name from console command line +* @idx: index from console command line +* @options: ptr to option string from console command line +* +* Only attempts to match console command lines of the form: +* console=uart<>,io|mmio|mmio32,<addr>,<options> +* console=uart<>,<addr>,options +* This form is used to register an initial earlycon boot console and +* replace it with the serial8250_console at 8250 driver init. +* +* Performs console setup for a match (as required by interface) +* +* Returns 0 if console matches; otherwise non-zero to use default matching +*/ +static int serial8250_console_match (struct console *co,char *name,int idx, +char *options) { -return serial8250_find_port_for_earlycon (); +char match[] ="uart" ;/* 8250-specific earlycon name */ +unsigned char iotype; +unsigned long addr; +int i; + +if (strncmp (name, match,4 ) !=0 ) +return -ENODEV ; + +if (uart_parse_earlycon (options, &iotype, &addr, &options)) +return -ENODEV ; + +/* try to match the port specified on the command line */ +for (i =0 ; i < nr_uarts; i++) { +struct uart_port *port = &serial8250_ports[i].port; + +if (port->iotype != iotype) +continue ; +if ((iotype ==UPIO_MEM || iotype ==UPIO_MEM32 ) && + (port->mapbase != addr)) +continue ; +if (iotype ==UPIO_PORT && port->iobase != addr) +continue ; + + co->index = i; +return serial8250_console_setup (co, options); + } + +return -ENODEV ; }static struct console serial8250_console = {
@@ -3347,7 +3392,7 @@ static struct console serial8250_console = { .write = serial8250_console_write, .device = uart_console_device, .setup = serial8250_console_setup, - .early_setup = serial8250_console_early_setup, + .match = serial8250_console_match, .flags = CON_PRINTBUFFER | CON_ANYTIME, .index = -1, .data = &serial8250_reg,
@@ -3361,19 +3406,6 @@ static int __init serial8250_console_init(void) }console_initcall (serial8250_console_init); -int serial8250_find_port (struct uart_port *p) -{ -int line; -struct uart_port *port; - -for (line =0 ; line < nr_uarts; line++) { - port = &serial8250_ports[line].port; -if (uart_match_port (p, port)) -return line; - } -return -ENODEV ; -} -#define SERIAL8250_CONSOLE &serial8250_console#else #define SERIAL8250_CONSOLE NULL
drivers/tty/serial/8250/8250_early.c +0 -23
@@ -173,26 +173,3 @@ int __init setup_early_serial8250_console(char *cmdline)return setup_earlycon (cmdline, match, early_serial8250_setup); } - -int serial8250_find_port_for_earlycon (void ) -{ -struct earlycon_device *device = early_device; -struct uart_port *port = device ? &device->port :NULL ; -int line; -int ret; - -if (!port || (!port->membase && !port->iobase)) -return -ENODEV ; - - line =serial8250_find_port (port); -if (line <0 ) -return -ENODEV ; - - ret =update_console_cmdline ("uart" ,8250 , -"ttyS" , line, device->options); -if (ret <0 ) - ret =update_console_cmdline ("uart" ,0 , -"ttyS" , line, device->options); - -return ret; -}
include/linux/console.h +1 -2
@@ -123,7 +123,7 @@ struct console {struct tty_driver *(*device)(struct console *,int *);void (*unblank)(void );int (*setup)(struct console *,char *); -int (*early_setup)(void ); +int (*match)(struct console *,char *name,int idx,char *options);short flags;short index;int cflag;
@@ -141,7 +141,6 @@ extern int console_set_on_cmdline;extern struct console *early_console;extern int add_preferred_console (char *name,int idx,char *options); -extern int update_console_cmdline (char *name,int idx,char *name_new,int idx_new,char *options);extern void register_console (struct console *);extern int unregister_console (struct console *);extern struct console *console_drivers;
include/linux/serial_8250.h +0 -2
@@ -118,8 +118,6 @@ void serial8250_resume_port(int line);extern int early_serial_setup (struct uart_port *port); -extern int serial8250_find_port (struct uart_port *p); -extern int serial8250_find_port_for_earlycon (void );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 int setup_early_serial8250_console (char *cmdline);
kernel/printk/printk.c +18 -34
72 lines not on this page · raw message
Signature · 1 line
2.3.0
Greg Kroah-Hartman
maintainerRe: [PATCH v2 -next 03/13] console: Add extensible console matching
Quoted 12 lines · Peter Hurley
Add
match()method to struct console which allows the console to perform console command line matching instead of (or in addition to) default console matching (ie., by fixed name and index).The
match()method returns 0 to indicate a successful match; normal console matching occurs if nomatch()method is defined or thematch()method returns non-zero. Thematch()method is expected to set the console index if required.Re-implement earlycon-to-console-handoff with direct matching of "console=uart|uart8250,..." to the 8250 ttyS console.
Quoted 8 lines
Signed-off-by Peter Hurley <[email protected]>--- drivers/tty/serial/8250/8250_core.c | 64 +++++++++++++++++++++++++++--------- drivers/tty/serial/8250/8250_early.c | 23 ------------- include/linux/console.h | 3 +- include/linux/serial_8250.h | 2 -- kernel/printk/printk.c | 52 ++++++++++------------------- 5 files changed, 67 insertions(+), 77 deletions(-)
This didn't apply, so I've stopped here.
thanks,
greg k-h
Re: [PATCH v2 -next 03/13] console: Add extensible console matching
Quoted 22 lines · Greg Kroah-Hartman
Quoted 12 lines · Peter Hurley
Add
match()method to struct console which allows the console to perform console command line matching instead of (or in addition to) default console matching (ie., by fixed name and index).The
match()method returns 0 to indicate a successful match; normal console matching occurs if nomatch()method is defined or thematch()method returns non-zero. Thematch()method is expected to set the console index if required.Re-implement earlycon-to-console-handoff with direct matching of "console=uart|uart8250,..." to the 8250 ttyS console.
Quoted 8 lines
Signed-off-by Peter Hurley <[email protected]>--- drivers/tty/serial/8250/8250_core.c | 64 +++++++++++++++++++++++++++--------- drivers/tty/serial/8250/8250_early.c | 23 ------------- include/linux/console.h | 3 +- include/linux/serial_8250.h | 2 -- kernel/printk/printk.c | 52 ++++++++++------------------- 5 files changed, 67 insertions(+), 77 deletions(-)
Quoted 1 line
This didn't apply, so I've stopped here.
Hi Greg,
Your tty-testing branch doesn't have "console: Fix console name size mismatch" that you added to tty-linus. I tried to draw attention to that in the series cover letter:
Quoted 2 lines · Peter Hurley
Changes from v1:
* rebased on and requires "console: Fix console name size mismatch"
Regards,
Peter Hurley
PATCH v2 4/13 serial: core: Fix kernel doc for uart_console_write()
In reply to Peter Hurley'/**' is required to start a kernel-doc comment block.
--- drivers/tty/serial/serial_core.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/tty/serial/serial_core.c +1 -1
@@ -1766,7 +1766,7 @@ static const struct file_operations uart_proc_fops = {#endif #if defined(CONFIG_SERIAL_CORE_CONSOLE ) || defined(CONFIG_CONSOLE_POLL ) -/* +/** * uart_console_write - write a console message to a serial port * @port: the port to write the message * @s: array of characters
Signature · 1 line
2.3.0
PATCH v2 5/13 serial: 8250_early: Remove early_device variable
In reply to Peter Hurleyearly_device was only required for serial8250_find_port_for_earlycon(), which was replaced by extensible console matching.
Fixup early_serial8250_write() to get the earlycon_device * from console->data (which is initialized by {of_}setup_earlycon()).
--- drivers/tty/serial/8250/8250_early.c | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-)
drivers/tty/serial/8250/8250_early.c +2 -4
@@ -36,8 +36,6 @@#include <asm/io.h> #include <asm/serial.h> -static struct earlycon_device *early_device; -unsigned int __weak __init serial8250_early_in (struct uart_port *port,int offset) {switch (port->iotype) {
@@ -90,7 +88,8 @@ static void __init serial_putc(struct uart_port *port, int c)static void __init early_serial8250_write (struct console *console,const char *s,unsigned int count) { -struct uart_port *port = &early_device->port; +struct earlycon_device *device = console->data; +struct uart_port *port = &device->port;unsigned int ier;/* Save the IER and disable interrupts preserving the UUE bit */
@@ -157,7 +156,6 @@ static int __init early_serial8250_setup(struct earlycon_device *device,init_port (device); - early_device = device; device->con->write = early_serial8250_write;return 0 ; }
Signature · 1 line
2.3.0
PATCH v2 6/13 serial: earlycon: Move ->uartclk initialize
In reply to Peter HurleyInitializing the ->uartclk field is not related to option parsing; relocate from parse_options() to setup_earlycon() (which mirrors the behavior of of_setup_earlycon()).
--- drivers/tty/serial/earlycon.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/tty/serial/earlycon.c +1 -2
@@ -76,8 +76,6 @@ static int __init parse_options(struct earlycon_device *device, char *options)return -EINVAL ; } - port->uartclk =BASE_BAUD *16 ; -if (options) { device->baud =simple_strtoul (options,NULL ,0 ); length = min(strcspn(options, " ") + 1,
@@ -121,6 +119,7 @@ int __init setup_earlycon(char *buf, const char *match,if (!err) buf =NULL ; + port->uartclk =BASE_BAUD *16 ;if (port->mapbase) port->membase =earlycon_map (port->mapbase,64 );
Signature · 1 line
2.3.0
PATCH v2 7/13 serial: 8250_early: Assume uart already initialized if no baud option
In reply to Peter HurleyThe <baud><parity><bit> option string is not supplied if the earlycon is started via devicetree and OF_EARLYCON_DECLARE(). The option string is also not required if started via kernel command line parameters of the form:
earlycon=uart,mmio,<addr>
console=uart,mmio,<addr>
If earlycon_device->baud is 0, then an option string was not supplied. In this case, assume the uart has already been initialized by the bootloader or firmware.
--- drivers/tty/serial/8250/8250_early.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-)
drivers/tty/serial/8250/8250_early.c +8 -2
@@ -149,12 +149,18 @@ static int __init early_serial8250_setup(struct earlycon_device *device,return 0 ;if (!device->baud) { +struct uart_port *port = &device->port; +unsigned int ier; + device->baud =probe_baud (&device->port);snprintf (device->options,sizeof (device->options),"%u" , device->baud); - } -init_port (device); +/* assume the device was initialized, only mask interrupts */ + ier =serial8250_early_in (port,UART_IER ); +serial8250_early_out (port,UART_IER , ier &UART_IER_UUE ); + }else +init_port (device); device->con->write = early_serial8250_write;return 0 ;
Signature · 1 line
2.3.0
PATCH v2 8/13 serial: 8250_early: Fix setup() error code
In reply to Peter HurleyIf parsing failed to decode a valid uart addr, return -ENODEV instead of success. Although setup_earlycon() will detect the failure anyway (because the write() method has not been set), that behavior is not obvious and should not be relied on.
--- drivers/tty/serial/8250/8250_early.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
drivers/tty/serial/8250/8250_early.c +1 -1
@@ -146,7 +146,7 @@ static int __init early_serial8250_setup(struct earlycon_device *device, const char *options) {if (!(device->port.membase || device->port.iobase)) -return 0 ; +return -ENODEV ;if (!device->baud) {struct uart_port *port = &device->port;
Signature · 1 line
2.3.0
PATCH v2 9/13 serial: earlycon: Ignore parse_options() error code
In reply to Peter HurleyBecause setup_earlycon() continues to attempt console registration if an error occurred parsing the option string, the actual value of the error code from parse_options() is ignored.
--- drivers/tty/serial/earlycon.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-)
drivers/tty/serial/earlycon.c +1 -2
@@ -114,9 +114,8 @@ int __init setup_earlycon(char *buf, const char *match, buf += len +1 ; - err =parse_options (&early_console_dev, buf);/* On parsing error, pass the options buf to the setup function */ -if (!err) +if (!parse_options (&early_console_dev, buf)) buf =NULL ; port->uartclk =BASE_BAUD *16 ;
Signature · 1 line
2.3.0
PATCH v2 10/13 serial: earlycon: Allow earlycon params with name only
In reply to Peter HurleyAllow earlycon param strings of the form
earlycon=<name>
--- drivers/tty/serial/earlycon.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)
drivers/tty/serial/earlycon.c +7 -4
@@ -109,13 +109,16 @@ int __init setup_earlycon(char *buf, const char *match, len =strlen (match);if (strncmp (buf, match, len))return 0 ; -if (buf[len] && (buf[len] !=',' )) -return 0 ; - buf += len +1 ; +if (buf[len]) { +if (buf[len] !=',' ) +return 0 ; + buf += len +1 ; + }else + buf =NULL ;/* On parsing error, pass the options buf to the setup function */ -if (!parse_options (&early_console_dev, buf)) +if (buf && !parse_options (&early_console_dev, buf)) buf =NULL ; port->uartclk =BASE_BAUD *16 ;
Signature · 1 line
2.3.0
Re: [PATCH v2 -next 10/13] serial: earlycon: Allow earlycon params with name only
Quoted 2 lines · Peter Hurley
Allow earlycon param strings of the form
earlycon=<name>
Humm, that should already be the case with ARM semihosting (smh).
Rob
Quoted 34 lines
Signed-off-by Peter Hurley <[email protected]>--- drivers/tty/serial/earlycon.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)drivers/tty/serial/earlycon.c +7
-5@@ -109,13 +109,16 @@ int __init setup_earlycon(char *buf, const char *match, len =strlen (match);if (strncmp (buf, match, len))return 0 ; -if (buf[len] && (buf[len] !=',' )) -return 0 ; - buf += len +1 ; +if (buf[len]) { +if (buf[len] !=',' ) +return 0 ; + buf += len +1 ; + }else + buf =NULL ;/* On parsing error, pass the options buf to the setup function */ -if (!parse_options (&early_console_dev, buf)) +if (buf && !parse_options (&early_console_dev, buf)) buf =NULL ; port->uartclk =BASE_BAUD *16 ; --2.3.0
Re: [PATCH v2 -next 10/13] serial: earlycon: Allow earlycon params with name only
Quoted 7 lines · Rob Herring
Quoted 2 lines · Peter Hurley
Allow earlycon param strings of the form
earlycon=<name>Humm, that should already be the case with ARM semihosting (smh).
Rob
Then it's passing a bogus options string to parse_options()
Quoted 34 lines
Quoted 34 lines
Signed-off-by Peter Hurley <[email protected]>--- drivers/tty/serial/earlycon.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)drivers/tty/serial/earlycon.c +7
-5@@ -109,13 +109,16 @@ int __init setup_earlycon(char *buf, const char *match, len =strlen (match);if (strncmp (buf, match, len))return 0 ; -if (buf[len] && (buf[len] !=',' )) -return 0 ; - buf += len +1 ; +if (buf[len]) { +if (buf[len] !=',' ) +return 0 ; + buf += len +1 ; + }else + buf =NULL ;/* On parsing error, pass the options buf to the setup function */ -if (!parse_options (&early_console_dev, buf)) +if (buf && !parse_options (&early_console_dev, buf)) buf =NULL ; port->uartclk =BASE_BAUD *16 ; --2.3.0
Re: [PATCH v2 -next 10/13] serial: earlycon: Allow earlycon params with name only
Quoted 10 lines · Peter Hurley
Quoted 7 lines · Rob Herring
Quoted 2 lines · Peter Hurley
Allow earlycon param strings of the form
earlycon=<name>Humm, that should already be the case with ARM semihosting (smh).
Rob
Then it's passing a bogus options string to
parse_options()
No, that's not right.
It's passing an empty string (the '\0' at the end) to parse_options() which is failing with -EINVAL, which upon returning sets buf to NULL.
My way has less obfuscation but the commit log needs to change.
Regards,
Peter Hurley
Quoted 35 lines
Quoted 34 lines
Quoted 34 lines
Signed-off-by Peter Hurley <[email protected]>--- drivers/tty/serial/earlycon.c | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-)drivers/tty/serial/earlycon.c +7
-5@@ -109,13 +109,16 @@ int __init setup_earlycon(char *buf, const char *match, len =strlen (match);if (strncmp (buf, match, len))return 0 ; -if (buf[len] && (buf[len] !=',' )) -return 0 ; - buf += len +1 ; +if (buf[len]) { +if (buf[len] !=',' ) +return 0 ; + buf += len +1 ; + }else + buf =NULL ;/* On parsing error, pass the options buf to the setup function */ -if (!parse_options (&early_console_dev, buf)) +if (buf && !parse_options (&early_console_dev, buf)) buf =NULL ; port->uartclk =BASE_BAUD *16 ; --2.3.0
PATCH v2 11/13 serial: earlycon: Refactor earlycon registration
In reply to Peter HurleySeparate earlycon matching from registration; add register_earlycon which initializes and registers the matched earlycon.
--- drivers/tty/serial/earlycon.c | 42 +++++++++++++++++++++++++----------------- 1 file changed, 25 insertions(+), 17 deletions(-)
drivers/tty/serial/earlycon.c +25 -17
@@ -96,27 +96,13 @@ static int __init parse_options(struct earlycon_device *device, char *options)return 0 ; } -int __init setup_earlycon (char *buf,const char *match, -int (*setup)(struct earlycon_device *,const char *)) + +static int __init +register_earlycon (char *buf,int (*setup)(struct earlycon_device *,const char *)) {int err; -size_t len;struct uart_port *port = &early_console_dev.port; -if (!buf || !match || !setup) -return 0 ; - - len =strlen (match); -if (strncmp (buf, match, len)) -return 0 ; - -if (buf[len]) { -if (buf[len] !=',' ) -return 0 ; - buf += len +1 ; - }else - buf =NULL ; -/* On parsing error, pass the options buf to the setup function */ if (buf && !parse_options (&early_console_dev, buf)) buf =NULL ;
@@ -136,6 +122,28 @@ int __init setup_earlycon(char *buf, const char *match,return 0 ; } +int __init setup_earlycon (char *buf,const char *match, +int (*setup)(struct earlycon_device *,const char *)) +{ +size_t len; + +if (!buf || !match || !setup) +return 0 ; + + len =strlen (match); +if (strncmp (buf, match, len)) +return 0 ; + +if (buf[len]) { +if (buf[len] !=',' ) +return 0 ; + buf += len +1 ; + }else + buf =NULL ; + +return register_earlycon (buf, setup); +} +int __init of_setup_earlycon (unsigned long addr,int (*setup)(struct earlycon_device *,const char *)) {
Signature · 1 line
2.3.0
PATCH v2 12/13 serial: earlycon: Enable earlycon without command line param
In reply to Peter HurleyEarlycon matching can only be triggered if 'earlycon=...' has been specified on the kernel command line. To workaround this limitation requires tight coupling between arches and specific serial drivers in order to start an earlycon. Devicetree avoids this limitation with a link table that contains the required data to match earlycons.
Mirror this approach for earlycon match by name. Re-purpose EARLYCON_DECLARE to generate a table entry which associates name with setup() function. Re-purpose setup_earlycon() to scan this table for an earlycon match, which is registered if found.
Declare one "earlycon" early_param, which calls setup_earlycon().
This design allows setup_earlycon() to be called directly with a param string (as if 'earlycon=...' had been set on the command line). Re-registration (either directly or by early_param) is prevented.
--- drivers/tty/serial/8250/8250_early.c | 7 +-- drivers/tty/serial/earlycon.c | 92 ++++++++++++++++++++++++++++-------- include/asm-generic/vmlinux.lds.h | 9 ++++ include/linux/serial_core.h | 19 ++++---- 4 files changed, 94 insertions(+), 33 deletions(-)
drivers/tty/serial/8250/8250_early.c +1 -6
@@ -170,10 +170,5 @@ EARLYCON_DECLARE(uart, early_serial8250_setup);int __init setup_early_serial8250_console (char *cmdline) { -char match[] ="uart8250" ; - -if (cmdline && cmdline[4 ] ==',' ) - match[4 ] ='\0' ; - -return setup_earlycon (cmdline, match, early_serial8250_setup); +return setup_earlycon (cmdline); }
drivers/tty/serial/earlycon.c +73 -19
128 lines not on this page · raw message
include/asm-generic/vmlinux.lds.h +9 -0
@@ -150,6 +150,14 @@#define TRACE_SYSCALLS ()#endif +#ifdef CONFIG_SERIAL_EARLYCON +#define EARLYCON_TABLE () . = ALIGN(8); \ + VMLINUX_SYMBOL(__earlycon_table) = .; \ + *(__earlycon_table) \ + *(__earlycon_table_end) +#else +#define EARLYCON_TABLE () +#endif #define ___OF_TABLE (cfg, name) _OF_TABLE_##cfg(name)#define __OF_TABLE (cfg, name) ___OF_TABLE(cfg, name)
@@ -502,6 +510,7 @@ CPU_METHOD_OF_TABLES() \ KERNEL_DTB() \ IRQCHIP_OF_MATCH_TABLE() \ + EARLYCON_TABLE() \ EARLYCON_OF_TABLES()#define INIT_TEXT \
include/linux/serial_core.h +11 -8
@@ -336,18 +336,21 @@ struct earlycon_device {char options[16 ];/* e.g., 115200n8 */ unsigned int baud; }; -int setup_earlycon (char *buf,const char *match, -int (*setup)(struct earlycon_device *,const char *)); +struct earlycon_id { +char name[16 ]; +int (*setup)(struct earlycon_device *,const char *options); +}; + +extern int setup_earlycon (char *buf);extern int of_setup_earlycon (unsigned long addr,int (*setup)(struct earlycon_device *,const char *)); -#define EARLYCON_DECLARE (name, func) \ -static int __init name ## _setup_earlycon(char *buf) \ -{ \ - return setup_earlycon(buf, __stringify(name), func); \ -} \ -early_param("earlycon", name ## _setup_earlycon); +#define EARLYCON_DECLARE (_name, func) \ + static const struct earlycon_id __earlycon_##_name \ + __used __section(__earlycon_table) \ + = { .name = __stringify(_name), \ + .setup = func }#define OF_EARLYCON_DECLARE (name, compat, fn) \ _OF_DECLARE(earlycon, name, compat, fn, void *)
Signature · 1 line
2.3.0
PATCH v2 13/13 serial: 8250_early: Remove setup_early_serial8250_console()
In reply to Peter Hurleysetup_earlycon() will now match and register the desired earlycon from the param string (as if 'earlycon=...' had been set on the command line). Use setup_earlycon() from existing arch call sites which start an earlycon directly.
--- arch/mips/mti-malta/malta-init.c | 4 ++-- drivers/firmware/pcdp.c | 4 ++-- drivers/tty/serial/8250/8250_early.c | 5 ----- include/linux/serial_8250.h | 1 - 4 files changed, 4 insertions(+), 10 deletions(-)
arch/mips/mti-malta/malta-init.c +2 -2
@@ -14,7 +14,7 @@#include <linux/init.h> #include <linux/string.h> #include <linux/kernel.h> -#include <linux/serial_8250.h> +#include <linux/serial_core.h> #include <asm/cacheflush.h> #include <asm/smp-ops.h>
@@ -75,7 +75,7 @@ static void __init console_config(void)if ((strstr (fw_getcmdline (),"earlycon=" )) ==NULL ) {sprintf (console_string,"uart8250,io,0x3f8,%d%c%c" , baud, parity, bits); -setup_early_serial8250_console (console_string); +setup_earlycon (console_string); }if ((strstr (fw_getcmdline (),"console=" )) ==NULL ) {
drivers/firmware/pcdp.c +2 -2
@@ -15,7 +15,7 @@#include <linux/console.h> #include <linux/efi.h> #include <linux/serial.h> -#include <linux/serial_8250.h> +#include <linux/serial_core.h> #include <asm/vga.h> #include "pcdp.h"
@@ -43,7 +43,7 @@ setup_serial_console(struct pcdp_uart *uart) }add_preferred_console ("uart" ,8250 , &options[9 ]); -return setup_early_serial8250_console (options); +return setup_earlycon (options);#else return -ENODEV ;#endif
drivers/tty/serial/8250/8250_early.c +0 -5
@@ -167,8 +167,3 @@ static int __init early_serial8250_setup(struct earlycon_device *device, }EARLYCON_DECLARE (uart8250, early_serial8250_setup);EARLYCON_DECLARE (uart, early_serial8250_setup); - -int __init setup_early_serial8250_console (char *cmdline) -{ -return setup_earlycon (cmdline); -}
include/linux/serial_8250.h +0 -1
@@ -120,7 +120,6 @@ extern int early_serial_setup(struct uart_port *port);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 int setup_early_serial8250_console (char *cmdline);extern void serial8250_do_set_termios (struct uart_port *port,struct ktermios *termios,struct ktermios *old);extern int serial8250_do_startup (struct uart_port *port);
Signature · 1 line
2.3.0
Quoted 2 lines · Peter Hurley
Changes from v1:
* rebased on and requires "console: Fix console name size mismatch"
I plan to pick this one up for 4.0 because I need it for "of: Fix premature bootconsole disable with 'stdout-path'".
Quoted 72 lines
Hi Greg & Andrew,
This patch series implements:
1. console-definable (aka extensible) matching
2. generic earlycon-to-console handoff via extensible matching
3.arch/promsupport for direct earlyconExtensible console matching
Extensible console matching enables the console itself to define the conditions for a "command line" match. This mimics the design of device matching in the driver model. Two important use-cases which this feature enables are generic earlycon-to-console handoff and support for driver migration.
Earlycon-to-console handoff was implemented in 2007. Console command lines of the form:
console=uart,io,0x3f8,115200n8start an earlycon and later allow the 8250 driver console to takeover. Unfortunately this implementation requires direct coupling between the earlycon and the console and is facilitated by ugly hacks like editing the console command line in-place.
Extensible console matching allows the 8250 driver to directly match that console command line instead, and enables other serial drivers to trivially support console handoff themselves.
In addition, extensible console matching allows a new driver to provide support for a different driver's console. This requirement stems from needing to minimize breakage when migrating serial drivers. Since many devices are based on the original 8250/16550 designs but sometimes have features incompatible with the existing 8250 driver support, the initial driver is often standalone. When/if the standalone driver is migrated to the 8250 driver, the problem of console names in the command line remains. Extensible console matching enables a simple migration path.
Direct earlycon
This feature enables arches and proms to start an earlycon directly, rather than requiring an "earlycon=" command line parameter. Devicetree can already do this via the 'linux,stdout-path' property, but arch and prom code requires direct coupling to the serial driver.
This support is implemented by judicious refactoring and the same construct that devicetree and
early_paramuse: a link table containing the necessary information (name andsetup()function) to find and bind the appropriate earlycon "driver".NB: I combined these two features in this series because their implementations heavily overlap in the same source files.
Regards,
Peter Hurley (13):
serial: earlycon: Refactorparse_optionsinto serial core
console: Preserve index after consolesetup()
console: Add extensible console matching
serial: core: Fix kernel doc foruart_console_write()
serial: 8250_early: Removeearly_devicevariable
serial: earlycon: Move ->uartclk initialize
serial: 8250_early: Assume uart already initialized if no baud option
serial: 8250_early: Fixsetup()error code
serial: earlycon: Ignoreparse_options()error code
serial: earlycon: Allow earlycon params with name only
serial: earlycon: Refactor earlycon registration
serial: earlycon: Enable earlycon without command line param
serial: 8250_early: Removesetup_early_serial8250_console()
Quoted 12 lines
arch/mips/mti-malta/malta-init.c | 4 +- drivers/firmware/pcdp.c | 4 +- drivers/tty/serial/8250/8250_core.c | 64 ++++++++++++---- drivers/tty/serial/8250/8250_early.c | 51 +++---------- drivers/tty/serial/earlycon.c | 140 ++++++++++++++++++++++++----------- drivers/tty/serial/serial_core.c | 48 +++++++++++- include/asm-generic/vmlinux.lds.h | 9 +++ include/linux/console.h | 3 +- include/linux/serial_8250.h | 3 - include/linux/serial_core.h | 21 ++++-- kernel/printk/printk.c | 53 +++++-------- 11 files changed, 246 insertions(+), 154 deletions(-)
For the series:
Quoted 4 lines
--
2.3.0