[v3,1/3] printk: Save console options for add_preferred_console_match()
Commit Message
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, 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 we do
not want 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 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 <tony@atomide.com>
---
include/linux/printk.h | 3 +
kernel/printk/Makefile | 2 +-
kernel/printk/conopt.c | 115 ++++++++++++++++++++++++++++++++
kernel/printk/console_cmdline.h | 4 ++
kernel/printk/printk.c | 11 ++-
5 files changed, 131 insertions(+), 4 deletions(-)
create mode 100644 kernel/printk/conopt.c
Comments
On Tue, Nov 21, 2023 at 01:31:55PM +0200, Tony Lindgren wrote:
> 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, 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 we do
> not want 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 modified accordingly. But that
> complicates things compared saving the console options, and then adding
> the consoles when the subsystems handling the consoles are ready.
...
> +#include <linux/console.h>
> +#include <linux/kernel.h>
I think instead of kernel.h you may want to see these:
linux/init.h
linux/string.h
asm/errno.h
> +#include "console_cmdline.h"
...
> +/**
> + * console_opt_save - Saves kernel command line console option for driver use
> + * @str: Kernel command line console name and option
> + *
> + * Saves a kernel command line console option for driver subsystems to use for
> + * adding a preferred console during init. Called from console_setup() only.
scripts/kernel-doc -v -none -Wall ...
most likely will complain (no Return section).
> + */
> +int __init console_opt_save(char *str)
str is not const? Hmm...
* Andy Shevchenko <andriy.shevchenko@intel.com> [231121 17:53]:
> On Tue, Nov 21, 2023 at 01:31:55PM +0200, Tony Lindgren wrote:
> > +#include <linux/console.h>
>
> > +#include <linux/kernel.h>
>
> I think instead of kernel.h you may want to see these:
>
> linux/init.h
> linux/string.h
>
> asm/errno.h
>
> > +#include "console_cmdline.h"
OK
> > +/**
> > + * console_opt_save - Saves kernel command line console option for driver use
> > + * @str: Kernel command line console name and option
> > + *
> > + * Saves a kernel command line console option for driver subsystems to use for
> > + * adding a preferred console during init. Called from console_setup() only.
>
> scripts/kernel-doc -v -none -Wall ...
>
> most likely will complain (no Return section).
OK adding.
> > + */
> > +int __init console_opt_save(char *str)
>
> str is not const? Hmm...
Nice yes it can be const char *str here. Hmm maybe with the third patch
also console_setup() can use const char * now.. Will check.
Thanks,
Tony
* Tony Lindgren <tony@atomide.com> [231122 08:18]:
> * Andy Shevchenko <andriy.shevchenko@intel.com> [231121 17:53]:
> > On Tue, Nov 21, 2023 at 01:31:55PM +0200, Tony Lindgren wrote:
> > > +int __init console_opt_save(char *str)
> >
> > str is not const? Hmm...
>
> Nice yes it can be const char *str here. Hmm maybe with the third patch
> also console_setup() can use const char * now.. Will check.
Nah console_setup() uses __setup().
Tony
@@ -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])
@@ -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
new file mode 100644
@@ -0,0 +1,115 @@
+// 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 <tony@atomide.com>
+ */
+
+#include <linux/console.h>
+#include <linux/kernel.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
+
+struct console_option {
+ char name[CONSOLE_NAME_MAX];
+ char opt[CONSOLE_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
+ *
+ * Saves a kernel command line console option for driver subsystems to use for
+ * adding a preferred console during init. Called from console_setup() only.
+ */
+int __init console_opt_save(char *str)
+{
+ 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);
+
+ 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().
+ */
+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;
+
+ add_preferred_console(name, idx, con->opt);
+
+ return 0;
+}
@@ -2,6 +2,10 @@
#ifndef _CONSOLE_CMDLINE_H
#define _CONSOLE_CMDLINE_H
+#define MAX_CMDLINECONSOLES 8
+
+int console_opt_save(char *str);
+
struct console_cmdline
{
char name[16]; /* Name of the driver */
@@ -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;
@@ -2445,6 +2442,14 @@ static int __init console_setup(char *str)
char *s, *options, *brl_options = NULL;
int idx;
+ /*
+ * Save the console for possible driver subsystem use. Bail out early
+ * for DEVICE:0.0 style console names as the character device name is
+ * be unknown at this point.
+ */
+ if (!console_opt_save(str) && strchr(str, ':'))
+ return 1;
+
/*
* console="" or console=null have been suggested as a way to
* disable console output. Use ttynull that has been created