Linux Serial subsystem development
 help / color / mirror / Atom feed
From: "Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>
To: John Ogness <john.ogness@linutronix.de>,
	 Andy Shevchenko <andy.shevchenko@gmail.com>
Cc: "Greg Kroah-Hartman" <gregkh@linuxfoundation.org>,
	"Jiri Slaby" <jirislaby@kernel.org>,
	"Andy Shevchenko" <andy.shevchenko@gmail.com>,
	LKML <linux-kernel@vger.kernel.org>,
	"Ilpo Järvinen" <ilpo.jarvinen@linux.intel.com>,
	"Thomas Gleixner" <tglx@kernel.org>,
	"Ingo Molnar" <mingo@kernel.org>, "Kees Cook" <kees@kernel.org>,
	"Osama Abdelkader" <osama.abdelkader@gmail.com>,
	"Randy Dunlap" <rdunlap@infradead.org>,
	"Joseph Tilahun" <jtilahun@astranis.com>,
	"Krzysztof Kozlowski" <krzysztof.kozlowski@oss.qualcomm.com>,
	"Dr. David Alan Gilbert" <linux@treblig.org>,
	linux-serial <linux-serial@vger.kernel.org>
Subject: Re: [PATCH tty v5 3/3] serial: 8250: Add support for console flow control
Date: Mon, 11 May 2026 19:07:51 +0300 (EEST)	[thread overview]
Message-ID: <f9f408c5-72f5-4be8-7471-e9aee2935a5b@linux.intel.com> (raw)
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.


  reply	other threads:[~2026-05-11 16:08 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-05-11 15:26 [PATCH tty v5 0/3] 8250: Add console flow control John Ogness
2026-05-11 15:27 ` [PATCH tty v5 1/3] serial: 8250: Set cons_flow on port registration John Ogness
2026-05-11 15:27 ` [PATCH tty v5 2/3] serial: 8250: Check LSR timeout on console flow control John Ogness
2026-05-11 15:27 ` [PATCH tty v5 3/3] serial: 8250: Add support for " John Ogness
2026-05-11 16:07   ` Ilpo Järvinen [this message]
2026-05-12  9:29     ` John Ogness

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=f9f408c5-72f5-4be8-7471-e9aee2935a5b@linux.intel.com \
    --to=ilpo.jarvinen@linux.intel.com \
    --cc=andy.shevchenko@gmail.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=jirislaby@kernel.org \
    --cc=john.ogness@linutronix.de \
    --cc=jtilahun@astranis.com \
    --cc=kees@kernel.org \
    --cc=krzysztof.kozlowski@oss.qualcomm.com \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-serial@vger.kernel.org \
    --cc=linux@treblig.org \
    --cc=mingo@kernel.org \
    --cc=osama.abdelkader@gmail.com \
    --cc=rdunlap@infradead.org \
    --cc=tglx@kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox