FAILED: patch "[PATCH] serial: 8250_dma: Fix DMA Rx rearm race" failed to apply to 5.4-stable tree
Subsystems (2)
[email protected]
maintainerThe patch below does not apply to the 5.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
Possible dependencies:
57e9af7831dc ("serial: 8250_dma: Fix DMA Rx rearm race")
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From 57e9af7831dcf211c5c689c2a6f209f4abdf0bce Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Ilpo=20J=C3=A4rvinen?= <[email protected]>
Date: Mon, 30 Jan 2023 13:48:41 +0200
Subject: [PATCH] serial: 8250_dma: Fix DMA Rx rearm race
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit
As DMA Rx can be completed from two places, it is possible that DMA Rx completes before DMA completion callback had a chance to complete it. Once the previous DMA Rx has been completed, a new one can be started on the next UART interrupt. The following race is possible (uart_unlock_and_check_sysrq_irqrestore() replaced with spin_unlock_irqrestore() for simplicity/clarity):
CPU0 CPU1
dma_rx_complete()serial8250_handle_irq()
spin_lock_irqsave(&port->lock)
handle_rx_dma()
serial8250_rx_dma_flush()
__dma_rx_complete()
dma->rx_running = 0
// Complete DMA Rx spin_unlock_irqrestore(&port->lock)
serial8250_handle_irq()
spin_lock_irqsave(&port->lock)
handle_rx_dma()
serial8250_rx_dma()
dma->rx_running = 1
// Setup a new DMA Rx spin_unlock_irqrestore(&port->lock)
spin_lock_irqsave(&port->lock) // sees dma->rx_running = 1 __dma_rx_complete() dma->rx_running = 0 // Incorrectly complete // running DMA Rx
This race seems somewhat theoretical to occur for real but handle it correctly regardless. Check what is the DMA status before complething anything in __dma_rx_complete().
drivers/tty/serial/8250/8250_dma.c +10 -2
@@ -43,15 +43,23 @@ static void __dma_rx_complete(struct uart_8250_port *p)struct uart_8250_dma *dma = p->dma;struct tty_port *tty_port = &p->port.state->port;struct dma_tx_state state; +enum dma_status dma_status;int count; - dma->rx_running =0 ; -dmaengine_tx_status (dma->rxchan, dma->rx_cookie, &state); +/* +* New DMA Rx can be started during the completion handler before it +* could acquire port's lock and it might still be ongoing. Don't to +* anything in such case. +*/ + dma_status =dmaengine_tx_status (dma->rxchan, dma->rx_cookie, &state); +if (dma_status ==DMA_IN_PROGRESS ) +return ; count = dma->rx_size - state.residue;tty_insert_flip_string (tty_port, dma->rx_buf, count); p->port.icount.rx += count; + dma->rx_running =0 ;tty_flip_buffer_push (tty_port); }