diff options
| author | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-06-09 12:32:51 +0200 |
|---|---|---|
| committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2026-06-09 12:32:51 +0200 |
| commit | 73e7709d9919efeb8df2cedd7804734a3254a0bb (patch) | |
| tree | 2c9126ec1b1e76c38f6713b4b7e10d44b4d24847 /drivers/tty/serial/qcom_geni_serial.c | |
| parent | d0acb5202d0e33d23cbe6994424587fbb05a5360 (diff) | |
| parent | f53879e2e1e2fa053040e734c1ef8f386109a61b (diff) | |
Merge v7.0.12linux-rolling-stable
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'drivers/tty/serial/qcom_geni_serial.c')
| -rw-r--r-- | drivers/tty/serial/qcom_geni_serial.c | 16 |
1 files changed, 14 insertions, 2 deletions
diff --git a/drivers/tty/serial/qcom_geni_serial.c b/drivers/tty/serial/qcom_geni_serial.c index e6b0a55f0cfb..774c0b7f8508 100644 --- a/drivers/tty/serial/qcom_geni_serial.c +++ b/drivers/tty/serial/qcom_geni_serial.c @@ -50,7 +50,7 @@ #define TX_STOP_BIT_LEN_2 2 /* SE_UART_RX_TRANS_CFG */ -#define UART_RX_PAR_EN BIT(3) +#define UART_RX_PAR_EN BIT(4) /* SE_UART_RX_WORD_LEN */ #define RX_WORD_LEN_MASK GENMASK(9, 0) @@ -1030,8 +1030,20 @@ static void qcom_geni_serial_handle_tx_dma(struct uart_port *uport) { struct qcom_geni_serial_port *port = to_dev_port(uport); struct tty_port *tport = &uport->state->port; + unsigned int fifo_len = kfifo_len(&tport->xmit_fifo); + + /* + * Only advance the kfifo if it still contains the bytes that were + * transferred. uart_flush_buffer() may have run before this IRQ + * fired: it calls kfifo_reset() under the port lock, making + * fifo_len = 0 while tx_remaining remains non-zero. Calling + * uart_xmit_advance() in that case would underflow kfifo->out past + * kfifo->in, making kfifo_len() wrap to UART_XMIT_SIZE - tx_remaining + * and triggering a spurious large DMA transfer of stale data. + */ + if (fifo_len >= port->tx_remaining) + uart_xmit_advance(uport, port->tx_remaining); - uart_xmit_advance(uport, port->tx_remaining); geni_se_tx_dma_unprep(&port->se, port->tx_dma_addr, port->tx_remaining); port->tx_dma_addr = 0; port->tx_remaining = 0; |
