Patch "tty: serial: fsl_lpuart: fix race on RX DMA shutdown" has been added to the 5.15-stable tree

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This is a note to let you know that I've just added the patch titled

    tty: serial: fsl_lpuart: fix race on RX DMA shutdown

to the 5.15-stable tree which can be found at:
    http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary

The filename of the patch is:
     tty-serial-fsl_lpuart-fix-race-on-rx-dma-shutdown.patch
and it can be found in the queue-5.15 subdirectory.

If you, or anyone else, feels it should not be added to the stable tree,
please let <stable@xxxxxxxxxxxxxxx> know about it.



commit 925a7fe212f094359a3de668d6eec38a67f58a02
Author: Alexander Sverdlin <alexander.sverdlin@xxxxxxxxxxx>
Date:   Thu Mar 9 14:43:02 2023 +0100

    tty: serial: fsl_lpuart: fix race on RX DMA shutdown
    
    [ Upstream commit 1be6f2b15f902c02e055ae0b419ca789200473c9 ]
    
    From time to time DMA completion can come in the middle of DMA shutdown:
    
    <process ctx>:                          <IRQ>:
    lpuart32_shutdown()
      lpuart_dma_shutdown()
        del_timer_sync()
                                            lpuart_dma_rx_complete()
                                              lpuart_copy_rx_to_tty()
                                                mod_timer()
        lpuart_dma_rx_free()
    
    When the timer fires a bit later, sport->dma_rx_desc is NULL:
    
    Unable to handle kernel NULL pointer dereference at virtual address 0000000000000004
    pc : lpuart_copy_rx_to_tty+0xcc/0x5bc
    lr : lpuart_timer_func+0x1c/0x2c
    Call trace:
     lpuart_copy_rx_to_tty
     lpuart_timer_func
     call_timer_fn
     __run_timers.part.0
     run_timer_softirq
     __do_softirq
     __irq_exit_rcu
     irq_exit
     handle_domain_irq
     gic_handle_irq
     call_on_irq_stack
     do_interrupt_handler
     ...
    
    To fix this fold del_timer_sync() into lpuart_dma_rx_free() after
    dmaengine_terminate_sync() to make sure timer will not be re-started in
    lpuart_copy_rx_to_tty() <= lpuart_dma_rx_complete().
    
    Fixes: 4a8588a1cf86 ("serial: fsl_lpuart: delete timer on shutdown")
    Cc: stable <stable@xxxxxxxxxx>
    Signed-off-by: Alexander Sverdlin <alexander.sverdlin@xxxxxxxxxxx>
    Link: https://lore.kernel.org/r/20230309134302.74940-2-alexander.sverdlin@xxxxxxxxxxx
    Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx>
    Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx>

diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 47097002a6427..ac3c6c1e80ccc 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -1308,6 +1308,7 @@ static void lpuart_dma_rx_free(struct uart_port *port)
 	struct dma_chan *chan = sport->dma_rx_chan;
 
 	dmaengine_terminate_sync(chan);
+	del_timer_sync(&sport->lpuart_timer);
 	dma_unmap_sg(chan->device->dev, &sport->rx_sgl, 1, DMA_FROM_DEVICE);
 	kfree(sport->rx_ring.buf);
 	sport->rx_ring.tail = 0;
@@ -1773,7 +1774,6 @@ static int lpuart32_startup(struct uart_port *port)
 static void lpuart_dma_shutdown(struct lpuart_port *sport)
 {
 	if (sport->lpuart_dma_rx_use) {
-		del_timer_sync(&sport->lpuart_timer);
 		lpuart_dma_rx_free(&sport->port);
 		sport->lpuart_dma_rx_use = false;
 	}
@@ -1933,10 +1933,8 @@ lpuart_set_termios(struct uart_port *port, struct ktermios *termios,
 	 * Since timer function acqures sport->port.lock, need to stop before
 	 * acquring same lock because otherwise del_timer_sync() can deadlock.
 	 */
-	if (old && sport->lpuart_dma_rx_use) {
-		del_timer_sync(&sport->lpuart_timer);
+	if (old && sport->lpuart_dma_rx_use)
 		lpuart_dma_rx_free(&sport->port);
-	}
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
@@ -2171,10 +2169,8 @@ lpuart32_set_termios(struct uart_port *port, struct ktermios *termios,
 	 * Since timer function acqures sport->port.lock, need to stop before
 	 * acquring same lock because otherwise del_timer_sync() can deadlock.
 	 */
-	if (old && sport->lpuart_dma_rx_use) {
-		del_timer_sync(&sport->lpuart_timer);
+	if (old && sport->lpuart_dma_rx_use)
 		lpuart_dma_rx_free(&sport->port);
-	}
 
 	spin_lock_irqsave(&sport->port.lock, flags);
 
@@ -2870,7 +2866,6 @@ static int __maybe_unused lpuart_suspend(struct device *dev)
 		 * Rx DMA path before suspend and start Rx DMA path on resume.
 		 */
 		if (irq_wake) {
-			del_timer_sync(&sport->lpuart_timer);
 			lpuart_dma_rx_free(&sport->port);
 		}
 



[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Index of Archives]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite News]     [Linux Kernel]     [Linux SCSI]

  Powered by Linux