2023-12-05 07:34:11

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH v4 0/4] Add support for DEVNAME:0.0 style hardware based addressing

Hi all,

With the recent serial core changes, we can now add DEVNAME:0.0 style
addressing for the serial ports. When using DEVNAME:0.0 naming, we don't
need to care which ttyS instance number is allocated depending on HSUART
settings or if the devicetree has added aliases for all the ports.

We also prepare the serial core to handle the ttyS related quirks done
in console_setup() to prepare things for eventually dropping the parsing
from console_setup(). This can only happen after further changes to
register_console().

Regards,

Tony

Changes since v3:
- Fix handling of brl_options by saving them too in console_opt_save()

- Drop changes to remove console_setup() parsing, further changes to
register_console() are still needed before can leave out the early
parsing

- Added a patch for serial8250_isa_init_preferred_console(), otherwise
the console gets initialized later for x86 when the console_setup()
parsing is dropped as pointed out by Petr

- Initialize __free() variables to NULL as noted by Dan

- Return handled in console_setup() if saving console options fails

- Simplify serial_base_add_preferred_console() and add a helper for
serial_base_add_one_prefcon() as suggested by Andy

- Header include changes to kernel/printk/conopt.c as suggested by Andy

Changes since v2:

- Console name got constified and already applied as suggested by Ilpo
and Andy

- Add printk/conopt.c to save console command line options

- Add a patch to drop old console_setup() character device name parsing

- Use cleanup.h to simplify freeing as suggested by Andy

- Use types.h instead of kernel.h as suggested by Andy

- Use strcspn() as suggested by Andy

- Various coding improvments suggested by Andy

Changes since v1:

- Constify printk add_preferred_console() as suggested by Jiri

- Use proper kernel command line helpers for parsing console as
suggested by Jiri

- Update description for HSUART based on Andy's comments

- Standardize on DEVNAME:0.0 style naming as suggested by Andy

- Added missing put_device() calls paired with device_find_child()

Tony Lindgren (4):
printk: Save console options for add_preferred_console_match()
serial: core: Add support for DEVNAME:0.0 style naming for kernel
console
serial: core: Handle serial console options
serial: 8250: Add preferred console in serial8250_isa_init_ports()

drivers/tty/serial/8250/8250_core.c | 32 +++++++
drivers/tty/serial/serial_base.h | 14 +++
drivers/tty/serial/serial_base_bus.c | 115 ++++++++++++++++++++++++
drivers/tty/serial/serial_core.c | 4 +
include/linux/printk.h | 3 +
kernel/printk/Makefile | 2 +-
kernel/printk/conopt.c | 128 +++++++++++++++++++++++++++
kernel/printk/console_cmdline.h | 6 ++
kernel/printk/printk.c | 14 ++-
9 files changed, 314 insertions(+), 4 deletions(-)
create mode 100644 kernel/printk/conopt.c

--
2.43.0


2023-12-05 07:34:40

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH v4 1/4] printk: Save console options for add_preferred_console_match()

Driver subsystems may need to translate the preferred console name to the
character device name used. We already do some of this in console_setup()
with a few hardcoded names, but that does not scale well.

The console options are parsed early in console_setup(), and the consoles
are added with __add_preferred_console(). At this point we don't know much
about the character device names and device drivers getting probed.

To allow drivers subsystems to set up a preferred console, let's save the
kernel command line console options. To add a preferred console from a
driver subsystem with optional character device name translation, let's
add a new function add_preferred_console_match().

This allows the serial core layer to support console=DEVNAME:0.0 style
hardware based addressing in addition to the current console=ttyS0 style
naming. And we can start moving console_setup() character device parsing
to the driver subsystem specific code.

We use a separate array from the console_cmdline array as the character
device name and index may be unknown at the console_setup() time. And
eventually there's no need to call __add_preferred_console() until the
character device name and index are known.

Adding the console name in addition to the character device name, and a
flag for an added console, could be added to the struct console_cmdline.
And the console_cmdline array handling could be modified accordingly. But
that complicates things compared saving the console options, and then
adding the consoles when the subsystems handling the consoles are ready.

Signed-off-by: Tony Lindgren <[email protected]>
---
include/linux/printk.h | 3 +
kernel/printk/Makefile | 2 +-
kernel/printk/conopt.c | 128 ++++++++++++++++++++++++++++++++
kernel/printk/console_cmdline.h | 6 ++
kernel/printk/printk.c | 14 +++-
5 files changed, 149 insertions(+), 4 deletions(-)
create mode 100644 kernel/printk/conopt.c

