Commit 287f0f5
FROMLIST: serial: qcom_geni: fix kfifo underflow when flush precedes DMA completion IRQ
When uart_flush_buffer() runs before the DMA completion IRQ is delivered,
the following race can occur (all steps serialized by uart_port_lock):
1. DMA starts: tx_remaining = N, kfifo contains N bytes
2. DMA completes in hardware; IRQ is pending but not yet delivered
3. uart_flush_buffer() acquires the port lock and calls kfifo_reset(),
making kfifo_len() = 0 while tx_remaining remains N
4. uart_flush_buffer() releases the port lock
5. DMA IRQ fires; handle_tx_dma() acquires the port lock and calls
uart_xmit_advance(uport, tx_remaining) on an empty kfifo
uart_xmit_advance() increments kfifo->out by tx_remaining. Since
kfifo_reset() already set both in and out to 0, out wraps past in,
causing kfifo_len() to return UART_XMIT_SIZE - tx_remaining. The next
start_tx_dma() call then submits a DMA transfer of stale buffer data.
Fix this by snapshotting kfifo_len() at the start of handle_tx_dma()
and skipping uart_xmit_advance() when fifo_len < tx_remaining, which
indicates the kfifo was reset by a preceding flush.
Link: https://patch.msgid.link/20260506-serial-dma-stale-tx-buf-v1-1-e3ccb360d719@oss.qualcomm.com
Fixes: 2aaa43c ("tty: serial: qcom-geni-serial: add support for serial engine DMA")
Cc: stable@vger.kernel.org
Signed-off-by: Viken Dadhaniya <viken.dadhaniya@oss.qualcomm.com>1 parent 6fe71bf commit 287f0f5
1 file changed
Lines changed: 13 additions & 1 deletion
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1031 | 1031 | | |
1032 | 1032 | | |
1033 | 1033 | | |
| 1034 | + | |
| 1035 | + | |
| 1036 | + | |
| 1037 | + | |
| 1038 | + | |
| 1039 | + | |
| 1040 | + | |
| 1041 | + | |
| 1042 | + | |
| 1043 | + | |
| 1044 | + | |
| 1045 | + | |
| 1046 | + | |
1034 | 1047 | | |
1035 | | - | |
1036 | 1048 | | |
1037 | 1049 | | |
1038 | 1050 | | |
| |||
0 commit comments