summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2026-10-06 11:32:54 +0200
committerLinus Torvalds <torvalds@linux-foundation.org>2026-10-06 11:32:54 +0200
commit22430ae5d90ab288b0ee2ad99ae941f4a666b694 (patch)
tree356f26177b7b428232f7205c452b6d98cde9fa7a
parent2c3418fffa9d037b2038a6db48be63f9e2291806 (diff)
parentc83e3d2912432107148cc5e288ddd153a84c0f43 (diff)
Merge tag 'printk-for-7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux
Pull printk fix from Petr Mladek: - Allow using Braille console with a serial console driver converted to NBCON API * tag 'printk-for-7.3-rc7' of git://git.kernel.org/pub/scm/linux/kernel/git/printk/linux: braille: nbcon: Allow to use a serial console with NBCON API as Braille console
-rw-r--r--drivers/accessibility/braille/braille_console.c57
-rw-r--r--drivers/tty/serial/8250/8250_port.c5
-rw-r--r--drivers/tty/serial/amba-pl011.c2
-rw-r--r--drivers/tty/serial/imx.c2
-rw-r--r--drivers/tty/serial/sifive.c2
-rw-r--r--include/linux/console.h15
-rw-r--r--kernel/printk/nbcon.c79
7 files changed, 156 insertions, 6 deletions
diff --git a/drivers/accessibility/braille/braille_console.c b/drivers/accessibility/braille/braille_console.c
index 06b43b678d6e..5a3e375f4800 100644
--- a/drivers/accessibility/braille/braille_console.c
+++ b/drivers/accessibility/braille/braille_console.c
@@ -62,14 +62,50 @@ static void braille_write(u16 *buf)
{
static u16 lastwrite[WIDTH];
unsigned char data[1 + 1 + 2*WIDTH + 2 + 1], csum = 0, *c;
+ struct nbcon_write_context wctxt = { };
+ unsigned long flags;
u16 out;
int i;
if (!braille_co)
return;
+ /*
+ * Braille console is not registered in console_list. Instead, it
+ * is integrated with VT and shows what appears on the graphical
+ * console under console_lock(). From this POV it is a legacy
+ * console. But it calls serial console driver which might be
+ * converted to the NBCON API. It is similar to
+ * nbcon_legacy_emit_next_record() except that we should try
+ * harder to get the lock. Otherwise, the Braille device won't show
+ * everything what is displayed on the terminal.
+ *
+ * In short, simulate the original locking using NBCON API.
+ */
+ if (braille_co->flags & CON_NBCON) {
+ if (panic_on_this_cpu()) {
+ /*
+ * This should be good enough in practice. Most/all
+ * serial console drivers have the atomic callback.
+ */
+ if (!braille_co->write_atomic)
+ return;
+
+ local_irq_save(flags);
+ /* NBCON API strictly requires the ownership. */
+ if (!nbcon_braille_try_acquire(braille_co, &wctxt)) {
+ local_irq_restore(flags);
+ return;
+ }
+ } else {
+ braille_co->device_lock(braille_co, &flags);
+ while (!nbcon_braille_try_acquire(braille_co, &wctxt))
+ cpu_relax();
+ }
+ }
+
if (!memcmp(lastwrite, buf, WIDTH * sizeof(*buf)))
- return;
+ goto unlock_nbcon;
memcpy(lastwrite, buf, WIDTH * sizeof(*buf));
#define SOH 1
@@ -102,7 +138,24 @@ static void braille_write(u16 *buf)
*c++ = csum;
*c++ = ETX;
- braille_co->write(braille_co, data, c - data);
+ if (braille_co->flags & CON_NBCON) {
+ nbcon_write_context_set_buf(&wctxt, (char *)data, c - data);
+ if (panic_on_this_cpu())
+ braille_co->write_atomic(braille_co, &wctxt);
+ else
+ braille_co->write_thread(braille_co, &wctxt);
+ } else {
+ braille_co->write(braille_co, data, c - data);
+ }
+
+unlock_nbcon:
+ if (braille_co->flags & CON_NBCON) {
+ nbcon_braille_release(&wctxt);
+ if (panic_on_this_cpu())
+ local_irq_restore(flags);
+ else
+ braille_co->device_unlock(braille_co, flags);
+ }
}
/* Follow the VC cursor*/
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 1acb73e45f8a..b01baff71f60 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -3417,8 +3417,11 @@ static void __serial8250_console_write(struct uart_8250_port *up,
* If the console printer did not fully output the previous line, it
* must have been handed or taken over. Insert a newline in order to
* maintain clean output.
+ *
+ * Braille consoles are an exception. The serial port is not used
+ * for printk(). The driver is supposed to write exactly what it gets.
*/
- if (!up->console_line_ended) {
+ if (unlikely(!up->console_line_ended && !nbcon_write_context_is_braille(wctxt))) {
if (use_fifo)
__serial8250_console_fifo_write(up, wctxt, "\n", 1);
else
diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c
index c4824c201e1c..e67f2ac454b6 100644
--- a/drivers/tty/serial/amba-pl011.c
+++ b/drivers/tty/serial/amba-pl011.c
@@ -2656,7 +2656,7 @@ pl011_console_write_atomic(struct console *co, struct nbcon_write_context *wctxt
uap, REG_CR);
}
- if (!uap->console_line_ended)
+ if (unlikely(!uap->console_line_ended && !nbcon_is_braille(co)))
uart_console_write(&uap->port, "\n", 1, pl011_console_putchar);
uart_console_write(&uap->port, wctxt->outbuf, wctxt->len, pl011_console_putchar);
diff --git a/drivers/tty/serial/imx.c b/drivers/tty/serial/imx.c
index 513dbe95f7e9..986fefb45c63 100644
--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -2136,7 +2136,7 @@ static void imx_uart_console_write_atomic(struct console *co,
imx_uart_writel(sport, ucr1, UCR1);
imx_uart_writel(sport, old_ucr.ucr2 | UCR2_TXEN, UCR2);
- if (!sport->last_putchar_was_newline)
+ if (unlikely(!sport->last_putchar_was_newline && !nbcon_is_braille(co)))
uart_console_write(port, "\n", 1, imx_uart_console_putchar);
uart_console_write(port, wctxt->outbuf, wctxt->len,
imx_uart_console_putchar);
diff --git a/drivers/tty/serial/sifive.c b/drivers/tty/serial/sifive.c
index 110d67613192..f615701fceb7 100644
--- a/drivers/tty/serial/sifive.c
+++ b/drivers/tty/serial/sifive.c
@@ -821,7 +821,7 @@ static void sifive_serial_console_write_atomic(struct console *co,
ier = __ssp_readl(ssp, SIFIVE_SERIAL_IE_OFFS);
__ssp_writel(0, SIFIVE_SERIAL_IE_OFFS, ssp);
- if (!ssp->console_line_ended)
+ if (unlikely(!ssp->console_line_ended && !nbcon_is_braille(co)))
uart_console_write(port, "\n", 1, sifive_serial_console_putchar);
uart_console_write(port, wctxt->outbuf, wctxt->len,
sifive_serial_console_putchar);
diff --git a/include/linux/console.h b/include/linux/console.h
index 502d1abe3f50..df23148987ee 100644
--- a/include/linux/console.h
+++ b/include/linux/console.h
@@ -615,6 +615,15 @@ extern bool nbcon_allow_unsafe_takeover(void);
extern bool nbcon_kdb_try_acquire(struct console *con,
struct nbcon_write_context *wctxt);
extern void nbcon_kdb_release(struct nbcon_write_context *wctxt);
+extern bool nbcon_write_context_is_braille(struct nbcon_write_context *wctxt);
+extern bool nbcon_braille_try_acquire(struct console *con,
+ struct nbcon_write_context *wctxt);
+extern void nbcon_braille_release(struct nbcon_write_context *wctxt);
+
+static inline bool nbcon_is_braille(struct console *con)
+{
+ return con && (con->flags & CON_BRL);
+}
/*
* Check if the given console is currently capable and allowed to print
@@ -678,8 +687,14 @@ static inline void nbcon_reacquire_nobuf(struct nbcon_write_context *wctxt) { }
static inline bool nbcon_kdb_try_acquire(struct console *con,
struct nbcon_write_context *wctxt) { return false; }
static inline void nbcon_kdb_release(struct nbcon_write_context *wctxt) { }
+static inline
+bool nbcon_write_context_is_braille(struct nbcon_write_context *wctxt) { return false; }
static inline bool console_is_usable(struct console *con, short flags,
bool use_atomic) { return false; }
+static inline bool nbcon_braille_try_acquire(struct console *con,
+ struct nbcon_write_context *wctxt) { return false; }
+static inline void nbcon_braille_release(struct nbcon_write_context *wctxt) { }
+static inline bool nbcon_is_braille(struct console *con) { return false; }
#endif
extern int console_set_on_cmdline;
diff --git a/kernel/printk/nbcon.c b/kernel/printk/nbcon.c
index d17704fe93ae..fb1b37741952 100644
--- a/kernel/printk/nbcon.c
+++ b/kernel/printk/nbcon.c
@@ -1887,6 +1887,7 @@ bool nbcon_device_try_acquire(struct console *con)
memset(ctxt, 0, sizeof(*ctxt));
ctxt->console = con;
+ /* Keep in sync with nbcon_braille_try_acquire(). */
ctxt->prio = NBCON_PRIO_NORMAL;
if (!nbcon_context_try_acquire(ctxt, false))
@@ -2002,3 +2003,81 @@ void nbcon_kdb_release(struct nbcon_write_context *wctxt)
*/
__nbcon_atomic_flush_pending_con(ctxt->console, prb_next_reserve_seq(prb));
}
+
+/**
+ * nbcon_is_braille - Checks whether the nbcon write context is using Braille console
+ *
+ * @wctxt: checked nbcon write context
+ *
+ * Return: True when the write context is associated with a Braille console.
+ * Otherwise, return false.
+ *
+ * Context: Can be called in any context but only when Braille console is
+ * registered and the struct console could not disappear.
+ */
+bool nbcon_write_context_is_braille(struct nbcon_write_context *wctxt)
+{
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
+ struct console *con = ctxt->console;
+
+ return con && con->flags & CON_BRL;
+}
+EXPORT_SYMBOL_GPL(nbcon_write_context_is_braille);
+
+/**
+ * nbcon_braille_try_acquire - Try to acquire nbcon console for braille_write()
+ *
+ * @con: The nbcon console to acquire
+ * @wctxt: The nbcon write context to be used on success
+ *
+ * Context: braille_write() for emitting a single buffer on Braille console.
+ *
+ * Return: True if the console was acquired. False otherwise.
+ *
+ * Braille console is not registered as a proper printk consoles. Instead,
+ * it is integrated with the graphical virtual terminal.
+ *
+ * This function is going to synchronize the Braille write against other
+ * operations on the used serial port. The port can be used also for a user
+ * input but printk() won't emit the messages there directly. It means
+ * the other operations will get synchronized using nbcon_device_try_acquire().
+ */
+bool nbcon_braille_try_acquire(struct console *con,
+ struct nbcon_write_context *wctxt)
+{
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
+ bool success;
+
+ memset(ctxt, 0, sizeof(*ctxt));
+ ctxt->console = con;
+ /* Keep in sync with nbcon_device_try_acquire(). */
+ if (panic_on_this_cpu())
+ ctxt->prio = NBCON_PRIO_PANIC;
+ else
+ ctxt->prio = NBCON_PRIO_NORMAL;
+
+ success = nbcon_context_try_acquire(ctxt, false);
+ /*
+ * Try hard in panic, otherwise the Braille console would
+ * miss a text on the related VT.
+ */
+ if (panic_on_this_cpu() && !success) {
+ ctxt->allow_unsafe_takeover = true;
+ success = nbcon_context_try_acquire(ctxt, false);
+ }
+
+ return success;
+}
+
+/**
+ * nbcon_braille_release - Release the nbcon console
+ *
+ * @wctxt: The nbcon write context initialized by a successful
+ * nbcon_braille_try_acquire()
+ */
+void nbcon_braille_release(struct nbcon_write_context *wctxt)
+{
+ struct nbcon_context *ctxt = &ACCESS_PRIVATE(wctxt, ctxt);
+
+ nbcon_context_release(ctxt);
+}