diff --git a/include/linux/printk.h b/include/linux/printk.h
--- a/include/linux/printk.h
+++ b/include/linux/printk.h
@@ -60,6 +60,9 @@ static inline const char *printk_skip_headers(const char *buffer)
#define CONSOLE_LOGLEVEL_DEFAULT CONFIG_CONSOLE_LOGLEVEL_DEFAULT
#define CONSOLE_LOGLEVEL_QUIET CONFIG_CONSOLE_LOGLEVEL_QUIET

+int add_preferred_console_match(const char *match, const char *name,
+ const short idx);
+
extern int console_printk[];

#define console_loglevel (console_printk[0])
diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile
--- a/kernel/printk/Makefile
+++ b/kernel/printk/Makefile
@@ -1,5 +1,5 @@
# SPDX-License-Identifier: GPL-2.0-only
-obj-y = printk.o
+obj-y = printk.o conopt.o
obj-$(CONFIG_PRINTK) += printk_safe.o nbcon.o
obj-$(CONFIG_A11Y_BRAILLE_CONSOLE) += braille.o
obj-$(CONFIG_PRINTK_INDEX) += index.o
diff --git a/kernel/printk/conopt.c b/kernel/printk/conopt.c
new file mode 100644
--- /dev/null
+++ b/kernel/printk/conopt.c
@@ -0,0 +1,128 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Kernel command line console options for hardware based addressing
+ *
+ * Copyright (C) 2023 Texas Instruments Incorporated - https://www.ti.com/
+ * Author: Tony Lindgren <[email protected]>
+ */
+
+#include <linux/console.h>
+#include <linux/init.h>
+#include <linux/string.h>
+
+#include <asm/errno.h>
+
+#include "console_cmdline.h"
+
+/*
+ * Allow longer DEVNAME:0.0 style console naming such as abcd0000.serial:0.0
+ * in addition to the legacy ttyS0 style naming.
+ */
+#define CONSOLE_NAME_MAX 32
+
+#define CONSOLE_OPT_MAX 16
+#define CONSOLE_BRL_OPT_MAX 16
+
+struct console_option {
+ char name[CONSOLE_NAME_MAX];
+ char opt[CONSOLE_OPT_MAX];
+ char brl_opt[CONSOLE_BRL_OPT_MAX];
+};
+
+/* Updated only at console_setup() time, no locking needed */
+static struct console_option conopt[MAX_CMDLINECONSOLES];
+
+/**
+ * console_opt_save - Saves kernel command line console option for driver use
+ * @str: Kernel command line console name and option
+ * @brl_opt: Braille console options
+ *
+ * Saves a kernel command line console option for driver subsystems to use for
+ * adding a preferred console during init. Called from console_setup() only.
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int __init console_opt_save(const char *str, const char *brl_opt)
+{
+ struct console_option *con;
+ const char *opt = NULL;
+ size_t namelen, optlen;
+ int i;
+
+ namelen = strcspn(str, ",");
+ if (!namelen)
+ return -EINVAL;
+
+ optlen = strlen(str) - namelen;
+ if (optlen > 1)
+ opt = str + namelen + 1;
+
+ if (namelen >= CONSOLE_NAME_MAX || optlen >= CONSOLE_OPT_MAX)
+ return -EINVAL;
+
+ for (i = 0; i < MAX_CMDLINECONSOLES; i++) {
+ con = &conopt[i];
+
+ if (con->name[0]) {
+ if (!strncmp(str, con->name, namelen))
+ return 0;
+ continue;
+ }
+
+ strscpy(con->name, str, namelen + 1);
+ if (opt)
+ strscpy(con->opt, opt, optlen + 1);
+
+ if (brl_opt)
+ strscpy(con->brl_opt, brl_opt, CONSOLE_BRL_OPT_MAX);
+
+ return 0;
+ }
+
+ return -ENOMEM;
+}
+
+static struct console_option *console_opt_find(const char *name)
+{
+ struct console_option *con;
+ int i;
+
+ for (i = 0; i < MAX_CMDLINECONSOLES; i++) {
+ con = &conopt[i];
+ if (!strcmp(name, con->name))
+ return con;
+ }
+
+ return NULL;
+}
+
+/**
+ * add_preferred_console_match - Adds a preferred console if a match is found
+ * @match: Expected console on kernel command line, such as console=DEVNAME:0.0
+ * @name: Name of the console character device to add such as ttyS
+ * @idx: Index for the console
+ *
+ * Allows driver subsystems to add a console after translating the command
+ * line name to the character device name used for the console. Options are
+ * added automatically based on the kernel command line. Duplicate preferred
+ * consoles are ignored by __add_preferred_console().
+ *
+ * Return: 0 on success, negative error code on failure.
+ */
+int add_preferred_console_match(const char *match, const char *name,
+ const short idx)
+{
+ struct console_option *con;
+
+ if (!match || !strlen(match) || !name || !strlen(name) ||
+ idx < 0)
+ return -EINVAL;
+
+ con = console_opt_find(match);
+ if (!con)
+ return -ENOENT;
+
+ console_opt_add_preferred_console(name, idx, con->opt, con->brl_opt);
+
+ return 0;
+}
diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h
--- a/kernel/printk/console_cmdline.h
+++ b/kernel/printk/console_cmdline.h
@@ -2,6 +2,12 @@
#ifndef _CONSOLE_CMDLINE_H
#define _CONSOLE_CMDLINE_H

