• Ilpo Järvinen's avatar
    serial: 8250_dma: Fix DMA Rx rearm race · 57e9af78
    Ilpo Järvinen authored
    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().
    Reported-by: default avatarGilles BULOZ <gilles.buloz@kontron.com>
    Tested-by: default avatarGilles BULOZ <gilles.buloz@kontron.com>
    Fixes: 9ee4b83e ("serial: 8250: Add support for dmaengine")
    Cc: stable@vger.kernel.org
    Signed-off-by: default avatarIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
    Link: https://lore.kernel.org/r/20230130114841.25749-3-ilpo.jarvinen@linux.intel.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
    57e9af78
8250_dma.c 7.19 KB