diff --git a/drivers/tty/serial/serial_base.h b/drivers/tty/serial/serial_base.h index c74c548f0db62..327a18b1813b6 100644 --- a/drivers/tty/serial/serial_base.h +++ b/drivers/tty/serial/serial_base.h @@ -45,3 +45,19 @@ void serial_ctrl_unregister_port(struct uart_driver *drv, struct uart_port *port int serial_core_register_port(struct uart_driver *drv, struct uart_port *port); void serial_core_unregister_port(struct uart_driver *drv, struct uart_port *port); + +#ifdef CONFIG_SERIAL_CORE_CONSOLE + +int serial_base_add_preferred_console(struct uart_driver *drv, + struct uart_port *port); + +#else + +static inline +int serial_base_add_preferred_console(struct uart_driver *drv, + struct uart_port *port) +{ + return 0; +} + +#endif diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c index 4df2a4b10445a..4ef26a1b09b11 100644 --- a/drivers/tty/serial/serial_base_bus.c +++ b/drivers/tty/serial/serial_base_bus.c @@ -8,6 +8,7 @@ * The serial core bus manages the serial core controller instances. */ +#include #include #include #include @@ -204,6 +205,71 @@ void serial_base_port_device_remove(struct serial_port_device *port_dev) put_device(&port_dev->dev); } +#ifdef CONFIG_SERIAL_CORE_CONSOLE + +static int serial_base_add_one_prefcon(const char *match, const char *dev_name, + int port_id) +{ + int ret; + + ret = add_preferred_console_match(match, dev_name, port_id); + if (ret == -ENOENT) + return 0; + + return ret; +} + +static int serial_base_add_prefcon(const char *name, int idx) +{ + const char *char_match __free(kfree) = NULL; + + /* Handle the traditional character device name style console=ttyS0 */ + char_match = kasprintf(GFP_KERNEL, "%s%i", name, idx); + if (!char_match) + return -ENOMEM; + + return serial_base_add_one_prefcon(char_match, name, idx); +} + +/** + * serial_base_add_preferred_console - Adds a preferred console + * @drv: Serial port device driver + * @port: Serial port instance + * + * Tries to add a preferred console for a serial port if specified in the + * kernel command line. Supports both the traditional character device such + * as console=ttyS0, and a hardware addressing based console=DEVNAME:0.0 + * style name. + * + * Translates the kernel command line option using a hardware based addressing + * console=DEVNAME:0.0 to the serial port character device such as ttyS0. + * Cannot be called early for ISA ports, depends on struct device. + * + * Note that duplicates are ignored by add_preferred_console(). + * + * Return: 0 on success, negative error code on failure. + */ +int serial_base_add_preferred_console(struct uart_driver *drv, + struct uart_port *port) +{ + const char *port_match __free(kfree) = NULL; + int ret; + + ret = serial_base_add_prefcon(drv->dev_name, port->line); + if (ret) + return ret; + + port_match = kasprintf(GFP_KERNEL, "%s:%i.%i", dev_name(port->dev), + port->ctrl_id, port->port_id); + if (!port_match) + return -ENOMEM; + + /* Translate a hardware addressing style console=DEVNAME:0.0 */ + return serial_base_add_one_prefcon(port_match, drv->dev_name, port->line); +} + +#endif + static int serial_base_init(void) { int ret; diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c index 3c0931fba1c68..a78ded8c60b52 100644 --- a/drivers/tty/serial/serial_core.c +++ b/drivers/tty/serial/serial_core.c @@ -3393,6 +3393,10 @@ int serial_core_register_port(struct uart_driver *drv, struct uart_port *port) if (ret) goto err_unregister_ctrl_dev; + ret = serial_base_add_preferred_console(drv, port); + if (ret) + goto err_unregister_port_dev; + ret = serial_core_add_one_port(drv, port); if (ret) goto err_unregister_port_dev;