+#define MAX_CMDLINECONSOLES 8
+
+int console_opt_save(const char *str, const char *brl_opt);
+int console_opt_add_preferred_console(const char *name, const short idx,
+ char *options, char *brl_options);
+
struct console_cmdline
{
char name[16]; /* Name of the driver */
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -360,9 +360,6 @@ static int console_locked;
/*
* Array of consoles built from command line options (console=)
*/
-
-#define MAX_CMDLINECONSOLES 8
-
static struct console_cmdline console_cmdline[MAX_CMDLINECONSOLES];

static int preferred_console = -1;
@@ -2458,6 +2455,10 @@ static int __init console_setup(char *str)
if (_braille_console_setup(&str, &brl_options))
return 1;

+ /* Save the console for driver subsystem use */
+ if (console_opt_save(str, brl_options))
+ return 1;
+
/*
* Decode str into name, index, options.
*/
@@ -2488,6 +2489,13 @@ static int __init console_setup(char *str)
}
__setup("console=", console_setup);

+/* Only called from add_preferred_console_match() */
+int console_opt_add_preferred_console(const char *name, const short idx,
+ char *options, char *brl_options)
+{
+ return __add_preferred_console(name, idx, options, brl_options, true);
+}
+
/**
* add_preferred_console - add a device to the list of preferred consoles.
* @name: device name
--
2.43.0

2023-12-05 07:35:13

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH v4 2/4] serial: core: Add support for DEVNAME:0.0 style naming for kernel console

We can now add hardware based addressing for serial ports. Starting with
commit 84a9582fd203 ("serial: core: Start managing serial controllers to
enable runtime PM"), and all the related fixes to this commit, the serial
core now knows to which serial port controller the ports are connected.

The serial ports can be addressed with DEVNAME:0.0 style naming. The names
are something like 00:04:0.0 for a serial port on qemu, and something like
2800000.serial:0.0 on platform device using systems like ARM64 for example.

The DEVNAME is the unique serial port hardware controller device name, AKA
the name for port->dev. The 0.0 are the serial core controller id and port
id.

Typically 0.0 are used for each controller and port instance unless the
serial port hardware controller has multiple controllers or ports.

Using DEVNAME:0.0 style naming actually solves two long term issues for
addressing the serial ports:

1. According to Andy Shevchenko, using DEVNAME:0.0 style naming fixes an
issue where depending on the BIOS settings, the kernel serial port ttyS
instance number may change if HSUART is enabled

2. Device tree using architectures no longer necessarily need to specify
aliases to find a specific serial port, and we can just allocate the
ttyS instance numbers dynamically in whatever probe order

To do this, let's match the hardware addressing style console name to
the character device name used, and add a preferred console using the
character device name.

Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/tty/serial/serial_base.h | 14 ++++++++
drivers/tty/serial/serial_base_bus.c | 48 ++++++++++++++++++++++++++++
drivers/tty/serial/serial_core.c | 4 +++
3 files changed, 66 insertions(+)

diff --git a/drivers/tty/serial/serial_base.h b/drivers/tty/serial/serial_base.h
--- a/drivers/tty/serial/serial_base.h
+++ b/drivers/tty/serial/serial_base.h
@@ -45,3 +45,17 @@ 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
--- 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 <linux/cleanup.h>
#include <linux/container_of.h>
#include <linux/device.h>
#include <linux/idr.h>
@@ -204,6 +205,53 @@ 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;
+}
+
+/**
+ * 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.
+ *
+ * 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);
+
+ 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
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -3359,6 +3359,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;
--
2.43.0

2023-12-05 07:35:49

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH v4 3/4] serial: core: Handle serial console options

In order to start moving the serial console quirks out of console_setup(),
let's add parsing for the quirks to the serial core layer. We can use
add_preferred_console_match() to handle the quirks.

At this point we can't drop the quirks from console_setup() because it
would confuse add_preferred_console(). And try_enable_default_console()
would get called before try_enable_preferred_console().

Note that eventually we may want to set up driver specific console quirk
handling for the serial port device drivers to use. But we need to figure
out which driver(s) need to call the quirk. So for now, we just handle the
sparc quirk directly.

Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/tty/serial/serial_base_bus.c | 67 ++++++++++++++++++++++++++++
1 file changed, 67 insertions(+)

diff --git a/drivers/tty/serial/serial_base_bus.c b/drivers/tty/serial/serial_base_bus.c
--- a/drivers/tty/serial/serial_base_bus.c
+++ b/drivers/tty/serial/serial_base_bus.c
@@ -207,6 +207,43 @@ void serial_base_port_device_remove(struct serial_port_device *port_dev)

#ifdef CONFIG_SERIAL_CORE_CONSOLE

+#ifdef __sparc__
+
+/* Handle Sparc ttya and ttyb options as done in console_setup() */
+static int serial_base_add_sparc_console(struct uart_driver *drv,
+ struct uart_port *port)
+{
+ const char *name = NULL;
+ int ret;
+
+ switch (port->line) {
+ case 0:
+ name = "ttya";
+ break;
+ case 1:
+ name = "ttyb";
+ break;
+ default:
+ return 0;
+ }
+
+ ret = add_preferred_console_match(name, drv->dev_name, port->line);
+ if (ret && ret != -ENOENT)
+ return ret;
+
+ return 0;
+}
+
+#else
+
+static inline int serial_base_add_sparc_console(struct uart_driver *drv,
+ struct uart_port *port)
+{
+ return 0;
+}
+
+#endif
+
static int serial_base_add_one_prefcon(const char *match, const char *dev_name,
int port_id)
{
@@ -240,12 +277,42 @@ int serial_base_add_preferred_console(struct uart_driver *drv,
struct uart_port *port)
{
const char *port_match __free(kfree);
+ const char *char_match __free(kfree) = NULL;
+ const char *nmbr_match __free(kfree) = NULL;
+ int ret;

port_match = kasprintf(GFP_KERNEL, "%s:%i.%i", dev_name(port->dev),
port->ctrl_id, port->port_id);
if (!port_match)
return -ENOMEM;

+ char_match = kasprintf(GFP_KERNEL, "%s%i", drv->dev_name, port->line);
+ if (!char_match)
+ return -ENOMEM;
+
+ /* Handle ttyS specific options */
+ if (!strncmp(drv->dev_name, "ttyS", 4)) {
+ /* No name, just a number */
+ nmbr_match = kasprintf(GFP_KERNEL, "%i", port->line);
+ if (!nmbr_match)
+ return -ENODEV;
+
+ ret = serial_base_add_one_prefcon(nmbr_match, drv->dev_name,
+ port->line);
+ if (ret)
+ return ret;
+
+ /* Sparc ttya and ttyb */
+ ret = serial_base_add_sparc_console(drv, port);
+ if (ret)
+ return ret;
+ }
+
+ /* Handle the traditional character device name style console=ttyS0 */
+ ret = serial_base_add_one_prefcon(char_match, drv->dev_name, port->line);
+ if (ret)
+ return ret;
+
/* Translate a hardware addressing style console=DEVNAME:0.0 */
return serial_base_add_one_prefcon(port_match, drv->dev_name, port->line);
}
--
2.43.0

2023-12-05 07:36:24

by Tony Lindgren

[permalink] [raw]
Subject: [PATCH v4 4/4] serial: 8250: Add preferred console in serial8250_isa_init_ports()

Prepare 8250 isa ports to drop kernel command line serial console
handling from console_setup().

We need to set the preferred console in serial8250_isa_init_ports().
Otherwise the console gets initialized only later on when the hardware
specific driver takes over, and console_setup() is no longer handling
the ttyS related quirks.

Note that this mostly affects x86 as this happens based on define
SERIAL_PORT_DFNS.

Signed-off-by: Tony Lindgren <[email protected]>
---
drivers/tty/serial/8250/8250_core.c | 32 +++++++++++++++++++++++++++++
1 file changed, 32 insertions(+)

diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -15,6 +15,7 @@
*/

#include <linux/acpi.h>
+#include <linux/cleanup.h>
#include <linux/module.h>
#include <linux/moduleparam.h>
#include <linux/ioport.h>
@@ -517,6 +518,35 @@ static struct uart_8250_port *serial8250_setup_port(int index)
return up;
}

