Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

serial: qcom-geni: Fix RTS behavior with flow control

When userspace enables flow control (CRTSCTS), the driver
deasserts RTS even when the receive buffer has space. This prevents the
peer device from transmitting, causing communication to stall.

The root cause is that the driver unconditionally uses manual RTS control
regardless of flow control mode. When CRTSCTS is set, the hardware should
automatically manage RTS based on buffer status, but the driver overrides
this by setting manual control.

Fix this by introducing port->manual_flow flag. In set_termios(), disable
manual flow when CRTSCTS is set. In set_mctrl(), only assert
SE_UART_MANUAL_RFR when manual_flow is active. Verified by enabling and
disabling hardware flow control with stty.

Signed-off-by: Anup Kulkarni <anup.kulkarni@oss.qualcomm.com>
Link: https://patch.msgid.link/20260310104155.339010-1-anup.kulkarni@oss.qualcomm.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Anup Kulkarni and committed by
Greg Kroah-Hartman
0b1837c0 74e0c9f0

+15 -4
+15 -4
drivers/tty/serial/qcom_geni_serial.c
··· 146 146 int wakeup_irq; 147 147 bool rx_tx_swap; 148 148 bool cts_rts_swap; 149 + bool manual_flow; 149 150 150 151 struct qcom_geni_private_data private_data; 151 152 const struct qcom_geni_device_data *dev_data; ··· 251 250 if (mctrl & TIOCM_LOOP) 252 251 port->loopback = RX_TX_CTS_RTS_SORTED; 253 252 254 - if (!(mctrl & TIOCM_RTS) && !uport->suspended) 253 + if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended) 255 254 uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY; 256 255 writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR); 257 256 } ··· 1402 1401 else 1403 1402 stop_bit_len = TX_STOP_BIT_LEN_1; 1404 1403 1405 - /* flow control, clear the CTS_MASK bit if using flow control. */ 1406 - if (termios->c_cflag & CRTSCTS) 1404 + /* Configure flow control based on CRTSCTS flag. 1405 + * When CRTSCTS is set, use HW/auto flow control mode, where HW 1406 + * controls the RTS/CTS pin based FIFO state. 1407 + * When CRTSCTS is clear, the CTS pin value is ignored for TX 1408 + * path and RTS pin can be set/cleared using registers, for RX 1409 + * path. 1410 + */ 1411 + 1412 + if (termios->c_cflag & CRTSCTS) { 1407 1413 tx_trans_cfg &= ~UART_CTS_MASK; 1408 - else 1414 + port->manual_flow = false; 1415 + } else { 1409 1416 tx_trans_cfg |= UART_CTS_MASK; 1417 + port->manual_flow = true; 1418 + } 1410 1419 1411 1420 if (baud) { 1412 1421 uart_update_timeout(uport, termios->c_cflag, baud);