tty: serial: fsl_lpuart: move dma_request_chan()
authorMichael Walle <michael@walle.cc>
Wed, 25 Mar 2020 09:06:57 +0000 (10:06 +0100)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Thu, 26 Mar 2020 14:34:05 +0000 (15:34 +0100)
Move dma_request_chan() out of the atomic context. First this call
should not be in the atomic context at all and second the
dev_info_once() may cause a hang because because the console takes this
spinlock, too.

Fixes: 159381df1442f ("tty: serial: fsl_lpuart: fix DMA operation when using IOMMU")
Reported-by: Leonard Crestez <leonard.crestez@nxp.com>
Signed-off-by: Michael Walle <michael@walle.cc>
Reviewed-by: Fugang Duan <fugang.duan@nxp.com>
Tested-by: Leonard Crestez <leonard.crestez@nxp.com>
Link: https://lore.kernel.org/r/20200325090658.25967-1-michael@walle.cc
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/fsl_lpuart.c

index 9c6a018..1310189 100644 (file)
@@ -1510,20 +1510,33 @@ static void rx_dma_timer_init(struct lpuart_port *sport)
        add_timer(&sport->lpuart_timer);
 }
 
-static void lpuart_tx_dma_startup(struct lpuart_port *sport)
+static void lpuart_request_dma(struct lpuart_port *sport)
 {
-       u32 uartbaud;
-       int ret;
-
        sport->dma_tx_chan = dma_request_chan(sport->port.dev, "tx");
        if (IS_ERR(sport->dma_tx_chan)) {
                dev_info_once(sport->port.dev,
                              "DMA tx channel request failed, operating without tx DMA (%ld)\n",
                              PTR_ERR(sport->dma_tx_chan));
                sport->dma_tx_chan = NULL;
-               goto err;
        }
 
+       sport->dma_rx_chan = dma_request_chan(sport->port.dev, "rx");
+       if (IS_ERR(sport->dma_rx_chan)) {
+               dev_info_once(sport->port.dev,
+                             "DMA rx channel request failed, operating without rx DMA (%ld)\n",
+                             PTR_ERR(sport->dma_rx_chan));
+               sport->dma_rx_chan = NULL;
+       }
+}
+
+static void lpuart_tx_dma_startup(struct lpuart_port *sport)
+{
+       u32 uartbaud;
+       int ret;
+
+       if (!sport->dma_tx_chan)
+               goto err;
+
        ret = lpuart_dma_tx_request(&sport->port);
        if (!ret)
                goto err;
@@ -1549,14 +1562,8 @@ static void lpuart_rx_dma_startup(struct lpuart_port *sport)
 {
        int ret;
 
-       sport->dma_rx_chan = dma_request_chan(sport->port.dev, "rx");
-       if (IS_ERR(sport->dma_rx_chan)) {
-               dev_info_once(sport->port.dev,
-                             "DMA rx channel request failed, operating without rx DMA (%ld)\n",
-                             PTR_ERR(sport->dma_rx_chan));
-               sport->dma_rx_chan = NULL;
+       if (!sport->dma_rx_chan)
                goto err;
-       }
 
        ret = lpuart_start_rx_dma(sport);
        if (ret)
@@ -1592,6 +1599,8 @@ static int lpuart_startup(struct uart_port *port)
        sport->rxfifo_size = UARTFIFO_DEPTH((temp >> UARTPFIFO_RXSIZE_OFF) &
                                            UARTPFIFO_FIFOSIZE_MASK);
 
+       lpuart_request_dma(sport);
+
        spin_lock_irqsave(&sport->port.lock, flags);
 
        lpuart_setup_watermark_enable(sport);
@@ -1649,11 +1658,12 @@ static int lpuart32_startup(struct uart_port *port)
                sport->port.fifosize = sport->txfifo_size;
        }
 
+       lpuart_request_dma(sport);
+
        spin_lock_irqsave(&sport->port.lock, flags);
 
        lpuart32_setup_watermark_enable(sport);
 
-
        lpuart_rx_dma_startup(sport);
        lpuart_tx_dma_startup(sport);