+#ifdef CONFIG_SERIAL_8250_CONSOLE
+
+/*
+ * There is no struct device at this point, so let's not try to use
+ * serial_base_add_preferred_console().
+ */
+static void __init serial8250_isa_init_preferred_console(int idx)
+{
+ const char *name __free(kfree);
+ int ret;
+
+ name = kasprintf(GFP_KERNEL, "%s%i", serial8250_reg.dev_name, idx);
+ ret = add_preferred_console_match(name, serial8250_reg.dev_name, idx);
+ if (!ret || ret == -ENOENT)
+ return;
+
+ pr_err("Could not add preferred console for %s idx %i\n",
+ serial8250_reg.dev_name, idx);
+}
+
+#else
+
+static inline void serial8250_isa_init_preferred_console(struct uart_port *port,
+ int idx)
+{
+}
+
+#endif
+
static void __init serial8250_isa_init_ports(void)
{
struct uart_8250_port *up;
@@ -563,6 +593,8 @@ static void __init serial8250_isa_init_ports(void)
port->irqflags |= irqflag;
if (serial8250_isa_config != NULL)
serial8250_isa_config(i, &up->port, &up->capabilities);
+
+ serial8250_isa_init_preferred_console(i);
}
}

--
2.43.0

2023-12-05 07:46:59

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH v4 0/4] Add support for DEVNAME:0.0 style hardware based addressing

