[PATCH 0/1] serial: qcom-geni: fix TX DMA buffer flush
jaseg <[email protected]> Wed, 29 Jul 2026 19:41:04 +0200
| Newsgroups | org.kernel.vger.linux-serial,org.kernel.vger.linux-arm-msm |
|---|---|
| Message-ID | <[email protected]> |
From: Jan Sebastian Götte <[email protected]> I ran into a weird issue using the UART on an Arduino Uno Q (Qualcomm QRB2210) target. When doing a write immediately followed by a transmit flush, the UART would get stuck infinitely repeating a stale DMA buffer and become unresponsive to further write() calls. With some assistance from an LLM, I tracked down the issue to the geni serial driver's DMA mode code. There are at least two issues in the code that contribute to this behavior: (1) In DMA mode, uart_ops.flush_buffer is missing, leading to an underflow in handle_tx_dma, which leads to an infinite loop of page-sized buffers being sent out. (2) In DMA mode, uart_ops.stop_tx was fishy, and unmapped the DMA buffer without actually stopping the peripheral's DMA engine which led to a stuck state where the UART wouldn't transmit any more bytes. Qualcomm refused to give me access to their documentation, so I'm left guessing and vibe checking LLM output on some of this, but I've confirmed looking at hardware with an oscilloscope that both the fixes in stop_tx, and the new flush_buffer are necessary to solve the issue. What's left is that I'm pretty sure that even with my rework, stop_tx will still lead to buffer contents being re-transmitted after restarting when it's called during an ongoing DMA transfer. AFAICT there never was anything here that would keep track of partial transfers, so I think I didn't make things worse. I don't have a nice way to debug this, and I don't know what the original intention of whoever wrote that code was, so I'm leaving that for maybe someone at Qualcomm to have a look at. Below is a reproducer that when the bug is present hangs and leads to an infinite stream of alphabet soup on the UART TX pin. (*snip*) #include <fcntl.h> #include <stdio.h> #include <termios.h> #include <unistd.h> int main(int argc, char **argv) { char buf[4096]; int fd, i; for (i = 0; i < (int)sizeof(buf); i++) buf[i] = 'A' + i % 26; fd = open(argc > 1 ? argv[1] : "/dev/ttyHS1", O_RDWR | O_NOCTTY); write(fd, buf, sizeof(buf)); usleep(20000); tcflush(fd, TCOFLUSH); write(fd, "foo\r\n", 5); usleep(100000); puts("tcdrain: hangs forever when wedged"); tcdrain(fd); puts("tcdrain returned: NOT wedged"); return 0; } (*snip*) Jan Sebastian Götte (1): serial: qcom-geni: fix TX DMA buffer flush drivers/tty/serial/qcom_geni_serial.c | 43 ++++++++++++++------------- 1 file changed, 22 insertions(+), 21 deletions(-) -- 2.53.0