]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
serial: msm: Disable DMA for kernel console UART
authorStephan Gerhold <stephan.gerhold@linaro.org>
Mon, 6 Jul 2026 18:03:32 +0000 (20:03 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 7 Jul 2026 15:24:42 +0000 (17:24 +0200)
At the moment, concurrent writes from userspace and the kernel to the
console can trigger a race condition that results in an infinite loop of
the same messages printed over and over again. This is most likely to
happen during system startup or shutdown when the init system starts/stops
a large number of system services that interact with various kernel code.

When userspace writes to the TTY device, the driver initiates an
asynchronous DMA transfer and releases the port lock. At the same moment,
the kernel printk path might grab the port lock and re-configure the UART
controller for PIO, without waiting for the DMA operation to complete. It
seems like this collision results in zero progress being reported for the
DMA engine, so the same text is printed to the console over and over again.

For the kernel console, we want a reliable output path that will be
functional even during crashes etc. So rather than implementing complex
code to synchronize the kernel console write routines with the userspace
DMA write routines, simply disable DMA for the console UART instance.

Similar checks exist in many other serial drivers, e.g. 8250_port.c,
imx.c, sh-sci.c etc.

Cc: stable <stable@kernel.org>
Fixes: 3a878c430fd6 ("tty: serial: msm: Add TX DMA support")
Signed-off-by: Stephan Gerhold <stephan.gerhold@linaro.org>
Acked-by: Konrad Dybcio <konrad.dybcio@oss.qualcomm.com>
Link: https://patch.msgid.link/20260706-serial-msm-console-dma-collision-v1-1-3179b8cb1d89@linaro.org
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/msm_serial.c

index 2e999cb9c97447255c14d632ccbbbbfc65972f77..bfa44b01c3e9795b9d2da2e6bf8d4cb33ed4ae84 100644 (file)
@@ -1228,7 +1228,8 @@ static int msm_startup(struct uart_port *port)
        data |= MSM_UART_MR1_AUTO_RFR_LEVEL0 & rfr_level;
        msm_write(port, data, MSM_UART_MR1);
 
-       if (msm_port->is_uartdm) {
+       /* Disable DMA for console to prevent PIO/DMA collisions */
+       if (msm_port->is_uartdm && !uart_console(port)) {
                msm_request_tx_dma(msm_port, msm_port->uart.mapbase);
                msm_request_rx_dma(msm_port, msm_port->uart.mapbase);
        }