* Tony Lindgren <[email protected]> [700101 02:00]:
> We also prepare the serial core to handle the ttyS related quirks done
> in console_setup() to prepare things for eventually dropping the parsing
> from console_setup(). This can only happen after further changes to
> register_console().

Petr FYI, so for dropping the console_setup() parsing, below is a hack
patch to see what goes wrong in register_console() if you have some ideas
on how to handle this.

We end up with the console device backed up seria8250 instead of ttyS0,
and earlycon won't get properly disabled. And of course other consoles
beyond ttyS need to be also considered.

Regards,

Tony

8< ----------------------
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -2438,9 +2438,7 @@ __setup("console_msg_format=", console_msg_format_setup);
*/
static int __init console_setup(char *str)
{
- char buf[sizeof(console_cmdline[0].name) + 4]; /* 4 for "ttyS" */
- char *s, *options, *brl_options = NULL;
- int idx;
+ char *brl_options = NULL;

/*
* console="" or console=null have been suggested as a way to
@@ -2459,32 +2457,9 @@ static int __init console_setup(char *str)
if (console_opt_save(str, brl_options))
return 1;

- /*
- * Decode str into name, index, options.
- */
- if (str[0] >= '0' && str[0] <= '9') {
- strcpy(buf, "ttyS");
- strncpy(buf + 4, str, sizeof(buf) - 5);
- } else {
- strncpy(buf, str, sizeof(buf) - 1);
- }
- buf[sizeof(buf) - 1] = 0;
- options = strchr(str, ',');
- if (options)
- *(options++) = 0;
-#ifdef __sparc__
- if (!strcmp(str, "ttya"))
- strcpy(buf, "ttyS0");
- if (!strcmp(str, "ttyb"))
- strcpy(buf, "ttyS1");
-#endif
- for (s = buf; *s; s++)
- if (isdigit(*s) || *s == ',')
- break;
- idx = simple_strtoul(s, NULL, 10);
- *s = 0;
+ /* Indicate register_console() a console was specified */
+ console_set_on_cmdline = 1;

- __add_preferred_console(buf, idx, options, brl_options, true);
return 1;
}
__setup("console=", console_setup);
@@ -3476,7 +3451,7 @@ void register_console(struct console *newcon)
* Note that a console with tty binding will have CON_CONSDEV
* flag set and will be first in the list.
*/
- if (preferred_console < 0) {
+ if (preferred_console < 0 && !console_set_on_cmdline) {
if (hlist_empty(&console_list) || !console_first()->device ||
console_first()->flags & CON_BOOT) {
try_enable_default_console(newcon);

2023-12-05 16:07:16

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v4 3/4] serial: core: Handle serial console options

On Tue, Dec 05, 2023 at 09:32:35AM +0200, Tony Lindgren wrote:
> In order to start moving the serial console quirks out of console_setup(),
> let's add parsing for the quirks to the serial core layer. We can use
> add_preferred_console_match() to handle the quirks.
>
> At this point we can't drop the quirks from console_setup() because it
> would confuse add_preferred_console(). And try_enable_default_console()
> would get called before try_enable_preferred_console().
>
> Note that eventually we may want to set up driver specific console quirk
> handling for the serial port device drivers to use. But we need to figure
> out which driver(s) need to call the quirk. So for now, we just handle the
> sparc quirk directly.

...

> +static int serial_base_add_sparc_console(struct uart_driver *drv,
> + struct uart_port *port)
> +{
> + const char *name = NULL;
> + int ret;
> +
> + switch (port->line) {
> + case 0:
> + name = "ttya";
> + break;
> + case 1:
> + name = "ttyb";
> + break;
> + default:
> + return 0;
> + }

> + ret = add_preferred_console_match(name, drv->dev_name, port->line);
> + if (ret && ret != -ENOENT)
> + return ret;
> +
> + return 0;

return serial_base_add_one_prefcon(...);

?

> +}

...

> + if (!strncmp(drv->dev_name, "ttyS", 4)) {

str_has_prefix()

> + }

--
With Best Regards,
Andy Shevchenko


2023-12-05 16:09:02

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v4 4/4] serial: 8250: Add preferred console in serial8250_isa_init_ports()

On Tue, Dec 05, 2023 at 09:32:36AM +0200, Tony Lindgren wrote:
> Prepare 8250 isa ports to drop kernel command line serial console

ISA

> handling from console_setup().
>
> We need to set the preferred console in serial8250_isa_init_ports().
> Otherwise the console gets initialized only later on when the hardware
> specific driver takes over, and console_setup() is no longer handling
> the ttyS related quirks.
>
> Note that this mostly affects x86 as this happens based on define
> SERIAL_PORT_DFNS.

...

> +static void __init serial8250_isa_init_preferred_console(int idx)
> +{
> + const char *name __free(kfree);
> + int ret;
> +
> + name = kasprintf(GFP_KERNEL, "%s%i", serial8250_reg.dev_name, idx);

No error check?

> + ret = add_preferred_console_match(name, serial8250_reg.dev_name, idx);
> + if (!ret || ret == -ENOENT)
> + return;

ret = serial_base_add_one_prefcon(...);

?

> + pr_err("Could not add preferred console for %s idx %i\n",
> + serial8250_reg.dev_name, idx);
> +}

--
With Best Regards,
Andy Shevchenko


2023-12-05 16:12:24

by Andy Shevchenko

[permalink] [raw]
Subject: Re: [PATCH v4 4/4] serial: 8250: Add preferred console in serial8250_isa_init_ports()

On Tue, Dec 05, 2023 at 06:08:37PM +0200, Andy Shevchenko wrote:
> On Tue, Dec 05, 2023 at 09:32:36AM +0200, Tony Lindgren wrote:

...

> > + pr_err("Could not add preferred console for %s idx %i\n",
> > + serial8250_reg.dev_name, idx);

And, btw, you can simply reuse name here

pr_err("Could not add preferred console for %s\n", name);

Would it work?

--
With Best Regards,
Andy Shevchenko


2023-12-05 18:08:27

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 4/4] serial: 8250: Add preferred console in serial8250_isa_init_ports()

