aboutsummaryrefslogtreecommitdiff
path: root/kernel/printk
diff options
context:
space:
mode:
authorLinus Torvalds2024-05-22 11:53:02 -0700
committerLinus Torvalds2024-05-22 11:53:02 -0700
commitf6b8e86b7a65495d3947a1d1fc22183c52f786f6 (patch)
treef0b15efd2dc851079a55a7b4e8a198fb6faa97ec /kernel/printk
parent89601f675b008ed0fd66c060fb23354a106436bb (diff)
parente21de1455a721a0cb4217b18589ede846f5b0686 (diff)
Merge tag 'tty-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty
Pull tty / serial updates from Greg KH: "Here is the big set of tty/serial driver changes for 6.10-rc1. Included in here are: - Usual good set of api cleanups and evolution by Jiri Slaby to make the serial interfaces move out of the 1990's by using kfifos instead of hand-rolling their own logic. - 8250_exar driver updates - max3100 driver updates - sc16is7xx driver updates - exar driver updates - sh-sci driver updates - tty ldisc api addition to help refuse bindings - other smaller serial driver updates All of these have been in linux-next for a while with no reported issues" * tag 'tty-6.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty: (113 commits) serial: Clear UPF_DEAD before calling tty_port_register_device_attr_serdev() serial: imx: Raise TX trigger level to 8 serial: 8250_pnp: Simplify "line" related code serial: sh-sci: simplify locking when re-issuing RXDMA fails serial: sh-sci: let timeout timer only run when DMA is scheduled serial: sh-sci: describe locking requirements for invalidating RXDMA serial: sh-sci: protect invalidating RXDMA on shutdown tty: add the option to have a tty reject a new ldisc serial: core: Call device_set_awake_path() for console port dt-bindings: serial: brcm,bcm2835-aux-uart: convert to dtschema tty: serial: uartps: Add support for uartps controller reset arm64: zynqmp: Add resets property for UART nodes dt-bindings: serial: cdns,uart: Add optional reset property serial: 8250_pnp: Switch to DEFINE_SIMPLE_DEV_PM_OPS() serial: 8250_exar: Keep the includes sorted serial: 8250_exar: Make type of bit the same in exar_ee_*_bit() serial: 8250_exar: Use BIT() in exar_ee_read() serial: 8250_exar: Switch to use dev_err_probe() serial: 8250_exar: Return directly from switch-cases serial: 8250_exar: Decrease indentation level ...
Diffstat (limited to 'kernel/printk')
-rw-r--r--kernel/printk/Makefile2
-rw-r--r--kernel/printk/conopt.c146
-rw-r--r--kernel/printk/console_cmdline.h6
-rw-r--r--kernel/printk/printk.c100
4 files changed, 225 insertions, 29 deletions
diff --git a/kernel/printk/Makefile b/kernel/printk/Makefile
index 39a2b61c7232..040fe7d1eda2 100644
--- 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
index 000000000000..9d507bac3657
--- /dev/null
+++ b/kernel/printk/conopt.c
@@ -0,0 +1,146 @@
+// 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/init.h>
+#include <linux/string.h>
+#include <linux/types.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];
+ u8 has_brl_opt:1;
+};
+
+/* 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;
+ size_t namelen, optlen;
+ const char *opt;
+ int i;
+
+ namelen = strcspn(str, ",");
+ if (namelen == 0 || namelen >= CONSOLE_NAME_MAX)
+ return -EINVAL;
+
+ opt = str + namelen;
+ if (*opt == ',')
+ opt++;
+
+ optlen = strlen(opt);
+ if (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;
+ }
+
+ /*
+ * The name isn't terminated, only opt is. Empty opt is fine,
+ * but brl_opt can be either empty or NULL. For more info, see
+ * _braille_console_setup().
+ */
+ strscpy(con->name, str, namelen + 1);
+ strscpy(con->opt, opt, CONSOLE_OPT_MAX);
+ if (brl_opt) {
+ strscpy(con->brl_opt, brl_opt, CONSOLE_BRL_OPT_MAX);
+ con->has_brl_opt = 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().
+ *
+ * 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;
+ char *brl_opt = NULL;
+
+ if (!match || !strlen(match) || !name || !strlen(name) ||
+ idx < 0)
+ return -EINVAL;
+
+ con = console_opt_find(match);
+ if (!con)
+ return -ENOENT;
+
+ /*
+ * See __add_preferred_console(). It checks for NULL brl_options to set
+ * the preferred_console flag. Empty brl_opt instead of NULL leads into
+ * the preferred_console flag not set, and CON_CONSDEV not being set,
+ * and the boot console won't get disabled at the end of console_setup().
+ */
+ if (con->has_brl_opt)
+ brl_opt = con->brl_opt;
+
+ console_opt_add_preferred_console(name, idx, con->opt, brl_opt);
+
+ return 0;
+}
diff --git a/kernel/printk/console_cmdline.h b/kernel/printk/console_cmdline.h
index 3ca74ad391d6..a125e0235589 100644
--- 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
index 3160d287d4cf..420fd310129d 100644
--- a/kernel/printk/printk.c
+++ b/kernel/printk/printk.c
@@ -383,9 +383,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;
@@ -2503,6 +2500,17 @@ 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;
+
+ /* Flag register_console() to not call try_enable_default_console() */
+ console_set_on_cmdline = 1;
+
+ /* Don't attempt to parse a DEVNAME:0.0 style console */
+ if (strchr(str, ':'))
+ return 1;
+
/*
* Decode str into name, index, options.
*/
@@ -2533,6 +2541,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
@@ -3146,6 +3161,40 @@ void console_unblank(void)
pr_flush(1000, true);
}
+/*
+ * Rewind all consoles to the oldest available record.
+ *
+ * IMPORTANT: The function is safe only when called under
+ * console_lock(). It is not enforced because
+ * it is used as a best effort in panic().
+ */
+static void __console_rewind_all(void)
+{
+ struct console *c;
+ short flags;
+ int cookie;
+ u64 seq;
+
+ seq = prb_first_valid_seq(prb);
+
+ cookie = console_srcu_read_lock();
+ for_each_console_srcu(c) {
+ flags = console_srcu_read_flags(c);
+
+ if (flags & CON_NBCON) {
+ nbcon_seq_force(c, seq);
+ } else {
+ /*
+ * This assignment is safe only when called under
+ * console_lock(). On panic, legacy consoles are
+ * only best effort.
+ */
+ c->seq = seq;
+ }
+ }
+ console_srcu_read_unlock(cookie);
+}
+
/**
* console_flush_on_panic - flush console content on panic
* @mode: flush all messages in buffer or just the pending ones
@@ -3174,30 +3223,8 @@ void console_flush_on_panic(enum con_flush_mode mode)
*/
console_may_schedule = 0;
- if (mode == CONSOLE_REPLAY_ALL) {
- struct console *c;
- short flags;
- int cookie;
- u64 seq;
-
- seq = prb_first_valid_seq(prb);
-
- cookie = console_srcu_read_lock();
- for_each_console_srcu(c) {
- flags = console_srcu_read_flags(c);
-
- if (flags & CON_NBCON) {
- nbcon_seq_force(c, seq);
- } else {
- /*
- * This is an unsynchronized assignment. On
- * panic legacy consoles are only best effort.
- */
- c->seq = seq;
- }
- }
- console_srcu_read_unlock(cookie);
- }
+ if (mode == CONSOLE_REPLAY_ALL)
+ __console_rewind_all();
console_flush_all(false, &next_seq, &handover);
}
@@ -3495,7 +3522,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);
@@ -4286,6 +4313,23 @@ void kmsg_dump_rewind(struct kmsg_dump_iter *iter)
}
EXPORT_SYMBOL_GPL(kmsg_dump_rewind);
+/**
+ * console_replay_all - replay kernel log on consoles
+ *
+ * Try to obtain lock on console subsystem and replay all
+ * available records in printk buffer on the consoles.
+ * Does nothing if lock is not obtained.
+ *
+ * Context: Any context.
+ */
+void console_replay_all(void)
+{
+ if (console_trylock()) {
+ __console_rewind_all();
+ /* Consoles are flushed as part of console_unlock(). */
+ console_unlock();
+ }
+}
#endif
#ifdef CONFIG_SMP