diff options
author | Michael Walle <michael@walle.cc> | 2020-03-25 10:06:57 +0100 |
---|---|---|
committer | Greg Kroah-Hartman <gregkh@linuxfoundation.org> | 2020-03-26 15:34:05 +0100 |
commit | d0e7600b914c9fd4935fe6dabf0cd5d71cb94347 (patch) | |
tree | 480b2a47d73395835b6d446ddb3b8d8f3781c120 /drivers/tty/serial | |
parent | a0c4adeeea84889890bb4c7a28dc58b7c764e4ad (diff) |
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/serial')
-rw-r--r-- | drivers/tty/serial/fsl_lpuart.c | 36 |
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); |