Hi Tony,

kernel test robot noticed the following build errors:

[auto build test ERROR on tty/tty-testing]
[also build test ERROR on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus linus/master v6.7-rc4 next-20231205]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Tony-Lindgren/printk-Save-console-options-for-add_preferred_console_match/20231205-153731
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20231205073255.20562-5-tony%40atomide.com
patch subject: [PATCH v4 4/4] serial: 8250: Add preferred console in serial8250_isa_init_ports()
config: powerpc-randconfig-r081-20231205 (https://download.01.org/0day-ci/archive/20231206/[email protected]/config)
compiler: clang version 17.0.0 (https://github.com/llvm/llvm-project.git 4a5ac14ee968ff0ad5d2cc1ffa0299048db4c88a)
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231206/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All errors (new ones prefixed by >>):

>> drivers/tty/serial/8250/8250_core.c:597:42: error: too few arguments to function call, expected 2, have 1
597 | serial8250_isa_init_preferred_console(i);
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ^
drivers/tty/serial/8250/8250_core.c:543:20: note: 'serial8250_isa_init_preferred_console' declared here
543 | static inline void serial8250_isa_init_preferred_console(struct uart_port *port,
| ^
1 error generated.


vim +597 drivers/tty/serial/8250/8250_core.c

549
550 static void __init serial8250_isa_init_ports(void)
551 {
552 struct uart_8250_port *up;
553 static int first = 1;
554 int i, irqflag = 0;
555
556 if (!first)
557 return;
558 first = 0;
559
560 if (nr_uarts > UART_NR)
561 nr_uarts = UART_NR;
562
563 /*
564 * Set up initial isa ports based on nr_uart module param, or else
565 * default to CONFIG_SERIAL_8250_RUNTIME_UARTS. Note that we do not
566 * need to increase nr_uarts when setting up the initial isa ports.
567 */
568 for (i = 0; i < nr_uarts; i++)
569 serial8250_setup_port(i);
570
571 /* chain base port ops to support Remote Supervisor Adapter */
572 univ8250_port_ops = *base_ops;
573 univ8250_rsa_support(&univ8250_port_ops);
574
575 if (share_irqs)
576 irqflag = IRQF_SHARED;
577
578 for (i = 0, up = serial8250_ports;
579 i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
580 i++, up++) {
581 struct uart_port *port = &up->port;
582
583 port->iobase = old_serial_port[i].port;
584 port->irq = irq_canonicalize(old_serial_port[i].irq);
585 port->irqflags = 0;
586 port->uartclk = old_serial_port[i].baud_base * 16;
587 port->flags = old_serial_port[i].flags;
588 port->hub6 = 0;
589 port->membase = old_serial_port[i].iomem_base;
590 port->iotype = old_serial_port[i].io_type;
591 port->regshift = old_serial_port[i].iomem_reg_shift;
592
593 port->irqflags |= irqflag;
594 if (serial8250_isa_config != NULL)
595 serial8250_isa_config(i, &up->port, &up->capabilities);
596
> 597 serial8250_isa_init_preferred_console(i);
598 }
599 }
600

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2023-12-05 18:30:49

by kernel test robot

[permalink] [raw]
Subject: Re: [PATCH v4 4/4] serial: 8250: Add preferred console in serial8250_isa_init_ports()

Hi Tony,

kernel test robot noticed the following build errors:

[auto build test ERROR on tty/tty-testing]
[also build test ERROR on tty/tty-next tty/tty-linus usb/usb-testing usb/usb-next usb/usb-linus linus/master v6.7-rc4 next-20231205]
[If your patch is applied to the wrong git tree, kindly drop us a note.
And when submitting patch, we suggest to use '--base' as documented in
https://git-scm.com/docs/git-format-patch#_base_tree_information]

url: https://github.com/intel-lab-lkp/linux/commits/Tony-Lindgren/printk-Save-console-options-for-add_preferred_console_match/20231205-153731
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20231205073255.20562-5-tony%40atomide.com
patch subject: [PATCH v4 4/4] serial: 8250: Add preferred console in serial8250_isa_init_ports()
config: m68k-randconfig-r071-20231205 (https://download.01.org/0day-ci/archive/20231206/[email protected]/config)
compiler: m68k-linux-gcc (GCC) 13.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20231206/[email protected]/reproduce)

If you fix the issue in a separate patch/commit (i.e. not just a new version of
the same patch/commit), kindly add following tags
| Reported-by: kernel test robot <[email protected]>
| Closes: https://lore.kernel.org/oe-kbuild-all/[email protected]/

All error/warnings (new ones prefixed by >>):

drivers/tty/serial/8250/8250_core.c: In function 'serial8250_isa_init_ports':
>> drivers/tty/serial/8250/8250_core.c:597:55: warning: passing argument 1 of 'serial8250_isa_init_preferred_console' makes pointer from integer without a cast [-Wint-conversion]
597 | serial8250_isa_init_preferred_console(i);
| ^
| |
| int
drivers/tty/serial/8250/8250_core.c:543:76: note: expected 'struct uart_port *' but argument is of type 'int'
543 | static inline void serial8250_isa_init_preferred_console(struct uart_port *port,
| ~~~~~~~~~~~~~~~~~~^~~~
>> drivers/tty/serial/8250/8250_core.c:597:17: error: too few arguments to function 'serial8250_isa_init_preferred_console'
597 | serial8250_isa_init_preferred_console(i);
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
drivers/tty/serial/8250/8250_core.c:543:20: note: declared here
543 | static inline void serial8250_isa_init_preferred_console(struct uart_port *port,
| ^~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~


vim +/serial8250_isa_init_preferred_console +597 drivers/tty/serial/8250/8250_core.c

549
550 static void __init serial8250_isa_init_ports(void)
551 {
552 struct uart_8250_port *up;
553 static int first = 1;
554 int i, irqflag = 0;
555
556 if (!first)
557 return;
558 first = 0;
559
560 if (nr_uarts > UART_NR)
561 nr_uarts = UART_NR;
562
563 /*
564 * Set up initial isa ports based on nr_uart module param, or else
565 * default to CONFIG_SERIAL_8250_RUNTIME_UARTS. Note that we do not
566 * need to increase nr_uarts when setting up the initial isa ports.
567 */
568 for (i = 0; i < nr_uarts; i++)
569 serial8250_setup_port(i);
570
571 /* chain base port ops to support Remote Supervisor Adapter */
572 univ8250_port_ops = *base_ops;
573 univ8250_rsa_support(&univ8250_port_ops);
574
575 if (share_irqs)
576 irqflag = IRQF_SHARED;
577
578 for (i = 0, up = serial8250_ports;
579 i < ARRAY_SIZE(old_serial_port) && i < nr_uarts;
580 i++, up++) {
581 struct uart_port *port = &up->port;
582
583 port->iobase = old_serial_port[i].port;
584 port->irq = irq_canonicalize(old_serial_port[i].irq);
585 port->irqflags = 0;
586 port->uartclk = old_serial_port[i].baud_base * 16;
587 port->flags = old_serial_port[i].flags;
588 port->hub6 = 0;
589 port->membase = old_serial_port[i].iomem_base;
590 port->iotype = old_serial_port[i].io_type;
591 port->regshift = old_serial_port[i].iomem_reg_shift;
592
593 port->irqflags |= irqflag;
594 if (serial8250_isa_config != NULL)
595 serial8250_isa_config(i, &up->port, &up->capabilities);
596
> 597 serial8250_isa_init_preferred_console(i);
598 }
599 }
600

--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki

2023-12-07 07:24:30

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH v4 4/4] serial: 8250: Add preferred console in serial8250_isa_init_ports()

* Andy Shevchenko <[email protected]> [231205 16:08]:
> On Tue, Dec 05, 2023 at 09:32:36AM +0200, Tony Lindgren wrote:
> > + name = kasprintf(GFP_KERNEL, "%s%i", serial8250_reg.dev_name, idx);
>
> No error check?

Oops

> > + ret = add_preferred_console_match(name, serial8250_reg.dev_name, idx);
> > + if (!ret || ret == -ENOENT)
> > + return;
>
> ret = serial_base_add_one_prefcon(...);
>
> ?

Yup that should work even before struct device. Will fix the other
places too you noticed.

Thanks,

Tony

2023-12-08 08:29:19

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH v4 0/4] Add support for DEVNAME:0.0 style hardware based addressing

* Tony Lindgren <[email protected]> [700101 02:00]:
> * Tony Lindgren <[email protected]> [700101 02:00]:
> > We also prepare the serial core to handle the ttyS related quirks done
> > in console_setup() to prepare things for eventually dropping the parsing
> > from console_setup(). This can only happen after further changes to
> > register_console().
>
> Petr FYI, so for dropping the console_setup() parsing, below is a hack
> patch to see what goes wrong in register_console() if you have some ideas
> on how to handle this.
>
> We end up with the console device backed up seria8250 instead of ttyS0,
> and earlycon won't get properly disabled. And of course other consoles
> beyond ttyS need to be also considered.

Hmm so the following extra patch seems to fix the issues based on light
testing. But is it safe to assume that if CON_PRINTBUFFER is set we can
disable the bootconsole?

I also noticed that the bootconsole not getting disabled issue is there
also for console=DEVNAME:0.0 usage even before we start dropping handling
in console_setup().

Regards,

Tony

8< ----------------------
diff --git a/kernel/printk/printk.c b/kernel/printk/printk.c
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -3549,7 +3549,8 @@ void register_console(struct console *newcon)
*/
con_printk(KERN_INFO, newcon, "enabled\n");
if (bootcon_registered &&
- ((newcon->flags & (CON_CONSDEV | CON_BOOT)) == CON_CONSDEV) &&
+ !(newcon->flags & CON_BOOT) &&
+ (newcon->flags & (CON_CONSDEV | CON_PRINTBUFFER)) &&
!keep_bootcon) {
struct hlist_node *tmp;

--
2.43.0

2023-12-18 06:49:30

by Tony Lindgren

[permalink] [raw]
Subject: Re: [PATCH v4 0/4] Add support for DEVNAME:0.0 style hardware based addressing

* Tony Lindgren <[email protected]> [231208 10:29]:
> * Tony Lindgren <[email protected]> [700101 02:00]:
> > * Tony Lindgren <[email protected]> [700101 02:00]:
> > > We also prepare the serial core to handle the ttyS related quirks done
> > > in console_setup() to prepare things for eventually dropping the parsing
> > > from console_setup(). This can only happen after further changes to
> > > register_console().
> >
> > Petr FYI, so for dropping the console_setup() parsing, below is a hack
> > patch to see what goes wrong in register_console() if you have some ideas
> > on how to handle this.
> >
> > We end up with the console device backed up seria8250 instead of ttyS0,
> > and earlycon won't get properly disabled. And of course other consoles
> > beyond ttyS need to be also considered.
>
> Hmm so the following extra patch seems to fix the issues based on light
> testing. But is it safe to assume that if CON_PRINTBUFFER is set we can
> disable the bootconsole?

OK so no need for the CON_PRINTBUFFER change, it's wrong. I found a few
bugs causing this issue and a lot of other confusion while testing:

- In console_setup(), a DEVNAME:0.0 style console can get added with the
IO address turned into a ttyS console with some crazy index :) So we
need to bail out early on consoles with ':' in the name.

- The brl_opts can be empty or NULL, but we need to pass NULL to
__add_preferred_console() to get CON_CONSDEV flag set for DEVNAME:0.0
console. Otherwise the preferred_console won't get set and the boot
console won't get disabled.

- The console_set_on_cmdline flag needs to be set if console_setup()
does not call __add_preferred_console() for DEVNAME:0.0 style console
as otherwise try_enable_default_console() may get called before the
console handling driver has added the preferred console.

I think with these the remaining issues are sorted out :) I'll post a
v5 set with as RFC as it's getting close to the merge window.

Regards,

Tony