]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
serial: amba-pl011: synchronize DMA teardown
authorFan Wu <fanwu01@zju.edu.cn>
Fri, 31 Jul 2026 08:59:15 +0000 (08:59 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 3 Aug 2026 14:31:22 +0000 (16:31 +0200)
dmaengine_terminate_all() does not wait for a running callback, so the TX
callback can still touch the TX buffer after it is freed. The RX poll
timer reads the RX buffers without the port lock.

Switch to dmaengine_terminate_sync() and delete the RX timer before
freeing the buffers.

Fixes: ead76f329f77 ("ARM: 6763/1: pl011: add optional RX DMA to PL011 v2")
Cc: stable <stable@kernel.org>
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Link: https://patch.msgid.link/20260731085915.326775-4-fanwu01@zju.edu.cn
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/amba-pl011.c

index 5232042fdd929c58fa7d364841b607ba7808018e..9abaeecd05fc80a7760e5d43764c16117abb9dad 100644 (file)
@@ -1247,7 +1247,7 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
 
        if (uap->using_tx_dma) {
                /* In theory, this should already be done by pl011_dma_flush_buffer */
-               dmaengine_terminate_all(uap->dmatx.chan);
+               dmaengine_terminate_sync(uap->dmatx.chan);
                if (uap->dmatx.queued) {
                        dma_unmap_single(uap->dmatx.chan->device->dev,
                                         uap->dmatx.dma, uap->dmatx.len,
@@ -1260,12 +1260,12 @@ static void pl011_dma_shutdown(struct uart_amba_port *uap)
        }
 
        if (uap->using_rx_dma) {
-               dmaengine_terminate_all(uap->dmarx.chan);
+               if (uap->dmarx.poll_rate)
+                       timer_delete_sync(&uap->dmarx.timer);
+               dmaengine_terminate_sync(uap->dmarx.chan);
                /* Clean up the RX DMA */
                pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_a, DMA_FROM_DEVICE);
                pl011_dmabuf_free(uap->dmarx.chan, &uap->dmarx.dbuf_b, DMA_FROM_DEVICE);
-               if (uap->dmarx.poll_rate)
-                       timer_delete_sync(&uap->dmarx.timer);
                uap->using_rx_dma = false;
        }
 }