From d0e7600b914c9fd4935fe6dabf0cd5d71cb94347 Mon Sep 17 00:00:00 2001 From: Michael Walle Date: Wed, 25 Mar 2020 10:06:57 +0100 Subject: 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 Signed-off-by: Michael Walle Reviewed-by: Fugang Duan Tested-by: Leonard Crestez Link: https://lore.kernel.org/r/20200325090658.25967-1-michael@walle.cc Signed-off-by: Greg Kroah-Hartman --- drivers/tty/serial/fsl_lpuart.c | 36 +++++++++++++++++++++++------------- 1 file changed, 23 insertions(+), 13 deletions(-) (limited to 'drivers/tty') 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); -- cgit v1.2.3