summary refs log tree commit diff
path: root/drivers/tty
diff options
context:
space:
mode:
authorMichael Walle <michael@walle.cc>2020-03-25 10:06:57 +0100
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2020-03-26 15:34:05 +0100
commitd0e7600b914c9fd4935fe6dabf0cd5d71cb94347 (patch)
tree480b2a47d73395835b6d446ddb3b8d8f3781c120 /drivers/tty
parenta0c4adeeea84889890bb4c7a28dc58b7c764e4ad (diff)
downloadlinux-d0e7600b914c9fd4935fe6dabf0cd5d71cb94347.tar.gz
tty: serial: fsl_lpuart: move dma_request_chan()
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>
Diffstat (limited to 'drivers/tty')
-rw-r--r--drivers/tty/serial/fsl_lpuart.c36
1 files changed, 23 insertions, 13 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c
index 9c6a018b1390..131018979b77 100644
--- a/drivers/tty/serial/fsl_lpuart.c
+++ b/drivers/tty/serial/fsl_lpuart.c
@@ -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);