Skip to content

Commit 0b1837c

Browse files
Anup Kulkarnigregkh
authored andcommitted
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>
1 parent 74e0c9f commit 0b1837c

1 file changed

Lines changed: 15 additions & 4 deletions

File tree

drivers/tty/serial/qcom_geni_serial.c

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ struct qcom_geni_serial_port {
146146
int wakeup_irq;
147147
bool rx_tx_swap;
148148
bool cts_rts_swap;
149+
bool manual_flow;
149150

150151
struct qcom_geni_private_data private_data;
151152
const struct qcom_geni_device_data *dev_data;
@@ -250,7 +251,7 @@ static void qcom_geni_serial_set_mctrl(struct uart_port *uport,
250251
if (mctrl & TIOCM_LOOP)
251252
port->loopback = RX_TX_CTS_RTS_SORTED;
252253

253-
if (!(mctrl & TIOCM_RTS) && !uport->suspended)
254+
if (port->manual_flow && !(mctrl & TIOCM_RTS) && !uport->suspended)
254255
uart_manual_rfr = UART_MANUAL_RFR_EN | UART_RFR_NOT_READY;
255256
writel(uart_manual_rfr, uport->membase + SE_UART_MANUAL_RFR);
256257
}
@@ -1401,11 +1402,21 @@ static void qcom_geni_serial_set_termios(struct uart_port *uport,
14011402
else
14021403
stop_bit_len = TX_STOP_BIT_LEN_1;
14031404

1404-
/* flow control, clear the CTS_MASK bit if using flow control. */
1405-
if (termios->c_cflag & CRTSCTS)
1405+
/* Configure flow control based on CRTSCTS flag.
1406+
* When CRTSCTS is set, use HW/auto flow control mode, where HW
1407+
* controls the RTS/CTS pin based FIFO state.
1408+
* When CRTSCTS is clear, the CTS pin value is ignored for TX
1409+
* path and RTS pin can be set/cleared using registers, for RX
1410+
* path.
1411+
*/
1412+
1413+
if (termios->c_cflag & CRTSCTS) {
14061414
tx_trans_cfg &= ~UART_CTS_MASK;
1407-
else
1415+
port->manual_flow = false;
1416+
} else {
14081417
tx_trans_cfg |= UART_CTS_MASK;
1418+
port->manual_flow = true;
1419+
}
14091420

14101421
if (baud) {
14111422
uart_update_timeout(uport, termios->c_cflag, baud);

0 commit comments

Comments
 (0)