* Re: [PATCH tty v5 3/3] serial: 8250: Add support for console flow control
From: Ilpo Järvinen @ 2026-05-11 16:07 UTC (permalink / raw)
To: John Ogness, Andy Shevchenko
Cc: Greg Kroah-Hartman, Jiri Slaby, Andy Shevchenko, LKML,
Ilpo Järvinen, Thomas Gleixner, Ingo Molnar, Kees Cook,
Osama Abdelkader, Randy Dunlap, Joseph Tilahun,
Krzysztof Kozlowski, Dr. David Alan Gilbert, linux-serial
In-Reply-To: <20260511152706.151498-4-john.ogness@linutronix.de>
On Mon, 11 May 2026, John Ogness wrote:
> The kernel documentation specifies that the console option 'r' can
> be used to enable hardware flow control for console writes. The 8250
> driver does include code for hardware flow control on the console if
> cons_flow is set, but there is no code path that actually sets this.
> However, that is not the only issue. The problems are:
>
> 1. Specifying the console option 'r' does not lead to cons_flow being
> set.
>
> 2. Even if cons_flow would be set, serial8250_register_8250_port()
> clears it.
>
> 3. When the console option 'r' is specified, uart_set_options()
> attempts to initialize the port for CRTSCTS. However, afterwards
> it does not set the UPSTAT_CTS_ENABLE status bit and therefore on
> boot, uart_cts_enabled() is always false. This policy bit is
> important for console drivers as a criteria if they may poll CTS.
>
> 4. Even though uart_set_options() attempts to initialize the port
> for CRTSCTS, the 8250 set_termios() callback does not enable the
> RTS signal (TIOCM_RTS) and thus the hardware is not properly
> initialized for CTS polling.
>
> 5. Even if modem control was properly setup for CTS polling
> (TIOCM_RTS), uart_configure_port() clears TIOCM_RTS, thus
> breaking CTS polling.
>
> 6. wait_for_xmitr() and serial8250_console_write() use cons_flow
> to decide if CTS polling should occur. However, the condition
> should also include a check that it is not in RS485 mode and
> CRTSCTS is actually enabled in the hardware.
>
> Address all these issues as conservatively as possible by gating them
> behind checks focussed on the user specifying console hardware flow
> control support and the hardware being configured for CTS polling
> at the time of the write to the UART.
>
> Since checking the UPSTAT_CTS_ENABLE status bit is a part of the new
> condition gate, these changes also support runtime termios updates to
> disable/enable CRTSCTS.
>
> Signed-off-by: John Ogness <john.ogness@linutronix.de>
> ---
> drivers/tty/serial/8250/8250_core.c | 6 +++++-
> drivers/tty/serial/8250/8250_port.c | 13 +++++++++++--
> drivers/tty/serial/serial_core.c | 21 ++++++++++++++++++++-
> include/linux/serial_core.h | 8 ++++++++
> 4 files changed, 44 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
> index b0275204e1167..1f03da85e3414 100644
> --- a/drivers/tty/serial/8250/8250_core.c
> +++ b/drivers/tty/serial/8250/8250_core.c
> @@ -693,6 +693,7 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
> int serial8250_register_8250_port(const struct uart_8250_port *up)
> {
> struct uart_8250_port *uart;
> + bool cons_flow;
> int ret;
>
> if (up->port.uartclk == 0)
> @@ -716,6 +717,9 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
> if (uart->port.type == PORT_8250_CIR)
> return -ENODEV;
>
> + /* Preserve specified console flow control. */
> + cons_flow = uart_cons_flow_enabled(&uart->port);
> +
> if (uart->port.dev)
> uart_remove_one_port(&serial8250_reg, &uart->port);
>
> @@ -746,7 +750,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
> uart->lsr_save_mask = up->lsr_save_mask;
> uart->dma = up->dma;
>
> - uart_set_cons_flow_enabled(&uart->port, uart_cons_flow_enabled(&up->port));
> + uart_set_cons_flow_enabled(&uart->port, uart_cons_flow_enabled(&up->port) | cons_flow);
>
> /* Take tx_loadsz from fifosize if it wasn't set separately */
> if (uart->port.fifosize && !uart->tx_loadsz)
> diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
> index fe2e0f1e66c21..ef245114105bc 100644
> --- a/drivers/tty/serial/8250/8250_port.c
> +++ b/drivers/tty/serial/8250/8250_port.c
> @@ -1991,7 +1991,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
> tx_ready = wait_for_lsr(up, bits);
>
> /* Wait up to 1s for flow control if necessary */
> - if (uart_cons_flow_enabled(&up->port)) {
> + if (uart_console_hwflow_active(&up->port)) {
> for (tmout = 1000000; tmout; tmout--) {
> unsigned int msr = serial_in(up, UART_MSR);
> up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
> @@ -2788,6 +2788,12 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
> serial8250_set_efr(port, termios);
> serial8250_set_divisor(port, baud, quot, frac);
> serial8250_set_fcr(port, termios);
> + /* Consoles manually poll CTS for hardware flow control. */
> + if (uart_console(port) &&
> + !(port->rs485.flags & SER_RS485_ENABLED)
> + && termios->c_cflag & CRTSCTS) {
> + port->mctrl |= TIOCM_RTS;
> + }
> serial8250_set_mctrl(port, port->mctrl);
> }
>
> @@ -3357,7 +3363,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
> * it regardless of the CTS state. Therefore, only use fifo
> * if we don't use control flow.
> */
> - !uart_cons_flow_enabled(&up->port);
> + !uart_console_hwflow_active(&up->port);
>
> if (likely(use_fifo))
> serial8250_console_fifo_write(up, s, count);
> @@ -3427,6 +3433,9 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
> if (ret)
> return ret;
>
> + /* Track user-specified console flow control. */
> + uart_set_cons_flow_enabled(port, flow == 'r');
> +
> if (port->dev)
> pm_runtime_get_sync(port->dev);
>
> diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
> index 89cebdd278410..840336f95c5f6 100644
> --- a/drivers/tty/serial/serial_core.c
> +++ b/drivers/tty/serial/serial_core.c
> @@ -2235,6 +2235,18 @@ uart_set_options(struct uart_port *port, struct console *co,
> port->mctrl |= TIOCM_DTR;
>
> port->ops->set_termios(port, &termios, &dummy);
> +
> + /*
> + * If console hardware flow control was specified and is supported,
> + * the related policy UPSTAT_CTS_ENABLE must be set to allow console
> + * drivers to identify if CTS should be used for polling.
> + */
> + if (flow == 'r' && (termios.c_cflag & CRTSCTS)) {
> + /* Synchronize @status RMW update against the console. */
> + guard(uart_port_lock_irqsave)(port);
> + port->status |= UPSTAT_CTS_ENABLE;
> + }
> +
> /*
> * Allow the setting of the UART parameters with a NULL console
> * too:
> @@ -2541,7 +2553,14 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
> * We probably don't need a spinlock around this, but
> */
> scoped_guard(uart_port_lock_irqsave, port) {
> - port->mctrl &= TIOCM_DTR;
> + unsigned int mask = TIOCM_DTR;
> +
> + /* Console hardware flow control polls CTS. */
> + if (uart_console_hwflow_active(port))
> + mask |= TIOCM_RTS;
> +
> + port->mctrl &= mask;
> +
> if (!(port->rs485.flags & SER_RS485_ENABLED))
> port->ops->set_mctrl(port, port->mctrl);
> }
> diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
> index 4f7bbdd900176..17fcff466e301 100644
> --- a/include/linux/serial_core.h
> +++ b/include/linux/serial_core.h
> @@ -1175,6 +1175,14 @@ static inline bool uart_cons_flow_enabled(const struct uart_port *uport)
> return uport->cons_flow;
> }
>
> +static inline bool uart_console_hwflow_active(struct uart_port *uport)
> +{
> + return uart_console(uport) &&
> + !(uport->rs485.flags & SER_RS485_ENABLED) &&
> + uart_cons_flow_enabled(uport) &&
> + uart_cts_enabled(uport);
> +}
> +
> /*
> * The following are helper functions for the low level drivers.
> */
>
Hi,
Did you miss Andy's comments or choose to not act on them?
--
i.
^ permalink raw reply
* [PATCH] tty: serial: atmel: Ignore chars when CREAD is cleared
From: Rakesh Alasyam @ 2026-05-11 15:56 UTC (permalink / raw)
To: gregkh
Cc: richard.genoud, jirislaby, nicolas.ferre, alexandre.belloni,
claudiu.beznea, linux-serial, linux-kernel, linux-arm-kernel,
Rakesh Alasyam
In-Reply-To: <2026051106-obliged-dismount-d85f@gregkh>
Ignore received characters when CREAD is cleared by adding RXRDY
to ignore_status_mask.
This replaces an existing TODO in the driver.
Tested on hardware.
Signed-off-by: Rakesh Alasyam <alasyamrakesh77@gmail.com>
---
v2:
- Add blank line before comment
- Tested on hardware
---
drivers/tty/serial/atmel_serial.c | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
index 5d8c1cfc1c60..5c756dc904b0 100644
--- a/drivers/tty/serial/atmel_serial.c
+++ b/drivers/tty/serial/atmel_serial.c
@@ -2184,7 +2184,8 @@ static void atmel_set_termios(struct uart_port *port,
if (termios->c_iflag & IGNPAR)
port->ignore_status_mask |= ATMEL_US_OVRE;
}
- /* TODO: Ignore all characters if CREAD is set.*/
+ if (!(termios->c_cflag & CREAD))
+ port->ignore_status_mask |= ATMEL_US_RXRDY;
/* update the per-port timeout */
uart_update_timeout(port, termios->c_cflag, baud);
--
2.43.0
^ permalink raw reply related
* [PATCH tty v5 3/3] serial: 8250: Add support for console flow control
From: John Ogness @ 2026-05-11 15:27 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Andy Shevchenko, linux-kernel, Ilpo Järvinen,
Thomas Gleixner, Ingo Molnar, Kees Cook, Osama Abdelkader,
Randy Dunlap, Joseph Tilahun, Krzysztof Kozlowski,
Dr. David Alan Gilbert, linux-serial
In-Reply-To: <20260511152706.151498-1-john.ogness@linutronix.de>
The kernel documentation specifies that the console option 'r' can
be used to enable hardware flow control for console writes. The 8250
driver does include code for hardware flow control on the console if
cons_flow is set, but there is no code path that actually sets this.
However, that is not the only issue. The problems are:
1. Specifying the console option 'r' does not lead to cons_flow being
set.
2. Even if cons_flow would be set, serial8250_register_8250_port()
clears it.
3. When the console option 'r' is specified, uart_set_options()
attempts to initialize the port for CRTSCTS. However, afterwards
it does not set the UPSTAT_CTS_ENABLE status bit and therefore on
boot, uart_cts_enabled() is always false. This policy bit is
important for console drivers as a criteria if they may poll CTS.
4. Even though uart_set_options() attempts to initialize the port
for CRTSCTS, the 8250 set_termios() callback does not enable the
RTS signal (TIOCM_RTS) and thus the hardware is not properly
initialized for CTS polling.
5. Even if modem control was properly setup for CTS polling
(TIOCM_RTS), uart_configure_port() clears TIOCM_RTS, thus
breaking CTS polling.
6. wait_for_xmitr() and serial8250_console_write() use cons_flow
to decide if CTS polling should occur. However, the condition
should also include a check that it is not in RS485 mode and
CRTSCTS is actually enabled in the hardware.
Address all these issues as conservatively as possible by gating them
behind checks focussed on the user specifying console hardware flow
control support and the hardware being configured for CTS polling
at the time of the write to the UART.
Since checking the UPSTAT_CTS_ENABLE status bit is a part of the new
condition gate, these changes also support runtime termios updates to
disable/enable CRTSCTS.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
drivers/tty/serial/8250/8250_core.c | 6 +++++-
drivers/tty/serial/8250/8250_port.c | 13 +++++++++++--
drivers/tty/serial/serial_core.c | 21 ++++++++++++++++++++-
include/linux/serial_core.h | 8 ++++++++
4 files changed, 44 insertions(+), 4 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index b0275204e1167..1f03da85e3414 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -693,6 +693,7 @@ static void serial_8250_overrun_backoff_work(struct work_struct *work)
int serial8250_register_8250_port(const struct uart_8250_port *up)
{
struct uart_8250_port *uart;
+ bool cons_flow;
int ret;
if (up->port.uartclk == 0)
@@ -716,6 +717,9 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
if (uart->port.type == PORT_8250_CIR)
return -ENODEV;
+ /* Preserve specified console flow control. */
+ cons_flow = uart_cons_flow_enabled(&uart->port);
+
if (uart->port.dev)
uart_remove_one_port(&serial8250_reg, &uart->port);
@@ -746,7 +750,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
uart->lsr_save_mask = up->lsr_save_mask;
uart->dma = up->dma;
- uart_set_cons_flow_enabled(&uart->port, uart_cons_flow_enabled(&up->port));
+ uart_set_cons_flow_enabled(&uart->port, uart_cons_flow_enabled(&up->port) | cons_flow);
/* Take tx_loadsz from fifosize if it wasn't set separately */
if (uart->port.fifosize && !uart->tx_loadsz)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index fe2e0f1e66c21..ef245114105bc 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1991,7 +1991,7 @@ static void wait_for_xmitr(struct uart_8250_port *up, int bits)
tx_ready = wait_for_lsr(up, bits);
/* Wait up to 1s for flow control if necessary */
- if (uart_cons_flow_enabled(&up->port)) {
+ if (uart_console_hwflow_active(&up->port)) {
for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = serial_in(up, UART_MSR);
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
@@ -2788,6 +2788,12 @@ serial8250_do_set_termios(struct uart_port *port, struct ktermios *termios,
serial8250_set_efr(port, termios);
serial8250_set_divisor(port, baud, quot, frac);
serial8250_set_fcr(port, termios);
+ /* Consoles manually poll CTS for hardware flow control. */
+ if (uart_console(port) &&
+ !(port->rs485.flags & SER_RS485_ENABLED)
+ && termios->c_cflag & CRTSCTS) {
+ port->mctrl |= TIOCM_RTS;
+ }
serial8250_set_mctrl(port, port->mctrl);
}
@@ -3357,7 +3363,7 @@ void serial8250_console_write(struct uart_8250_port *up, const char *s,
* it regardless of the CTS state. Therefore, only use fifo
* if we don't use control flow.
*/
- !uart_cons_flow_enabled(&up->port);
+ !uart_console_hwflow_active(&up->port);
if (likely(use_fifo))
serial8250_console_fifo_write(up, s, count);
@@ -3427,6 +3433,9 @@ int serial8250_console_setup(struct uart_port *port, char *options, bool probe)
if (ret)
return ret;
+ /* Track user-specified console flow control. */
+ uart_set_cons_flow_enabled(port, flow == 'r');
+
if (port->dev)
pm_runtime_get_sync(port->dev);
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 89cebdd278410..840336f95c5f6 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -2235,6 +2235,18 @@ uart_set_options(struct uart_port *port, struct console *co,
port->mctrl |= TIOCM_DTR;
port->ops->set_termios(port, &termios, &dummy);
+
+ /*
+ * If console hardware flow control was specified and is supported,
+ * the related policy UPSTAT_CTS_ENABLE must be set to allow console
+ * drivers to identify if CTS should be used for polling.
+ */
+ if (flow == 'r' && (termios.c_cflag & CRTSCTS)) {
+ /* Synchronize @status RMW update against the console. */
+ guard(uart_port_lock_irqsave)(port);
+ port->status |= UPSTAT_CTS_ENABLE;
+ }
+
/*
* Allow the setting of the UART parameters with a NULL console
* too:
@@ -2541,7 +2553,14 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
* We probably don't need a spinlock around this, but
*/
scoped_guard(uart_port_lock_irqsave, port) {
- port->mctrl &= TIOCM_DTR;
+ unsigned int mask = TIOCM_DTR;
+
+ /* Console hardware flow control polls CTS. */
+ if (uart_console_hwflow_active(port))
+ mask |= TIOCM_RTS;
+
+ port->mctrl &= mask;
+
if (!(port->rs485.flags & SER_RS485_ENABLED))
port->ops->set_mctrl(port, port->mctrl);
}
diff --git a/include/linux/serial_core.h b/include/linux/serial_core.h
index 4f7bbdd900176..17fcff466e301 100644
--- a/include/linux/serial_core.h
+++ b/include/linux/serial_core.h
@@ -1175,6 +1175,14 @@ static inline bool uart_cons_flow_enabled(const struct uart_port *uport)
return uport->cons_flow;
}
+static inline bool uart_console_hwflow_active(struct uart_port *uport)
+{
+ return uart_console(uport) &&
+ !(uport->rs485.flags & SER_RS485_ENABLED) &&
+ uart_cons_flow_enabled(uport) &&
+ uart_cts_enabled(uport);
+}
+
/*
* The following are helper functions for the low level drivers.
*/
--
2.47.3
^ permalink raw reply related
* [PATCH tty v5 2/3] serial: 8250: Check LSR timeout on console flow control
From: John Ogness @ 2026-05-11 15:27 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Andy Shevchenko, linux-kernel, Ilpo Järvinen,
Andy Shevchenko, linux-serial
In-Reply-To: <20260511152706.151498-1-john.ogness@linutronix.de>
wait_for_xmitr() calls wait_for_lsr() to wait for the transmission
registers to be empty. wait_for_lsr() can timeout after a reasonable
amount of time.
When console flow control is active, wait_for_xmitr() additionally
polls CTS, waiting for the peer to signal that it is ready to receive
more data.
If hardware flow control is enabled (auto CTS) and the peer deasserts
CTS, wait_for_lsr() will timeout. If additionally console flow
control is active and while polling CTS the peer asserts CTS, the
console will assume it can immediately transmit, even though the
transmission registers may not be empty. This can lead to data loss.
Avoid this problem by performing an extra wait_for_lsr() upon CTS
assertion if wait_for_lsr() previously timed out.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
drivers/tty/serial/8250/8250_port.c | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index e4e6a53ebea39..fe2e0f1e66c21 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -1986,16 +1986,20 @@ static bool wait_for_lsr(struct uart_8250_port *up, int bits)
static void wait_for_xmitr(struct uart_8250_port *up, int bits)
{
unsigned int tmout;
+ bool tx_ready;
- wait_for_lsr(up, bits);
+ tx_ready = wait_for_lsr(up, bits);
/* Wait up to 1s for flow control if necessary */
if (uart_cons_flow_enabled(&up->port)) {
for (tmout = 1000000; tmout; tmout--) {
unsigned int msr = serial_in(up, UART_MSR);
up->msr_saved_flags |= msr & MSR_SAVE_FLAGS;
- if (msr & UART_MSR_CTS)
+ if (msr & UART_MSR_CTS) {
+ if (!tx_ready)
+ wait_for_lsr(up, bits);
break;
+ }
udelay(1);
touch_nmi_watchdog();
}
--
2.47.3
^ permalink raw reply related
* [PATCH tty v5 1/3] serial: 8250: Set cons_flow on port registration
From: John Ogness @ 2026-05-11 15:27 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Andy Shevchenko, linux-kernel, Ilpo Järvinen, Xin Zhao,
Kees Cook, Osama Abdelkader, linux-serial
In-Reply-To: <20260511152706.151498-1-john.ogness@linutronix.de>
Since console flow control policy is no longer part of uart_port.flags,
explicitly set the policy for the port.
Signed-off-by: John Ogness <john.ogness@linutronix.de>
---
drivers/tty/serial/8250/8250_core.c | 2 ++
1 file changed, 2 insertions(+)
diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
index a428e88938eb7..b0275204e1167 100644
--- a/drivers/tty/serial/8250/8250_core.c
+++ b/drivers/tty/serial/8250/8250_core.c
@@ -746,6 +746,8 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
uart->lsr_save_mask = up->lsr_save_mask;
uart->dma = up->dma;
+ uart_set_cons_flow_enabled(&uart->port, uart_cons_flow_enabled(&up->port));
+
/* Take tx_loadsz from fifosize if it wasn't set separately */
if (uart->port.fifosize && !uart->tx_loadsz)
uart->tx_loadsz = uart->port.fifosize;
--
2.47.3
^ permalink raw reply related
* [PATCH tty v5 0/3] 8250: Add console flow control
From: John Ogness @ 2026-05-11 15:26 UTC (permalink / raw)
To: Greg Kroah-Hartman, Jiri Slaby
Cc: Andy Shevchenko, linux-kernel, Ilpo Järvinen, Xin Zhao,
Kees Cook, Osama Abdelkader, linux-serial, Andy Shevchenko,
Thomas Gleixner, Ingo Molnar, Randy Dunlap, Joseph Tilahun,
Krzysztof Kozlowski, Dr. David Alan Gilbert
Hi,
As requested by Greg [0], this is a resend of the last 3 patches from
v4 of a series to implement console flow control for the 8250 serial
driver. v4 is here [1] (including all the details about the entirety
of the series).
John Ogness
[0] https://lore.kernel.org/lkml/2026051134-revisable-sherry-e5b5@gregkh
[1] https://lore.kernel.org/lkml/20260506121606.5805-1-john.ogness@linutronix.de
John Ogness (3):
serial: 8250: Set cons_flow on port registration
serial: 8250: Check LSR timeout on console flow control
serial: 8250: Add support for console flow control
drivers/tty/serial/8250/8250_core.c | 6 ++++++
drivers/tty/serial/8250/8250_port.c | 21 +++++++++++++++++----
drivers/tty/serial/serial_core.c | 21 ++++++++++++++++++++-
include/linux/serial_core.h | 8 ++++++++
4 files changed, 51 insertions(+), 5 deletions(-)
base-commit: 4a9a0b1a82a8b23eb68032dd19b120e82cd67004
--
2.47.3
^ permalink raw reply
* Re: [PATCH] tty: serial: qcom-geni: re-arm RX DMA on spurious zero-length interrupt
From: Greg KH @ 2026-05-11 15:21 UTC (permalink / raw)
To: vyndiktus; +Cc: linux-serial, linux-kernel
In-Reply-To: <20260422-qcom-geni-uart-dma-rearm-v1-1-76d13aac7fdf@gmail.com>
On Wed, Apr 22, 2026 at 04:13:03PM +0000, Vynnie Von Diktus via B4 Relay wrote:
> From: Vynnie Von Diktus <vyndiktus@gmail.com>
>
> qcom_geni_serial_handle_rx_dma() returns early when SE_DMA_RX_LEN_IN
> reads as zero, interpreting it as a spurious interrupt. The early return
> skips geni_se_rx_dma_prep(), leaving the RX DMA descriptor permanently
> unarmed. All subsequently received bytes are silently dropped until the
> port is closed and reopened.
>
> On cold boots, chip startup transients on the UART lines can produce a
> genuine spurious DMA interrupt with a zero-length count. The bug is
> invisible on warm reboots (the UART stays powered and stable, so no
> spurious interrupt fires), which makes it appear as an intermittent
> failure only on power-cycle reboots.
>
> Fix by restructuring the zero-length check to fall through to
> geni_se_rx_dma_prep() in all cases. Only the data processing
> (handle_rx_uart) is skipped when no bytes arrived.
>
> Tested on SM8150 (Snapdragon 855) with a WCN3990 BT UART — Bluetooth
> firmware download now succeeds on every cold boot without
> "Frame reassembly failed" errors.
>
> The same GENI serial IP block is used across SDM845, SM8150, SM8250,
> SM8350 and many other Snapdragon SoCs; the bug and fix are expected to
> apply to all of them.
>
> Signed-off-by: Vynnie Von Diktus <vyndiktus@gmail.com>
> ---
> drivers/tty/serial/qcom_geni_serial.c | 6 ++----
> 1 file changed, 2 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c
> index 69a632fef..3c950bdc0 100644
> --- a/drivers/tty/serial/qcom_geni_serial.c
> +++ b/drivers/tty/serial/qcom_geni_serial.c
> @@ -837,11 +837,9 @@ static void qcom_geni_serial_handle_rx_dma(struct uart_port *uport, bool drop)
> rx_in = readl(uport->membase + SE_DMA_RX_LEN_IN);
> if (!rx_in) {
> dev_warn(uport->dev, "serial engine reports 0 RX bytes in!\n");
> - return;
> - }
> -
> - if (!drop)
> + } else if (!drop) {
> handle_rx_uart(uport, rx_in, drop);
> + }
>
> ret = geni_se_rx_dma_prep(&port->se, port->rx_buf,
> DMA_RX_BUF_SIZE,
>
> ---
> base-commit: 4a8d8848356e9e4c41e22de9b1ef1507ea21734a
> change-id: 20260422-qcom-geni-uart-dma-rearm-a5df83e164ff
>
> Best regards,
> --
> Vynnie Von Diktus <vyndiktus@gmail.com>
Does not apply to the tty-next tree :(
^ permalink raw reply
* Re: [PATCH] serial: atmel: honor CREAD in atmel_set_termios
From: Greg KH @ 2026-05-11 15:17 UTC (permalink / raw)
To: Rakesh Alasyam
Cc: richard.genoud, jirislaby, nicolas.ferre, alexandre.belloni,
claudiu.beznea, linux-serial, linux-kernel, linux-arm-kernel
In-Reply-To: <20260501081317.15477-1-alasyamrakesh77@gmail.com>
On Fri, May 01, 2026 at 01:43:17PM +0530, Rakesh Alasyam wrote:
> Ignore received characters when CREAD is cleared by adding RXRDY
> to ignore_status_mask.
>
> This replaces an existing TODO in the driver.
>
> Signed-off-by: Rakesh Alasyam <alasyamrakesh77@gmail.com>
> ---
> drivers/tty/serial/atmel_serial.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/tty/serial/atmel_serial.c b/drivers/tty/serial/atmel_serial.c
> index 5d8c1cfc1c60..5b062d8ccabe 100644
> --- a/drivers/tty/serial/atmel_serial.c
> +++ b/drivers/tty/serial/atmel_serial.c
> @@ -2184,8 +2184,8 @@ static void atmel_set_termios(struct uart_port *port,
> if (termios->c_iflag & IGNPAR)
> port->ignore_status_mask |= ATMEL_US_OVRE;
> }
> - /* TODO: Ignore all characters if CREAD is set.*/
> -
> + if (!(termios->c_cflag & CREAD))
> + port->ignore_status_mask |= ATMEL_US_RXRDY;
> /* update the per-port timeout */
> uart_update_timeout(port, termios->c_cflag, baud);
>
> --
> 2.43.0
>
>
Cool, was this tested to work properly?
And a blank line is needed before the comment, right?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v2] serial: 8250: Clear CON_PRINTBUFFER on port re-registration
From: Greg KH @ 2026-05-11 15:16 UTC (permalink / raw)
To: Fushuai Wang
Cc: jirislaby, ilpo.jarvinen, osama.abdelkader, andy.shevchenko, kees,
linux-kernel, linux-serial, wangfushuai
In-Reply-To: <20260428090349.30047-1-fushuai.wang@linux.dev>
On Tue, Apr 28, 2026 at 05:03:49PM +0800, Fushuai Wang wrote:
> From: Fushuai Wang <wangfushuai@baidu.com>
>
> When two PnP devices map to the same physical port, the serial8250 driver
> removes and re-registers the console structure for the same port.
>
> During re-registration, the console structure still has CON_PRINTBUFFER set
> from the initial registration, which causes console_init_seq() to set
> console->seq to syslog_seq. This results in re-printing the entire
> system log buffer, which may lead to RCU stall on slow serial consoles.
>
> Clear CON_PRINTBUFFER when re-registering a port to prevent duplicate
> log printing.
>
> Fixes: 835d844d1a28 ("8250_pnp: do pnp probe before legacy probe")
> Signed-off-by: Fushuai Wang <wangfushuai@baidu.com>
> ---
> V1->V2: Add Fixes tag
> previous discussion: https://lore.kernel.org/all/20260416092917.27301-1-fushuai.wang@linux.dev/T/#u
>
> Please ignore previous email if you received it before. There is something wrong with my email client.
>
> drivers/tty/serial/8250/8250_core.c | 9 ++++++++-
> 1 file changed, 8 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/8250/8250_core.c b/drivers/tty/serial/8250/8250_core.c
> index a428e88938eb..01b14392d9f7 100644
> --- a/drivers/tty/serial/8250/8250_core.c
> +++ b/drivers/tty/serial/8250/8250_core.c
> @@ -694,6 +694,7 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
> {
> struct uart_8250_port *uart;
> int ret;
> + bool was_removed = false;
>
> if (up->port.uartclk == 0)
> return -EINVAL;
> @@ -716,8 +717,10 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
> if (uart->port.type == PORT_8250_CIR)
> return -ENODEV;
>
> - if (uart->port.dev)
> + if (uart->port.dev) {
> uart_remove_one_port(&serial8250_reg, &uart->port);
> + was_removed = true;
> + }
>
> uart->port.ctrl_id = up->port.ctrl_id;
> uart->port.port_id = up->port.port_id;
> @@ -819,6 +822,10 @@ int serial8250_register_8250_port(const struct uart_8250_port *up)
> &uart->capabilities);
>
> serial8250_apply_quirks(uart);
> +
> + if (was_removed && uart_console(&uart->port))
> + uart->port.cons->flags &= ~CON_PRINTBUFFER;
Why not set the flag up above when you remove the port? Why down here?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH] serial: altera_jtaguart: handle uart_add_one_port() failures
From: Greg Kroah-Hartman @ 2026-05-11 15:15 UTC (permalink / raw)
To: Myeonghun Pak
Cc: Tobias Klauser, Jiri Slaby, linux-serial, linux-kernel, Ijae Kim
In-Reply-To: <20260428064511.8934-1-mhun512@gmail.com>
On Tue, Apr 28, 2026 at 03:44:57PM +0900, Myeonghun Pak wrote:
> altera_jtaguart_probe() maps the register window before registering the
> UART port, but it ignores failures from uart_add_one_port(). If port
> registration fails, probe still returns success and the mapping remains
> live until a later remove path that is not part of probe failure cleanup.
>
> Return the uart_add_one_port() error and unmap the register window on
> that failure path.
>
> Fixes: 5bcd601049c6 ("serial: Add driver for the Altera JTAG UART")
> Co-developed-by: Ijae Kim <ae878000@gmail.com>
> Signed-off-by: Ijae Kim <ae878000@gmail.com>
> Signed-off-by: Myeonghun Pak <mhun512@gmail.com>
> ---
> drivers/tty/serial/altera_jtaguart.c | 8 +++++++-
> 1 file changed, 7 insertions(+), 1 deletion(-)
>
> diff --git a/drivers/tty/serial/altera_jtaguart.c b/drivers/tty/serial/altera_jtaguart.c
> index d47a62d1c9..15588b6dc3 100644
> --- a/drivers/tty/serial/altera_jtaguart.c
> +++ b/drivers/tty/serial/altera_jtaguart.c
> @@ -379,6 +379,7 @@ static int altera_jtaguart_probe(struct platform_device *pdev)
> struct resource *res_mem;
> int i = pdev->id;
> int irq;
> + int ret;
>
> /* -1 emphasizes that the platform must have one port, no .N suffix */
> if (i == -1)
> @@ -418,7 +419,12 @@ static int altera_jtaguart_probe(struct platform_device *pdev)
> port->flags = UPF_BOOT_AUTOCONF;
> port->dev = &pdev->dev;
>
> - uart_add_one_port(&altera_jtaguart_driver, port);
> + ret = uart_add_one_port(&altera_jtaguart_driver, port);
> + if (ret) {
> + iounmap(port->membase);
> + port->membase = NULL;
Why is membase being set to NULL, that should not be needed, right?
How was this tested?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH tty v4 3/6] serial: sh-sci: Avoid deprecated UPF_CONS_FLOW
From: Greg Kroah-Hartman @ 2026-05-11 15:00 UTC (permalink / raw)
To: John Ogness
Cc: Geert Uytterhoeven, Jiri Slaby, Andy Shevchenko, linux-kernel,
Biju Das, Lad Prabhakar, Thierry Bultel, linux-serial,
Linux-sh list
In-Reply-To: <87v7d08ztd.fsf@jogness.linutronix.de>
On Wed, May 06, 2026 at 02:59:02PM +0206, John Ogness wrote:
> Hi Geert,
>
> On 2026-05-06, Geert Uytterhoeven <geert@linux-m68k.org> wrote:
> >> --- a/drivers/tty/serial/sh-sci.c
> >> +++ b/drivers/tty/serial/sh-sci.c
> >> @@ -3369,9 +3369,12 @@ static int sci_init_single(struct platform_device *dev,
> >> }
> >>
> >> port->type = SCI_PUBLIC_PORT_ID(p->type);
> >> - port->flags = UPF_FIXED_PORT | UPF_BOOT_AUTOCONF | p->flags;
> >> + port->flags = UPF_FIXED_PORT | UPF_BOOT_AUTOCONF |
> >> + (p->flags & ~UPF_CONS_FLOW);
> >
> > This seems over-cautious to me.
> > The last setter of p->flags was removed in commit 37744feebc086908
> > ("sh: remove sh5 support") in v5.8. No platform data ever set the
> > UPF_CONS_FLOW flag before. I would rather remove plat_sci_port.flags
> > and this "| p->flags", so we don't have to care about UPF_CONS_FLOW
> > in this driver at all.
>
> If there is a v5, I will drop this patch. If v4 is acceptable, the
> maintainer can just drop this patch.
>
> I will leave the plat_sci_port.flags removal as an excercise for the sh
> folks.
Ah, this is what confused me. I've taken the first two patches here,
can you respin the rest on my branch and resend them?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH tty v4 0/6] 8250: Add console flow control
From: Greg Kroah-Hartman @ 2026-05-11 14:58 UTC (permalink / raw)
To: John Ogness
Cc: Jiri Slaby, Andy Shevchenko, linux-kernel, linux-serial,
Krzysztof Kozlowski, Alim Akhtar, David S. Miller,
Ilpo Järvinen, Andy Shevchenko, Thomas Fourier, Kees Cook,
linux-arm-kernel, linux-samsung-soc, sparclinux, Biju Das,
Geert Uytterhoeven, Lad Prabhakar, Thierry Bultel,
Osama Abdelkader, Ingo Molnar, Xin Zhao, Joseph Tilahun,
Krzysztof Kozlowski, Lukas Wunner, Dr. David Alan Gilbert
In-Reply-To: <20260506121606.5805-1-john.ogness@linutronix.de>
On Wed, May 06, 2026 at 02:21:55PM +0206, John Ogness wrote:
> Hi,
>
> This is v4 of a series to implement console flow control for the
> 8250 serial driver. v3 is here [0].
>
> The 8250 driver already has code in place to support console flow
> control. However, there is no way to activate it and it is
> incomplete. This series provides the necessary missing pieces while
> attempting to be as conservative as possible, so as not to introduce
> any side effects into the many 8250 variants or other non-8250 serial
> drivers.
This had some rejections in drivers/tty/serial/sh-sci.c, what
branch/tree did you make this against?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v7 0/4] rust: add basic serial device bus abstractions
From: Markus Probst @ 2026-05-11 14:54 UTC (permalink / raw)
To: Rob Herring
Cc: Greg Kroah-Hartman, Jiri Slaby, Miguel Ojeda, Gary Guo,
Björn Roy Baron, Benno Lossin, Andreas Hindborg, Alice Ryhl,
Trevor Gross, Danilo Krummrich, Kari Argillander,
Rafael J. Wysocki, Viresh Kumar, Boqun Feng, David Airlie,
Simona Vetter, linux-serial, linux-kernel, rust-for-linux,
linux-pm, driver-core, dri-devel
In-Reply-To: <20260430195858.GA1650658-robh@kernel.org>
[-- Attachment #1: Type: text/plain, Size: 1395 bytes --]
On Thu, 2026-04-30 at 14:58 -0500, Rob Herring wrote:
> On Wed, Apr 29, 2026 at 08:21:30PM +0200, Markus Probst wrote:
> > This patch series adds the serdev device bus rust abstraction into the
> > kernel.
> >
> > This abstraction will be used by a driver,
> > which targets the MCU devices in Synology devices.
> >
> > Kari Argillander also messaged me, stating that he wants to write a
> > watchdog driver with this abstraction (needing initial device data).
> >
> > @Rob: Are you willing to maintain these rust abstractions yourself,
> > as you are the expert on this subsystem, otherwise I would take care of
> > it with a "SERIAL DEVICE BUS [RUST]" section in the MAINTAINERS file. In
> > the second case, I assume you are going to pick those patches as-is into
> > your tree, after they have been reviewed?
>
> Well I can ignore the Rust part as much as I ignore the C serdev part...
> Honestly, I need to find someone else to maintain all of it as I don't
> really have the bandwidth. I don't think we should split it though.
I could maintain both C and Rust.
However my knowledge regarding the tty subsystem is very limited, so I
would need to heavily rely on kernel documentation.
Thanks
- Markus Probst
>
> And I don't have a tree for serdev. Greg picks up the serdev patches. If
> the Rust folks are fine with them, then I am.
>
> Rob
[-- Attachment #2: This is a digitally signed message part --]
[-- Type: application/pgp-signature, Size: 870 bytes --]
^ permalink raw reply
* Re: [PATCH] tty: n_gsm: fix memory leak in gsm_activate_mux
From: Greg KH @ 2026-05-11 14:44 UTC (permalink / raw)
To: Minu Jin
Cc: jirislaby, daniel.starke, linux-kernel, linux-serial,
syzbot+b5d1f455d385b2c7da3c
In-Reply-To: <20260422183321.596414-1-s9430939@naver.com>
On Thu, Apr 23, 2026 at 03:33:21AM +0900, Minu Jin wrote:
> syzbot reported a memory leak in gsm_activate_mux().
> The root cause is a missing cleanup path when gsm_register_devices()
> fails. In this case, the previously allocated DLCI 0
> and its associated kfifo remain allocated, leading to a memory leak.
>
> And gsm_dlci_alloc() does not check for already allocated DLCIs.
> Repeated calls to gsm_activate_mux() would overwrite the existing pointer
> in gsm->dlci[addr], causing the original memory to be lost.
>
> Fix this by:
> 1. Adding gsm_dlci_free() in the error path of gsm_activate_mux().
> 2. Adding a check in gsm_dlci_alloc() to return the existing DLCI
> if it is already allocated.
>
> Reported-by: syzbot+b5d1f455d385b2c7da3c@syzkaller.appspotmail.com
> Closes: https://syzkaller.appspot.com/bug?extid=b5d1f455d385b2c7da3c
> Tested-by: syzbot+b5d1f455d385b2c7da3c@syzkaller.appspotmail.com
> Fixes: 01aecd917114 ("tty: n_gsm: fix tty registration before control channel open")
> Signed-off-by: Minu Jin <s9430939@naver.com>
> ---
> drivers/tty/n_gsm.c | 11 +++++++++--
> 1 file changed, 9 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/tty/n_gsm.c b/drivers/tty/n_gsm.c
> index c13e050de83b..de3d30eac86e 100644
> --- a/drivers/tty/n_gsm.c
> +++ b/drivers/tty/n_gsm.c
> @@ -2645,7 +2645,12 @@ static int gsm_dlci_config(struct gsm_dlci *dlci, struct gsm_dlci_config *dc, in
>
> static struct gsm_dlci *gsm_dlci_alloc(struct gsm_mux *gsm, int addr)
> {
> - struct gsm_dlci *dlci = kzalloc_obj(struct gsm_dlci, GFP_ATOMIC);
> + struct gsm_dlci *dlci;
> +
> + if (gsm->dlci[addr])
> + return gsm->dlci[addr];
Why would you be allocating a device twice? Shouldn't that logic be
fixed instead?
> +
> + dlci = kzalloc_obj(struct gsm_dlci, GFP_ATOMIC);
> if (dlci == NULL)
> return NULL;
> spin_lock_init(&dlci->lock);
> @@ -3196,8 +3201,10 @@ static int gsm_activate_mux(struct gsm_mux *gsm)
> gsm->receive = gsm1_receive;
>
> ret = gsm_register_devices(gsm_tty_driver, gsm->num);
> - if (ret)
> + if (ret) {
> + gsm_dlci_free(&dlci->port);
> return ret;
> + }
How was this tested?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH v1 1/1] serial: 8250_fsl: Export fsl8250_handle_irq() conditionally
From: kernel test robot @ 2026-05-11 12:54 UTC (permalink / raw)
To: Andy Shevchenko, linux-serial, linux-kernel
Cc: oe-kbuild-all, Greg Kroah-Hartman
In-Reply-To: <20260504151259.483924-1-andriy.shevchenko@linux.intel.com>
Hi Andy,
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 linus/master v7.1-rc3 next-20260508]
[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/Andy-Shevchenko/serial-8250_fsl-Export-fsl8250_handle_irq-conditionally/20260511-115924
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20260504151259.483924-1-andriy.shevchenko%40linux.intel.com
patch subject: [PATCH v1 1/1] serial: 8250_fsl: Export fsl8250_handle_irq() conditionally
config: microblaze-defconfig (https://download.01.org/0day-ci/archive/20260511/202605112003.uLqRrYzE-lkp@intel.com/config)
compiler: microblaze-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260511/202605112003.uLqRrYzE-lkp@intel.com/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 <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605112003.uLqRrYzE-lkp@intel.com/
All errors (new ones prefixed by >>):
drivers/tty/serial/8250/8250_of.c: In function 'of_platform_serial_setup':
>> drivers/tty/serial/8250/8250_of.c:187:36: error: 'fsl8250_handle_irq' undeclared (first use in this function); did you mean 'serial8250_handle_irq'?
187 | port->handle_irq = fsl8250_handle_irq;
| ^~~~~~~~~~~~~~~~~~
| serial8250_handle_irq
drivers/tty/serial/8250/8250_of.c:187:36: note: each undeclared identifier is reported only once for each function it appears in
vim +187 drivers/tty/serial/8250/8250_of.c
32f6ec282fb0ddb drivers/tty/serial/8250/8250_of.c Bastien Curutchet 2024-04-05 83
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 84 /*
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 85 * Fill a struct uart_port for a given device node
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 86 */
9671f09921d93e7 drivers/tty/serial/of_serial.c Bill Pemberton 2012-11-19 87 static int of_platform_serial_setup(struct platform_device *ofdev,
058bc104f7ca5c8 drivers/tty/serial/8250/8250_of.c Lukas Wunner 2020-02-28 88 int type, struct uart_8250_port *up,
0bbeb3c3e84bc96 drivers/tty/serial/of_serial.c Murali Karicheri 2012-10-22 89 struct of_serial_info *info)
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 90 {
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 91 struct resource resource;
4678de73932f8f3 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2023-09-12 92 struct device *dev = &ofdev->dev;
4678de73932f8f3 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2023-09-12 93 struct device_node *np = dev->of_node;
058bc104f7ca5c8 drivers/tty/serial/8250/8250_of.c Lukas Wunner 2020-02-28 94 struct uart_port *port = &up->port;
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 95 u32 spd;
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 96 int ret;
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 97
d3210c8e88ee413 drivers/tty/serial/8250/8250_of.c jempty.liang 2025-11-17 98 memset(port, 0, sizeof(*port));
a2d23edaef9e022 drivers/tty/serial/8250/8250_of.c Franklin S Cooper Jr 2017-08-16 99
a2d23edaef9e022 drivers/tty/serial/8250/8250_of.c Franklin S Cooper Jr 2017-08-16 100 pm_runtime_enable(&ofdev->dev);
a2d23edaef9e022 drivers/tty/serial/8250/8250_of.c Franklin S Cooper Jr 2017-08-16 101 pm_runtime_get_sync(&ofdev->dev);
a2d23edaef9e022 drivers/tty/serial/8250/8250_of.c Franklin S Cooper Jr 2017-08-16 102
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 103 ret = of_address_to_resource(np, 0, &resource);
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 104 if (ret) {
4678de73932f8f3 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2023-09-12 105 dev_err_probe(dev, ret, "invalid address\n");
aef6b8631f9ddf2 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2023-09-19 106 goto err_pmruntime;
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 107 }
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 108
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 109 port->dev = &ofdev->dev;
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 110 port->flags = UPF_BOOT_AUTOCONF | UPF_FIXED_PORT | UPF_FIXED_TYPE;
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 111 spin_lock_init(&port->lock);
aa95947400edb57 drivers/tty/serial/8250/8250_of.c John Garry 2018-04-27 112
aa95947400edb57 drivers/tty/serial/8250/8250_of.c John Garry 2018-04-27 113 if (resource_type(&resource) == IORESOURCE_IO) {
aa95947400edb57 drivers/tty/serial/8250/8250_of.c John Garry 2018-04-27 114 port->iobase = resource.start;
aa95947400edb57 drivers/tty/serial/8250/8250_of.c John Garry 2018-04-27 115 } else {
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 116 port->mapbase = resource.start;
0787691230d88af drivers/tty/serial/of_serial.c Mans Rullgard 2015-03-08 117 port->mapsize = resource_size(&resource);
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 118 port->flags |= UPF_IOREMAP;
d06b1cf28297e27 drivers/tty/serial/8250/8250_of.c Robert Hancock 2022-01-12 119 }
d06b1cf28297e27 drivers/tty/serial/8250/8250_of.c Robert Hancock 2022-01-12 120
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 121 ret = uart_read_and_validate_port_properties(port);
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 122 if (ret)
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 123 goto err_pmruntime;
b912b5e2cfb35c0 drivers/serial/of_serial.c John Linn 2008-04-03 124
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 125 /* Get clk rate through clk driver if present */
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 126 if (!port->uartclk) {
81e4de4ba298d73 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-09 127 struct clk *bus_clk;
81e4de4ba298d73 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-09 128
81e4de4ba298d73 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-09 129 bus_clk = devm_clk_get_optional_enabled(dev, "bus");
81e4de4ba298d73 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-09 130 if (IS_ERR(bus_clk)) {
81e4de4ba298d73 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-09 131 ret = dev_err_probe(dev, PTR_ERR(bus_clk), "failed to get bus clock\n");
81e4de4ba298d73 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-09 132 goto err_pmruntime;
81e4de4ba298d73 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-09 133 }
81e4de4ba298d73 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-09 134
81e4de4ba298d73 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-09 135 /* If the bus clock is required, core clock must be named */
81e4de4ba298d73 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-09 136 info->clk = devm_clk_get_enabled(dev, bus_clk ? "core" : NULL);
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 137 if (IS_ERR(info->clk)) {
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 138 ret = dev_err_probe(dev, PTR_ERR(info->clk), "failed to get clock\n");
aef6b8631f9ddf2 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2023-09-19 139 goto err_pmruntime;
7423734e19e7e0a drivers/tty/serial/of_serial.c Jamie Iles 2011-06-27 140 }
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 141
926040da6064233 drivers/tty/serial/8250/8250_of.c Alex Elder 2025-04-11 142 info->bus_clk = bus_clk;
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 143 port->uartclk = clk_get_rate(info->clk);
7423734e19e7e0a drivers/tty/serial/of_serial.c Jamie Iles 2011-06-27 144 }
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 145 /* If current-speed was set, then try not to change it. */
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 146 if (of_property_read_u32(np, "current-speed", &spd) == 0)
1117a6fdc7c14d6 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-03-04 147 port->custom_divisor = port->uartclk / (16 * spd);
aa95947400edb57 drivers/tty/serial/8250/8250_of.c John Garry 2018-04-27 148
f4817843e39ce78 drivers/tty/serial/8250/8250_of.c Lubomir Rintel 2019-02-24 149 /* Compatibility with the deprecated pxa driver and 8250_pxa drivers. */
f4817843e39ce78 drivers/tty/serial/8250/8250_of.c Lubomir Rintel 2019-02-24 150 if (of_device_is_compatible(np, "mrvl,mmp-uart"))
f4817843e39ce78 drivers/tty/serial/8250/8250_of.c Lubomir Rintel 2019-02-24 151 port->regshift = 2;
f4817843e39ce78 drivers/tty/serial/8250/8250_of.c Lubomir Rintel 2019-02-24 152
e2860e1f62f2e87 drivers/tty/serial/8250/8250_of.c Joel Stanley 2017-05-29 153 info->rst = devm_reset_control_get_optional_shared(&ofdev->dev, NULL);
b9820a31691b771 drivers/tty/serial/8250/8250_of.c Masahiro Yamada 2017-12-27 154 if (IS_ERR(info->rst)) {
b9820a31691b771 drivers/tty/serial/8250/8250_of.c Masahiro Yamada 2017-12-27 155 ret = PTR_ERR(info->rst);
aef6b8631f9ddf2 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2023-09-19 156 goto err_pmruntime;
b9820a31691b771 drivers/tty/serial/8250/8250_of.c Masahiro Yamada 2017-12-27 157 }
b9820a31691b771 drivers/tty/serial/8250/8250_of.c Masahiro Yamada 2017-12-27 158
e2860e1f62f2e87 drivers/tty/serial/8250/8250_of.c Joel Stanley 2017-05-29 159 ret = reset_control_deassert(info->rst);
e2860e1f62f2e87 drivers/tty/serial/8250/8250_of.c Joel Stanley 2017-05-29 160 if (ret)
aef6b8631f9ddf2 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2023-09-19 161 goto err_pmruntime;
e2860e1f62f2e87 drivers/tty/serial/8250/8250_of.c Joel Stanley 2017-05-29 162
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 163 port->type = type;
283e096ffb7077c drivers/tty/serial/8250/8250_of.c Lukas Wunner 2020-02-28 164 port->rs485_config = serial8250_em485_config;
0139da50dc53f0c drivers/tty/serial/8250/8250_of.c Ilpo Järvinen 2022-07-04 165 port->rs485_supported = serial8250_em485_supported;
058bc104f7ca5c8 drivers/tty/serial/8250/8250_of.c Lukas Wunner 2020-02-28 166 up->rs485_start_tx = serial8250_em485_start_tx;
058bc104f7ca5c8 drivers/tty/serial/8250/8250_of.c Lukas Wunner 2020-02-28 167 up->rs485_stop_tx = serial8250_em485_stop_tx;
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 168
9b8777e3473e31b drivers/tty/serial/of_serial.c John Crispin 2014-10-16 169 switch (type) {
9b8777e3473e31b drivers/tty/serial/of_serial.c John Crispin 2014-10-16 170 case PORT_RT2880:
b334214ea08d941 drivers/tty/serial/8250/8250_of.c Ilpo Järvinen 2023-05-11 171 ret = rt288x_setup(port);
cd0eb354d441488 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-02-15 172 break;
cd0eb354d441488 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-02-15 173 case PORT_NPCM:
cd0eb354d441488 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-02-15 174 ret = npcm_setup(port);
cd0eb354d441488 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-02-15 175 break;
cd0eb354d441488 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-02-15 176 default:
cd0eb354d441488 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-02-15 177 /* Nothing to do */
cd0eb354d441488 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-02-15 178 ret = 0;
9b8777e3473e31b drivers/tty/serial/of_serial.c John Crispin 2014-10-16 179 break;
9b8777e3473e31b drivers/tty/serial/of_serial.c John Crispin 2014-10-16 180 }
cd0eb354d441488 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-02-15 181 if (ret)
cd0eb354d441488 drivers/tty/serial/8250/8250_of.c Andy Shevchenko 2024-02-15 182 goto err_pmruntime;
bf03f65b7967df5 drivers/tty/serial/of_serial.c Dan Williams 2012-04-10 183
d9f59caf94a92f7 drivers/tty/serial/8250/8250_of.c Uwe Kleine-König 2023-06-09 184 if (IS_REACHABLE(CONFIG_SERIAL_8250_FSL) &&
d43b54d269d27bd drivers/tty/serial/of_serial.c Scott Wood 2015-10-07 185 (of_device_is_compatible(np, "fsl,ns16550") ||
d68fefdd5b5f107 drivers/tty/serial/8250/8250_of.c Dmitry Safonov 2019-12-13 186 of_device_is_compatible(np, "fsl,16550-FIFO64"))) {
d43b54d269d27bd drivers/tty/serial/of_serial.c Scott Wood 2015-10-07 @187 port->handle_irq = fsl8250_handle_irq;
d68fefdd5b5f107 drivers/tty/serial/8250/8250_of.c Dmitry Safonov 2019-12-13 188 port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
d68fefdd5b5f107 drivers/tty/serial/8250/8250_of.c Dmitry Safonov 2019-12-13 189 }
d43b54d269d27bd drivers/tty/serial/of_serial.c Scott Wood 2015-10-07 190
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 191 return 0;
a2d23edaef9e022 drivers/tty/serial/8250/8250_of.c Franklin S Cooper Jr 2017-08-16 192 err_pmruntime:
a2d23edaef9e022 drivers/tty/serial/8250/8250_of.c Franklin S Cooper Jr 2017-08-16 193 pm_runtime_put_sync(&ofdev->dev);
a2d23edaef9e022 drivers/tty/serial/8250/8250_of.c Franklin S Cooper Jr 2017-08-16 194 pm_runtime_disable(&ofdev->dev);
0bbeb3c3e84bc96 drivers/tty/serial/of_serial.c Murali Karicheri 2012-10-22 195 return ret;
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 196 }
8d38a5b2fab1397 drivers/serial/of_serial.c Arnd Bergmann 2007-02-13 197
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH v1 1/1] serial: 8250_fsl: Export fsl8250_handle_irq() conditionally
From: kernel test robot @ 2026-05-11 12:32 UTC (permalink / raw)
To: Andy Shevchenko, linux-serial, linux-kernel
Cc: oe-kbuild-all, Greg Kroah-Hartman
In-Reply-To: <20260504151259.483924-1-andriy.shevchenko@linux.intel.com>
Hi Andy,
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 linus/master v7.1-rc3 next-20260508]
[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/Andy-Shevchenko/serial-8250_fsl-Export-fsl8250_handle_irq-conditionally/20260511-115924
base: https://git.kernel.org/pub/scm/linux/kernel/git/gregkh/tty.git tty-testing
patch link: https://lore.kernel.org/r/20260504151259.483924-1-andriy.shevchenko%40linux.intel.com
patch subject: [PATCH v1 1/1] serial: 8250_fsl: Export fsl8250_handle_irq() conditionally
config: powerpc-allmodconfig (https://download.01.org/0day-ci/archive/20260511/202605112047.Ie6qC0oT-lkp@intel.com/config)
compiler: powerpc64-linux-gcc (GCC) 15.2.0
reproduce (this is a W=1 build): (https://download.01.org/0day-ci/archive/20260511/202605112047.Ie6qC0oT-lkp@intel.com/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 <lkp@intel.com>
| Closes: https://lore.kernel.org/oe-kbuild-all/202605112047.Ie6qC0oT-lkp@intel.com/
All errors (new ones prefixed by >>):
arch/powerpc/kernel/legacy_serial.c: In function 'fixup_port_irq':
>> arch/powerpc/kernel/legacy_serial.c:514:44: error: 'fsl8250_handle_irq' undeclared (first use in this function); did you mean 'serial8250_handle_irq'?
514 | port->handle_irq = fsl8250_handle_irq;
| ^~~~~~~~~~~~~~~~~~
| serial8250_handle_irq
arch/powerpc/kernel/legacy_serial.c:514:44: note: each undeclared identifier is reported only once for each function it appears in
vim +514 arch/powerpc/kernel/legacy_serial.c
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 489
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 490 static void __init fixup_port_irq(int index,
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 491 struct device_node *np,
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 492 struct plat_serial8250_port *port)
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 493 {
0ebfff1491ef85 Benjamin Herrenschmidt 2006-07-03 494 unsigned int virq;
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 495
0ebfff1491ef85 Benjamin Herrenschmidt 2006-07-03 496 DBG("fixup_port_irq(%d)\n", index);
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 497
0ebfff1491ef85 Benjamin Herrenschmidt 2006-07-03 498 virq = irq_of_parse_and_map(np, 0);
ef24ba7091517d Michael Ellerman 2016-09-06 499 if (!virq && legacy_serial_infos[index].irq_check_parent) {
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 500 np = of_get_parent(np);
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 501 if (np == NULL)
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 502 return;
0ebfff1491ef85 Benjamin Herrenschmidt 2006-07-03 503 virq = irq_of_parse_and_map(np, 0);
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 504 of_node_put(np);
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 505 }
ef24ba7091517d Michael Ellerman 2016-09-06 506 if (!virq)
0ebfff1491ef85 Benjamin Herrenschmidt 2006-07-03 507 return;
0ebfff1491ef85 Benjamin Herrenschmidt 2006-07-03 508
0ebfff1491ef85 Benjamin Herrenschmidt 2006-07-03 509 port->irq = virq;
9deaa53ac7fa37 Paul Gortmaker 2011-12-04 510
66eff0ef528b6d Uwe Kleine-König 2023-06-05 511 if (IS_ENABLED(CONFIG_SERIAL_8250) &&
66eff0ef528b6d Uwe Kleine-König 2023-06-05 512 of_device_is_compatible(np, "fsl,ns16550")) {
1eea99c04555e5 Uwe Kleine-König 2023-06-09 513 if (IS_REACHABLE(CONFIG_SERIAL_8250_FSL)) {
9deaa53ac7fa37 Paul Gortmaker 2011-12-04 @514 port->handle_irq = fsl8250_handle_irq;
d68fefdd5b5f10 Dmitry Safonov 2019-12-13 515 port->has_sysrq = IS_ENABLED(CONFIG_SERIAL_8250_CONSOLE);
66eff0ef528b6d Uwe Kleine-König 2023-06-05 516 } else {
66eff0ef528b6d Uwe Kleine-König 2023-06-05 517 pr_warn_once("Not activating Freescale specific workaround for device %pOFP\n",
66eff0ef528b6d Uwe Kleine-König 2023-06-05 518 np);
66eff0ef528b6d Uwe Kleine-König 2023-06-05 519 }
d68fefdd5b5f10 Dmitry Safonov 2019-12-13 520 }
0ebfff1491ef85 Benjamin Herrenschmidt 2006-07-03 521 }
463ce0e103f419 Benjamin Herrenschmidt 2005-11-23 522
--
0-DAY CI Kernel Test Service
https://github.com/intel/lkp-tests/wiki
^ permalink raw reply
* Re: [PATCH 6.12.y 0/8] serial: 8250_dw: backport BUSY deassert series
From: Ilpo Järvinen @ 2026-05-11 10:26 UTC (permalink / raw)
To: Ionut Nechita (Wind River)
Cc: Greg Kroah-Hartman, Andy Shevchenko, linux-serial
In-Reply-To: <20260510134011.618215-1-ionut.nechita@windriver.com>
[-- Attachment #1: Type: text/plain, Size: 6427 bytes --]
On Sun, 10 May 2026, Ionut Nechita (Wind River) wrote:
> From: Ionut Nechita <ionut.nechita@windriver.com>
>
> Hi Greg, Ilpo,
>
> This series backports the 8250_dw BUSY deassert fix to 6.12.y, per
> Ilpo's guidance from the request thread:
>
> https://lore.kernel.org/linux-serial/deb9499d-3245-7e38-9034-e533d4b5f512@linux.intel.com/
>
> Background: we ship 6.12 LTS as part of a certified production
> platform (StarlingX/Yocto) and are hitting the BUSY assertion issue
> on Intel DesignWare 8250 UARTs - LCR writes get silently ignored
> under Rx load, causing baud-rate / framing mismatches after
> set_termios. A major LTS bump is a multi-month re-qualification we
> can't justify for a single subsystem fix.
>
> The original mainline series is 7 patches by Ilpo (plus its
> dependencies). For 6.12.y, the resulting series here is 8 patches:
>
> Prerequisites (per Ilpo):
> 1/8 serial: 8250: use serial_port_in/out() helpers [dbd26a886e94]
> 2/8 serial: 8250_dw: Comment possible corner cases ... [bd8cad85561b]
>
> BUSY deassert series:
> 3/8 serial: 8250: Protect LCR write in shutdown [59a33d83bbe6]
> 4/8 serial: 8250_dw: Avoid unnecessary LCR writes [8002d6d6d0d8]
> 5/8 serial: 8250: Add serial8250_handle_irq_locked() [8324a54f604d]
> 6/8 serial: 8250_dw: Rework dw8250_handle_irq() ... [883c5a2bc934]
> 7/8 serial: 8250_dw: Rework IIR_NO_INT handling ... [73a4ed8f9efa]
> 8/8 serial: 8250_dw: Ensure BUSY is deasserted [a7b9ce39fbe4]
>
> Notes:
>
> - Patch 6/7 of the original mainline series,
> commit e0a368ae7953 ("serial: 8250: Add late synchronize_irq() to shutdown to handle DW UART BUSY"),
> is *already* in 6.12.y as
> commit 0bae1c670aa8 ("serial: 8250: Add late synchronize_irq() to shutdown to handle DW UART BUSY")
> (Ilpo, 2026-02-03), so it is not re-sent here. Functionally this
> means patches 3-8 above land on top of the existing
> late-synchronize_irq() fix; the conflict in patch 3 (LCR write
> placement around the late synchronize_irq) was resolved
> accordingly.
>
> - Ilpo's other suggested prerequisites are *not* included as prereqs:
> * commit b339809edda1 ("serial: 8250: use guard()s")
> * commit fc9ceb501e38 ("serial: 8250: sanitize uart_port::serial_{in,out}() types")
> * commit c213375e3283 ("serial: 8250_dw: Call dw8250_quirks() conditionally")
>
> Reasoning:
>
> * commit b339809edda1 ("serial: 8250: use guard()s") is a
> large refactor and only the shutdown hunk was needed;
> instead, patches 3, 5, 6, 7 here are adapted to use the
> existing explicit uart_port_lock_irqsave/unlock_irqrestore
> form rather than the cleanup-based guard() introduced by
> that commit;
Hi,
By doing this you had to add some gotos which makes code control flow
more complicated than it was in the original changes. From reviewer's
point of view, the code is more complicated without guard() than with
them.
guard() seems to be already used in 6.12 in general so I don't know why
you had to go replacing guard()s introduced in the original changes with
lock/unlock pairs.
FWIW, I scanned through the patches and didn't find anything that
interesting (other than that the approach chosen ignored my advice that
would have resulted in less changes/conflicts compared with the original
changes).
> * commit fc9ceb501e38 ("serial: 8250: sanitize
> uart_port::serial_{in,out}() types") only causes a trivial
> conflict in patch 8 in code that the BUSY change removes
> anyway (per Ilpo's note);
> * commit c213375e3283 ("serial: 8250_dw: Call dw8250_quirks()
> conditionally") only causes a conflict in patch 7 around
> the dw8250_setup_dma_filter() helper and the conditional
> p->handle_irq assignment, neither of which exist in 6.12.y
> and neither of which is needed for the BUSY fix.
>
> - Namespace export syntax: in 6.12.y both EXPORT_SYMBOL_NS_GPL()
> and MODULE_IMPORT_NS() apply __stringify(ns) to the namespace
> argument, so it must be a bare identifier. Mainline (where the
> upstream patches were written) accepts a string literal. Patches
> 5 and 8 here use the bare-identifier form (SERIAL_8250) instead
> of the upstream string form ("SERIAL_8250"); without this fix
> the .vmlinux.export.c link step fails with "expected ':' or ')'
> before 'SERIAL_8250'". This is noted in the [Ionut: ...] block
> of the affected patches.
>
> Each of patches 3, 5, 6, 7 and 8 carries an explicit
> "[Ionut: adapt to 6.12.y - ...]" note describing exactly what
> was changed relative to the upstream commit.
>
> Build:
> - Each patch builds individually on 6.12.87 to a complete vmlinux
> (bisect-safe), with CONFIG_SERIAL_8250=y, CONFIG_SERIAL_8250_DW=m
> on x86_64 defconfig.
>
> Testing plan:
> - We will test on Intel platforms with DW APB UART
> (snps,dw-apb-uart) running 6.12.57-rt / 6.12.87-rt (PREEMPT_RT)
> to confirm the original symptom (LCR writes silently ignored
> under Rx load -> baud / framing mismatch after set_termios) is
> gone. Will report Tested-by once cycles complete.
Testing with a reproduces is highly appreciated.
> Based on: linux-6.12.y at v6.12.87 (8bf2f55ef536).
>
> Andy Shevchenko (1):
> serial: 8250_dw: Comment possible corner cases in serial_out()
> implementation
>
> Ilpo Järvinen (6):
> serial: 8250: Protect LCR write in shutdown
> serial: 8250_dw: Avoid unnecessary LCR writes
> serial: 8250: Add serial8250_handle_irq_locked()
> serial: 8250_dw: Rework dw8250_handle_irq() locking and IIR handling
> serial: 8250_dw: Rework IIR_NO_INT handling to stop interrupt storm
> serial: 8250_dw: Ensure BUSY is deasserted
>
> Jiri Slaby (SUSE) (1):
> serial: 8250: use serial_port_in/out() helpers
>
> drivers/tty/serial/8250/8250.h | 25 +++
> drivers/tty/serial/8250/8250_dw.c | 298 +++++++++++++++++++++++-----
> drivers/tty/serial/8250/8250_fsl.c | 8 +-
> drivers/tty/serial/8250/8250_omap.c | 2 +-
> drivers/tty/serial/8250/8250_port.c | 66 +++---
> include/linux/serial_8250.h | 1 +
> 6 files changed, 319 insertions(+), 81 deletions(-)
>
>
--
i.
^ permalink raw reply
* Re: [PATCH v7 4/4] serial: 8250_dw: Use a fixed CPR value for UltraRISC DP1000 UART
From: Jia Wang @ 2026-05-11 9:50 UTC (permalink / raw)
To: Ilpo Järvinen
Cc: Jia Wang, Andy Shevchenko, Greg Kroah-Hartman, Jiri Slaby,
Paul Walmsley, Palmer Dabbelt, Albert Ou, Alexandre Ghiti,
Rob Herring, Krzysztof Kozlowski, Conor Dooley, LKML,
linux-serial, linux-riscv, devicetree
In-Reply-To: <66f322a7-70c5-13f9-3e97-6d0b18193f91@linux.intel.com>
On 2026-04-29 13:55 +0300, Ilpo Järvinen wrote:
> On Wed, 29 Apr 2026, Jia Wang wrote:
>
> > The UltraRISC DP1000 UART does not provide the standard CPR register used
> > by 8250_dw to discover port capabilities.
> >
> > Provide a fixed CPR value for the DP1000-specific compatible so the
> > driver can configure the port correctly.
> >
> > Signed-off-by: Jia Wang <wangjia@ultrarisc.com>
> > Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
> > ---
> > drivers/tty/serial/8250/8250_dw.c | 10 ++++++++++
> > 1 file changed, 10 insertions(+)
> >
> > diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
> > index 480f82d89856..55e40c10f46a 100644
> > --- a/drivers/tty/serial/8250/8250_dw.c
> > +++ b/drivers/tty/serial/8250/8250_dw.c
> > @@ -959,6 +959,15 @@ static const struct dw8250_platform_data dw8250_intc10ee = {
> > .quirks = DW_UART_QUIRK_IER_KICK,
> > };
> >
> > +static const struct dw8250_platform_data dw8250_ultrarisc_dp1000_data = {
> > + .usr_reg = DW_UART_USR,
> > + .cpr_value = FIELD_PREP_CONST(DW_UART_CPR_ABP_DATA_WIDTH, 2) |
> > + DW_UART_CPR_THRE_MODE |
> > + DW_UART_CPR_DMA_EXTRA |
> > + DW_UART_CPR_FIFO_MODE_FROM_SIZE(32),
> > + .quirks = DW_UART_QUIRK_CPR_VALUE,
>
> Thanks for all the effort you put to this series,
>
> Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
>
> Unrelated to this patch, I suppose we wouldn't strictly need to have
> DW_UART_QUIRK_CPR_VALUE in this driver as non-zero .cpr_value should be
> enough to decide if the CPR quirk should be used or not (if the code is
> adapted, obviously).
>
Thanks for the review and the tag, Ilpo.
The idea of dropping the quirk flag sounds reasonable to me. I'll keep
it in mind for a future cleanup patch once this series is merged.
> > +};
> > +
> > static const struct of_device_id dw8250_of_match[] = {
> > { .compatible = "snps,dw-apb-uart", .data = &dw8250_dw_apb },
> > { .compatible = "cavium,octeon-3860-uart", .data = &dw8250_octeon_3860_data },
> > @@ -966,6 +975,7 @@ static const struct of_device_id dw8250_of_match[] = {
> > { .compatible = "renesas,rzn1-uart", .data = &dw8250_renesas_rzn1_data },
> > { .compatible = "sophgo,sg2044-uart", .data = &dw8250_skip_set_rate_data },
> > { .compatible = "starfive,jh7100-uart", .data = &dw8250_skip_set_rate_data },
> > + { .compatible = "ultrarisc,dp1000-uart", .data = &dw8250_ultrarisc_dp1000_data },
> > { /* Sentinel */ }
> > };
> > MODULE_DEVICE_TABLE(of, dw8250_of_match);
> >
> >
>
> --
> i.
Best Regards,
Jia Wang
^ permalink raw reply
* Re: [PATCH v7 6/6] ARM: zte: defconfig: Add a zx29 defconfig file
From: Linus Walleij @ 2026-05-11 9:00 UTC (permalink / raw)
To: Stefan Dösinger
Cc: Jonathan Corbet, Shuah Khan, Russell King, Rob Herring,
Krzysztof Kozlowski, Conor Dooley, Arnd Bergmann,
Krzysztof Kozlowski, Alexandre Belloni, Drew Fustini,
Greg Kroah-Hartman, Jiri Slaby, linux-doc, linux-kernel,
linux-arm-kernel, devicetree, linux-serial
In-Reply-To: <23095518.EfDdHjke4D@silicon.doe.home>
On Fri, May 8, 2026 at 12:09 AM Stefan Dösinger
<stefandoesinger@gmail.com> wrote:
> So I read https://docs.kernel.org/process/maintainer-soc.html a few times. If
> I understand it correctly at this point "pull request" still means emails sent
> with p4, correct?
No it's the contents of an
git request-pull v7.1-rc1 git://..... tags/my-soc
put into a regular email and sent to soc@kernel.org.
I'm sorry if the terminology isn't always clear on what a pull request
actually is in the kernel world (as opposed to e.g. github). It's just
an email with request-pull contents and some cover letter.
> Or does someone create a git repository on git.kernel.org
> for me that I can use to send actual pull requests?
We can pull from wherever as long as you can sign your tag
with a GPG key that we can (in best cases) trust. We can also
just inspect the result of a pull request from a branch (no tag)
if we wanna, it just involves more inspection and trust.
> As I understand it, my 6 patches then go to the 4 corners of the kernel:
>
> Patch 1 (dt binding) to devicetree@vger.kernel.org
Nah as long as the DT maintianers ACK it (i.e. Reviewed-by) we
can merge that to the SoC tree.
> Patches 2 (platform), 5 (DTS) and 6 (defconfig) to soc@kernel.org, but not in
> one series but 3 independent ones
In an ideal world.
> Patches 3 and 4 (UART) to linux-serial@vger.kernel.org. I think this can and
> should be a series of both patches belonging together
Yups. Greg merges those.
Yours,
Linus Walleij
^ permalink raw reply
* Re: [PATCH] vt: keyboard: serialize KDGETLED with keyboard_tasklet
From: Cen Zhang @ 2026-05-10 17:01 UTC (permalink / raw)
To: Greg KH; +Cc: jirislaby, linux-kernel, linux-serial, baijiaju1990
In-Reply-To: <2026051039-snitch-attitude-a67d@gregkh>
Hi Greg,
> In the past decades of use, has anyone every noticed or complained about
> this consitency issue? If not, I would recommend not worrying about it :)
>
Understood, thanks. I will drop this patch.
Thank you for the review and guidance.
Best regards,
Cen
^ permalink raw reply
* Re: [PATCH] vt: keyboard: serialize KDGETLED with keyboard_tasklet
From: Greg KH @ 2026-05-10 16:55 UTC (permalink / raw)
To: Cen Zhang; +Cc: jirislaby, linux-kernel, linux-serial, baijiaju1990
In-Reply-To: <CAFRLqsUeat=rUj7aCSAku=A9NBNj3Wxd+xi8xzzBtRWqCxp18Q@mail.gmail.com>
On Mon, May 11, 2026 at 12:43:26AM +0800, Cen Zhang wrote:
> Hi Greg,
>
> > On Sun, May 10, 2026 at 06:22:xxPM +0200, Greg KH wrote:
>
> > Why is that an issue?
>
> Thanks, that's a fair point. The issue I was trying to describe is not
> that KDGETLED can race with a normal LED state transition and return
> either the old or the new value. That part is just the usual snapshot
> semantics, and the value can of course change immediately after the ioctl
> returns.
>
> The specific case I was concerned about is the VT-switch force-update
> path. vt_set_leds_compute_shiftstate() sets vt_switch and schedules
> keyboard_tasklet, and then kbd_bh() does:
>
> if (vt_switch) {
> ledstate = ~leds;
> vt_switch = false;
> }
>
> if (leds != ledstate) {
> kbd_propagate_led_state(ledstate, leds);
> ledstate = leds;
> }
>
> That first assignment is only an internal old-state sentinel to force LED
> propagation when switching VTs. It is not a committed LED state intended
> to be returned to userspace. Since KDGETLED currently returns
> ledstate & 0xff without quiescing the tasklet, it can expose that
> temporary complemented value. For example, if the real LED state is
> LED_NUM only, a read in that window can return the complemented low byte
> instead of 0x02.
>
> > stable for "what" exactly? This is a snapshot in time, be it before or
> > after it changes is not always going to really matter here, as it can
> > change right after you "enable" the tasklet, right?
>
> Yes, I agree. "stable snapshot" was too broad a description.
>
> By "stable" I only meant "not while kbd_bh() is in the middle of using
> that internal force-update value". tasklet_disable() would make KDGETLED
> observe either the old value before the tasklet runs, or the committed
> value after it finishes. It does not make the value stable after
> tasklet_enable(), and the changelog should not imply that.
>
> This is a small userspace-visible consistency issue, not a memory-safety
> problem. If this behavior is considered acceptable for KDGETLED, I can
> drop the patch; otherwise I can send a v2 with a narrower changelog.
In the past decades of use, has anyone every noticed or complained about
this consitency issue? If not, I would recommend not worrying about it :)
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH] vt: keyboard: serialize KDGETLED with keyboard_tasklet
From: Cen Zhang @ 2026-05-10 16:43 UTC (permalink / raw)
To: Greg KH; +Cc: jirislaby, linux-kernel, linux-serial, baijiaju1990
In-Reply-To: <2026051001-peso-enamel-2e62@gregkh>
Hi Greg,
> On Sun, May 10, 2026 at 06:22:xxPM +0200, Greg KH wrote:
> Why is that an issue?
Thanks, that's a fair point. The issue I was trying to describe is not
that KDGETLED can race with a normal LED state transition and return
either the old or the new value. That part is just the usual snapshot
semantics, and the value can of course change immediately after the ioctl
returns.
The specific case I was concerned about is the VT-switch force-update
path. vt_set_leds_compute_shiftstate() sets vt_switch and schedules
keyboard_tasklet, and then kbd_bh() does:
if (vt_switch) {
ledstate = ~leds;
vt_switch = false;
}
if (leds != ledstate) {
kbd_propagate_led_state(ledstate, leds);
ledstate = leds;
}
That first assignment is only an internal old-state sentinel to force LED
propagation when switching VTs. It is not a committed LED state intended
to be returned to userspace. Since KDGETLED currently returns
ledstate & 0xff without quiescing the tasklet, it can expose that
temporary complemented value. For example, if the real LED state is
LED_NUM only, a read in that window can return the complemented low byte
instead of 0x02.
> stable for "what" exactly? This is a snapshot in time, be it before or
> after it changes is not always going to really matter here, as it can
> change right after you "enable" the tasklet, right?
Yes, I agree. "stable snapshot" was too broad a description.
By "stable" I only meant "not while kbd_bh() is in the middle of using
that internal force-update value". tasklet_disable() would make KDGETLED
observe either the old value before the tasklet runs, or the committed
value after it finishes. It does not make the value stable after
tasklet_enable(), and the changelog should not imply that.
This is a small userspace-visible consistency issue, not a memory-safety
problem. If this behavior is considered acceptable for KDGETLED, I can
drop the patch; otherwise I can send a v2 with a narrower changelog.
Best regards,
Cen
^ permalink raw reply
* Re: [PATCH] tty: n_tty: read termios under lock in poll
From: Greg KH @ 2026-05-10 16:23 UTC (permalink / raw)
To: Cen Zhang; +Cc: jirislaby, linux-kernel, linux-serial, baijiaju1990
In-Reply-To: <20260510025940.1884932-1-zzzccc427@gmail.com>
On Sun, May 10, 2026 at 10:59:40AM +0800, Cen Zhang wrote:
> n_tty_poll() uses input_available_p() to decide whether buffered input
> makes the tty readable. That helper reads termios state through
> L_EXTPROC(), VMIN, and VTIME, but the poll path does not hold the read
> side of tty->termios_rwsem.
>
> tty_set_termios() updates tty->termios under the write side of the same
> semaphore, including c_lflag and c_cc[]. n_tty_read() already takes the
> read side before reading the same termios fields and before calling
> input_available_p(). Protect the poll-side readiness checks the same way
> so poll observes a coherent termios state when deciding whether to report
> readable input.
But why does that matter? If it changes right after you grab/release
the lock, the data will be stale as well. What userspace logic is
broken because of there not being a lock held here?
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH] vt: keyboard: serialize KDGETLED with keyboard_tasklet
From: Greg KH @ 2026-05-10 16:21 UTC (permalink / raw)
To: Cen Zhang; +Cc: jirislaby, linux-kernel, linux-serial, baijiaju1990
In-Reply-To: <20260510031348.1922157-1-zzzccc427@gmail.com>
On Sun, May 10, 2026 at 11:13:48AM +0800, Cen Zhang wrote:
> KDGETLED reaches getledstate() and samples ledstate without serializing
> against keyboard_tasklet.
>
> That is problematic because kbd_bh() temporarily stores ~leds into
> ledstate during a VT switch to force LED propagation before committing
> the final value. An unlocked KDGETLED can therefore observe that
> internal sentinel instead of the last committed LED state.
Why is that an issue?
> Other ledstate readers in this file already quiesce keyboard_tasklet
> before sampling the value. Do the same in getledstate() so the ioctl
> only returns a stable snapshot.
stable for "what" exactly? This is a snapshot in time, be it before or
after it changes is not always going to really matter here, as it can
change right after you "enable" the tasklet, right?
thanks,
greg k-h
^ permalink raw reply
* [PATCH 6.12.y 8/8] serial: 8250_dw: Ensure BUSY is deasserted
From: Ionut Nechita (Wind River) @ 2026-05-10 13:40 UTC (permalink / raw)
To: ilpo.jarvinen, gregkh
Cc: andriy.shevchenko, linux-serial, stable, qianfan Zhao,
Adriana Nicolae, Bandal, Shankar, Murthy, Shanth, Ionut Nechita
In-Reply-To: <20260510134011.618215-1-ionut.nechita@windriver.com>
From: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
commit a7b9ce39fbe4ae2919fe4f7ac16c293cb6632d30 upstream.
DW UART cannot write to LCR, DLL, and DLH while BUSY is asserted.
Existance of BUSY depends on uart_16550_compatible, if UART HW is
configured with it those registers can always be written.
There currently is dw8250_force_idle() which attempts to achieve
non-BUSY state by disabling FIFO, however, the solution is unreliable
when Rx keeps getting more and more characters.
Create a sequence of operations that ensures UART cannot keep BUSY
asserted indefinitely. The new sequence relies on enabling loopback mode
temporarily to prevent incoming Rx characters keeping UART BUSY.
Ensure no Tx in ongoing while the UART is switches into the loopback
mode (requires exporting serial8250_fifo_wait_for_lsr_thre() and adding
DMA Tx pause/resume functions).
According to tests performed by Adriana Nicolae <adriana@arista.com>,
simply disabling FIFO or clearing FIFOs only once does not always
ensure BUSY is deasserted but up to two tries may be needed. This could
be related to ongoing Rx of a character (a guess, not known for sure).
Therefore, retry FIFO clearing a few times (retry limit 4 is arbitrary
number but using, e.g., p->fifosize seems overly large). Tests
performed by others did not exhibit similar challenge but it does not
seem harmful to leave the FIFO clearing loop in place for all DW UARTs
with BUSY functionality.
Use the new dw8250_idle_enter/exit() to do divisor writes and LCR
writes. In case of plain LCR writes, opportunistically try to update
LCR first and only invoke dw8250_idle_enter() if the write did not
succeed (it has been observed that in practice most LCR writes do
succeed without complications).
This issue was first reported by qianfan Zhao who put lots of debugging
effort into understanding the solution space.
Fixes: c49436b657d0 ("serial: 8250_dw: Improve unwritable LCR workaround")
Fixes: 7d4008ebb1c9 ("tty: add a DesignWare 8250 driver")
Cc: stable <stable@kernel.org>
Reported-by: qianfan Zhao <qianfanguijin@163.com>
Link: https://lore.kernel.org/linux-serial/289bb78a-7509-1c5c-2923-a04ed3b6487d@163.com/
Reported-by: Adriana Nicolae <adriana@arista.com>
Link: https://lore.kernel.org/linux-serial/20250819182322.3451959-1-adriana@arista.com/
Reported-by: Bandal, Shankar <shankar.bandal@intel.com>
Tested-by: Bandal, Shankar <shankar.bandal@intel.com>
Tested-by: Murthy, Shanth <shanth.murthy@intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Link: https://patch.msgid.link/20260203171049.4353-8-ilpo.jarvinen@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
[Ionut: adapt to 6.12.y -
- trivial conflict in dw8250_check_lcr(): 6.12.y still has the
(int offset, int value) signature (the 'unsigned int offset,
u32 value' rework from fc9ceb501e38 is not backported), but
the conflicting tries/loop body is removed by this patch
anyway - took the new code as-is;
- use the bare-identifier form EXPORT_SYMBOL_NS_GPL(...,
SERIAL_8250) and MODULE_IMPORT_NS(SERIAL_8250) rather than
the string forms; in 6.12.y both macros stringify the
namespace argument via __stringify(ns), so it must be an
unquoted identifier.]
Signed-off-by: Ionut Nechita <ionut.nechita@windriver.com>
---
drivers/tty/serial/8250/8250.h | 25 +++++
drivers/tty/serial/8250/8250_dw.c | 165 ++++++++++++++++++++--------
drivers/tty/serial/8250/8250_port.c | 28 ++---
3 files changed, 162 insertions(+), 56 deletions(-)
diff --git a/drivers/tty/serial/8250/8250.h b/drivers/tty/serial/8250/8250.h
index 10a706fe4b24..1fe8222ffacd 100644
--- a/drivers/tty/serial/8250/8250.h
+++ b/drivers/tty/serial/8250/8250.h
@@ -184,7 +184,9 @@ static unsigned int __maybe_unused serial_icr_read(struct uart_8250_port *up,
return value;
}
+void serial8250_clear_fifos(struct uart_8250_port *p);
void serial8250_clear_and_reinit_fifos(struct uart_8250_port *p);
+void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count);
static inline u32 serial_dl_read(struct uart_8250_port *up)
{
@@ -402,6 +404,26 @@ static inline bool serial8250_tx_dma_running(struct uart_8250_port *p)
return dma && dma->tx_running;
}
+
+static inline void serial8250_tx_dma_pause(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+
+ if (!dma->tx_running)
+ return;
+
+ dmaengine_pause(dma->txchan);
+}
+
+static inline void serial8250_tx_dma_resume(struct uart_8250_port *p)
+{
+ struct uart_8250_dma *dma = p->dma;
+
+ if (!dma->tx_running)
+ return;
+
+ dmaengine_resume(dma->txchan);
+}
#else
static inline int serial8250_tx_dma(struct uart_8250_port *p)
{
@@ -423,6 +445,9 @@ static inline bool serial8250_tx_dma_running(struct uart_8250_port *p)
{
return false;
}
+
+static inline void serial8250_tx_dma_pause(struct uart_8250_port *p) { }
+static inline void serial8250_tx_dma_resume(struct uart_8250_port *p) { }
#endif
static inline int ns16550a_goto_highspeed(struct uart_8250_port *up)
diff --git a/drivers/tty/serial/8250/8250_dw.c b/drivers/tty/serial/8250/8250_dw.c
index 1650107d1cbc..630cc7227494 100644
--- a/drivers/tty/serial/8250/8250_dw.c
+++ b/drivers/tty/serial/8250/8250_dw.c
@@ -16,6 +16,7 @@
#include <linux/delay.h>
#include <linux/device.h>
#include <linux/io.h>
+#include <linux/lockdep.h>
#include <linux/mod_devicetable.h>
#include <linux/module.h>
#include <linux/notifier.h>
@@ -47,6 +48,8 @@
#define DW_UART_MCR_SIRE BIT(6)
+#define DW_UART_USR_BUSY BIT(0)
+
/* Renesas specific register fields */
#define RZN1_UART_xDMACR_DMA_EN BIT(0)
#define RZN1_UART_xDMACR_1_WORD_BURST (0 << 1)
@@ -89,6 +92,7 @@ struct dw8250_data {
unsigned int skip_autocfg:1;
unsigned int uart_16550_compatible:1;
+ unsigned int in_idle:1;
u8 no_int_count;
};
@@ -121,78 +125,151 @@ static inline int dw8250_modify_msr(struct uart_port *p, int offset, int value)
return value;
}
+static void dw8250_idle_exit(struct uart_port *p)
+{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ struct uart_8250_port *up = up_to_u8250p(p);
+
+ if (d->uart_16550_compatible)
+ return;
+
+ if (up->capabilities & UART_CAP_FIFO)
+ serial_port_out(p, UART_FCR, up->fcr);
+ serial_port_out(p, UART_MCR, up->mcr);
+ serial_port_out(p, UART_IER, up->ier);
+
+ /* DMA Rx is restarted by IRQ handler as needed. */
+ if (up->dma)
+ serial8250_tx_dma_resume(up);
+
+ d->in_idle = 0;
+}
+
/*
- * This function is being called as part of the uart_port::serial_out()
- * routine. Hence, it must not call serial_port_out() or serial_out()
- * against the modified registers here, i.e. LCR.
+ * Ensure BUSY is not asserted. If DW UART is configured with
+ * !uart_16550_compatible, the writes to LCR, DLL, and DLH fail while
+ * BUSY is asserted.
+ *
+ * Context: port's lock must be held
*/
-static void dw8250_force_idle(struct uart_port *p)
+static int dw8250_idle_enter(struct uart_port *p)
{
+ struct dw8250_data *d = to_dw8250_data(p->private_data);
+ unsigned int usr_reg = d->pdata ? d->pdata->usr_reg : DW_UART_USR;
struct uart_8250_port *up = up_to_u8250p(p);
- unsigned int lsr;
+ int retries;
+ u32 lsr;
- /*
- * The following call currently performs serial_out()
- * against the FCR register. Because it differs to LCR
- * there will be no infinite loop, but if it ever gets
- * modified, we might need a new custom version of it
- * that avoids infinite recursion.
- */
- serial8250_clear_and_reinit_fifos(up);
+ lockdep_assert_held_once(&p->lock);
+
+ if (d->uart_16550_compatible)
+ return 0;
+
+ d->in_idle = 1;
+
+ /* Prevent triggering interrupt from RBR filling */
+ serial_port_out(p, UART_IER, 0);
+
+ if (up->dma) {
+ serial8250_rx_dma_flush(up);
+ if (serial8250_tx_dma_running(up))
+ serial8250_tx_dma_pause(up);
+ }
/*
- * With PSLVERR_RESP_EN parameter set to 1, the device generates an
- * error response when an attempt to read an empty RBR with FIFO
- * enabled.
+ * Wait until Tx becomes empty + one extra frame time to ensure all bits
+ * have been sent on the wire.
+ *
+ * FIXME: frame_time delay is too long with very low baudrates.
*/
- if (up->fcr & UART_FCR_ENABLE_FIFO) {
- lsr = serial_port_in(p, UART_LSR);
- if (!(lsr & UART_LSR_DR))
- return;
+ serial8250_fifo_wait_for_lsr_thre(up, p->fifosize);
+ ndelay(p->frame_time);
+
+ serial_port_out(p, UART_MCR, up->mcr | UART_MCR_LOOP);
+
+ retries = 4; /* Arbitrary limit, 2 was always enough in tests */
+ do {
+ serial8250_clear_fifos(up);
+ if (!(serial_port_in(p, usr_reg) & DW_UART_USR_BUSY))
+ break;
+ /* FIXME: frame_time delay is too long with very low baudrates. */
+ ndelay(p->frame_time);
+ } while (--retries);
+
+ lsr = serial_lsr_in(up);
+ if (lsr & UART_LSR_DR) {
+ serial_port_in(p, UART_RX);
+ up->lsr_saved_flags = 0;
+ }
+
+ /* Now guaranteed to have BUSY deasserted? Just sanity check */
+ if (serial_port_in(p, usr_reg) & DW_UART_USR_BUSY) {
+ dw8250_idle_exit(p);
+ return -EBUSY;
}
- serial_port_in(p, UART_RX);
+ return 0;
+}
+
+static void dw8250_set_divisor(struct uart_port *p, unsigned int baud,
+ unsigned int quot, unsigned int quot_frac)
+{
+ struct uart_8250_port *up = up_to_u8250p(p);
+ int ret;
+
+ ret = dw8250_idle_enter(p);
+ if (ret < 0)
+ return;
+
+ serial_port_out(p, UART_LCR, up->lcr | UART_LCR_DLAB);
+ if (!(serial_port_in(p, UART_LCR) & UART_LCR_DLAB))
+ goto idle_failed;
+
+ serial_dl_write(up, quot);
+ serial_port_out(p, UART_LCR, up->lcr);
+
+idle_failed:
+ dw8250_idle_exit(p);
}
/*
* This function is being called as part of the uart_port::serial_out()
- * routine. Hence, it must not call serial_port_out() or serial_out()
- * against the modified registers here, i.e. LCR.
+ * routine. Hence, special care must be taken when serial_port_out() or
+ * serial_out() against the modified registers here, i.e. LCR (d->in_idle is
+ * used to break recursion loop).
*/
static void dw8250_check_lcr(struct uart_port *p, int offset, int value)
{
struct dw8250_data *d = to_dw8250_data(p->private_data);
- void __iomem *addr = p->membase + (offset << p->regshift);
- int tries = 1000;
+ u32 lcr;
+ int ret;
if (offset != UART_LCR || d->uart_16550_compatible)
return;
+ lcr = serial_port_in(p, UART_LCR);
+
/* Make sure LCR write wasn't ignored */
- while (tries--) {
- unsigned int lcr = serial_port_in(p, offset);
+ if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
+ return;
- if ((value & ~UART_LCR_SPAR) == (lcr & ~UART_LCR_SPAR))
- return;
+ if (d->in_idle)
+ goto write_err;
- dw8250_force_idle(p);
+ ret = dw8250_idle_enter(p);
+ if (ret < 0)
+ goto write_err;
-#ifdef CONFIG_64BIT
- if (p->type == PORT_OCTEON)
- __raw_writeq(value & 0xff, addr);
- else
-#endif
- if (p->iotype == UPIO_MEM32)
- writel(value, addr);
- else if (p->iotype == UPIO_MEM32BE)
- iowrite32be(value, addr);
- else
- writeb(value, addr);
- }
+ serial_port_out(p, UART_LCR, value);
+ dw8250_idle_exit(p);
+ return;
+
+write_err:
/*
* FIXME: this deadlocks if port->lock is already held
* dev_err(p->dev, "Couldn't set LCR to %d\n", value);
*/
+ return; /* Silences "label at the end of compound statement" */
}
/*
@@ -636,8 +713,10 @@ static int dw8250_probe(struct platform_device *pdev)
p->type = PORT_8250;
p->flags = UPF_FIXED_PORT;
p->dev = dev;
+
p->set_ldisc = dw8250_set_ldisc;
p->set_termios = dw8250_set_termios;
+ p->set_divisor = dw8250_set_divisor;
data = devm_kzalloc(dev, sizeof(*data), GFP_KERNEL);
if (!data)
@@ -929,7 +1008,7 @@ static struct platform_driver dw8250_platform_driver = {
module_platform_driver(dw8250_platform_driver);
-MODULE_IMPORT_NS("SERIAL_8250");
+MODULE_IMPORT_NS(SERIAL_8250);
MODULE_AUTHOR("Jamie Iles");
MODULE_LICENSE("GPL");
MODULE_DESCRIPTION("Synopsys DesignWare 8250 serial port driver");
diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c
index 1e6dca739eab..ce26d1649ca5 100644
--- a/drivers/tty/serial/8250/8250_port.c
+++ b/drivers/tty/serial/8250/8250_port.c
@@ -478,7 +478,7 @@ serial_port_out_sync(struct uart_port *p, int offset, int value)
/*
* FIFO support.
*/
-static void serial8250_clear_fifos(struct uart_8250_port *p)
+void serial8250_clear_fifos(struct uart_8250_port *p)
{
if (p->capabilities & UART_CAP_FIFO) {
serial_out(p, UART_FCR, UART_FCR_ENABLE_FIFO);
@@ -487,6 +487,7 @@ static void serial8250_clear_fifos(struct uart_8250_port *p)
serial_out(p, UART_FCR, 0);
}
}
+EXPORT_SYMBOL_NS_GPL(serial8250_clear_fifos, SERIAL_8250);
static enum hrtimer_restart serial8250_em485_handle_start_tx(struct hrtimer *t);
static enum hrtimer_restart serial8250_em485_handle_stop_tx(struct hrtimer *t);
@@ -3288,6 +3289,17 @@ void serial8250_set_defaults(struct uart_8250_port *up)
}
EXPORT_SYMBOL_GPL(serial8250_set_defaults);
+void serial8250_fifo_wait_for_lsr_thre(struct uart_8250_port *up, unsigned int count)
+{
+ unsigned int i;
+
+ for (i = 0; i < count; i++) {
+ if (wait_for_lsr(up, UART_LSR_THRE))
+ return;
+ }
+}
+EXPORT_SYMBOL_NS_GPL(serial8250_fifo_wait_for_lsr_thre, SERIAL_8250);
+
#ifdef CONFIG_SERIAL_8250_CONSOLE
static void serial8250_console_putchar(struct uart_port *port, unsigned char ch)
@@ -3324,16 +3336,6 @@ static void serial8250_console_restore(struct uart_8250_port *up)
serial8250_out_MCR(up, up->mcr | UART_MCR_DTR | UART_MCR_RTS);
}
-static void fifo_wait_for_lsr(struct uart_8250_port *up, unsigned int count)
-{
- unsigned int i;
-
- for (i = 0; i < count; i++) {
- if (wait_for_lsr(up, UART_LSR_THRE))
- return;
- }
-}
-
/*
* Print a string to the serial port using the device FIFO
*
@@ -3351,7 +3353,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
while (s != end) {
/* Allow timeout for each byte of a possibly full FIFO */
- fifo_wait_for_lsr(up, fifosize);
+ serial8250_fifo_wait_for_lsr_thre(up, fifosize);
for (i = 0; i < fifosize && s != end; ++i) {
if (*s == '\n' && !cr_sent) {
@@ -3369,7 +3371,7 @@ static void serial8250_console_fifo_write(struct uart_8250_port *up,
* Allow timeout for each byte written since the caller will only wait
* for UART_LSR_BOTH_EMPTY using the timeout of a single character
*/
- fifo_wait_for_lsr(up, tx_count);
+ serial8250_fifo_wait_for_lsr_thre(up, tx_count);
}
/*
--
2.54.0
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox