diff options
author | Fugang Duan <fugang.duan@nxp.com> | 2017-07-26 12:51:51 +0800 |
---|---|---|
committer | Fugang Duan <fugang.duan@nxp.com> | 2017-07-26 14:50:42 +0800 |
commit | 8caf1f5a3efaf0f76f470c338e7727a558ac01bc (patch) | |
tree | ad4724d6fd4bc0616aeedd365edf66cde3d37b5b | |
parent | 4334e587722ac8a6c9c49f72d307f514db5e2f81 (diff) |
MLK-16086 tty: serial: lpuart: add port.lock to protect registers accessing in suspend
Add port.lock to protect register accessing in suspend/resume function.
Disable RIE and ILIE before DMA chan is ternminated in suspend function.
Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
(cherry picked from commit: 51f874a9205cbcbbdb55642f5502bf18aaf245bd)
-rw-r--r-- | drivers/tty/serial/fsl_lpuart.c | 34 |
1 files changed, 23 insertions, 11 deletions
diff --git a/drivers/tty/serial/fsl_lpuart.c b/drivers/tty/serial/fsl_lpuart.c index b1357ac800a8..247286c91c66 100644 --- a/drivers/tty/serial/fsl_lpuart.c +++ b/drivers/tty/serial/fsl_lpuart.c @@ -254,6 +254,7 @@ struct lpuart_port { bool lpuart_dma_tx_use; bool lpuart_dma_rx_use; + bool dma_rx_chan_active; struct dma_chan *dma_tx_chan; struct dma_chan *dma_rx_chan; struct dma_async_tx_descriptor *dma_tx_desc; @@ -776,7 +777,7 @@ static irqreturn_t lpuart32_int(int irq, void *dev_id) if (!sport->lpuart_dma_rx_use || (sts & (UARTSTAT_PE | UARTSTAT_NF | UARTSTAT_FE))) lpuart32_rxint(irq, dev_id); - else + else if (sport->lpuart_dma_rx_use && sport->dma_rx_chan_active) lpuart_prepare_rx(sport); } @@ -809,7 +810,7 @@ static void lpuart_copy_rx_to_tty(struct lpuart_port *sport, sport->port.icount.rx += copied; } -static void lpuart_dma_stop(struct lpuart_port *sport) +static void lpuart_dma_stop(struct lpuart_port *sport, bool enable_pio) { unsigned int temp; unsigned int crdma; @@ -819,9 +820,11 @@ static void lpuart_dma_stop(struct lpuart_port *sport) crdma = lpuart32_read(sport->port.membase + UARTBAUD); lpuart32_write(crdma & ~(UARTBAUD_RDMAE), sport->port.membase + UARTBAUD); - temp = lpuart32_read(sport->port.membase + UARTCTRL); - temp |= (UARTCTRL_RIE | UARTCTRL_ILIE); - lpuart32_write(temp, sport->port.membase + UARTCTRL); + if (enable_pio) { + temp = lpuart32_read(sport->port.membase + UARTCTRL); + temp |= (UARTCTRL_RIE | UARTCTRL_ILIE); + lpuart32_write(temp, sport->port.membase + UARTCTRL); + } } else { temp = readb(sport->port.membase + UARTCR5); writeb(temp & ~UARTCR5_RDMAS, sport->port.membase + UARTCR5); @@ -847,7 +850,7 @@ static void lpuart_dma_rx_complete(void *arg) tty_flip_buffer_push(port); if (count < sport->rxfifo_watermark) - lpuart_dma_stop(sport); + lpuart_dma_stop(sport, true); else lpuart_dma_rx(sport); @@ -874,7 +877,7 @@ static void lpuart_timer_func(unsigned long data) sport->dma_rx_in_progress = false; lpuart_copy_rx_to_tty(sport, port, count); tty_flip_buffer_push(port); - lpuart_dma_stop(sport); + lpuart_dma_stop(sport, true); spin_unlock_irqrestore(&sport->port.lock, flags); } @@ -906,6 +909,7 @@ static void lpuart_dma_rx_free(struct uart_port *port) struct lpuart_port *sport = container_of(port, struct lpuart_port, port); + sport->dma_rx_chan_active = false; dma_unmap_single(sport->port.dev, sport->dma_rx_buf_bus, sport->rxdma_len, DMA_FROM_DEVICE); @@ -1188,6 +1192,7 @@ static int lpuart_dma_rx_request(struct uart_port *port) sport->dma_rx_buf_virt = dma_buf; sport->dma_rx_buf_bus = dma_bus; sport->dma_rx_in_progress = false; + sport->dma_rx_chan_active = true; return 0; } @@ -2302,6 +2307,7 @@ static int lpuart_suspend(struct device *dev) struct lpuart_port *sport = dev_get_drvdata(dev); struct tty_port *port = &sport->port.state->port; unsigned long temp; + unsigned long flags; int ret; ret = clk_prepare_enable(sport->ipg_clk); @@ -2311,12 +2317,10 @@ static int lpuart_suspend(struct device *dev) uart_suspend_port(&lpuart_reg, &sport->port); if (sport->lpuart32) { - /* disable Rx/Tx and interrupts */ temp = lpuart32_read(sport->port.membase + UARTCTRL); temp &= ~(UARTCTRL_TE | UARTCTRL_TIE | UARTCTRL_TCIE); lpuart32_write(temp, sport->port.membase + UARTCTRL); } else { - /* disable Rx/Tx and interrupts */ temp = readb(sport->port.membase + UARTCR2); temp &= ~(UARTCR2_TE | UARTCR2_TIE | UARTCR2_TCIE); writeb(temp, sport->port.membase + UARTCR2); @@ -2324,8 +2328,10 @@ static int lpuart_suspend(struct device *dev) if (sport->lpuart_dma_rx_use && sport->port.irq_wake && tty_port_initialized(port)) { - /* it needs uart interrupt as wakeup source in low power mode */ - lpuart_dma_stop(sport); + spin_lock_irqsave(&sport->port.lock, flags); + lpuart_dma_stop(sport, false); + spin_unlock_irqrestore(&sport->port.lock, flags); + dmaengine_terminate_all(sport->dma_rx_chan); del_timer_sync(&sport->lpuart_timer); lpuart_dma_rx_free(&sport->port); @@ -2353,7 +2359,9 @@ static inline void lpuart32_resume_init(struct lpuart_port *sport) { struct tty_port *port = &sport->port.state->port; unsigned long temp; + unsigned long flags; + spin_lock_irqsave(&sport->port.lock, flags); lpuart32_setup_watermark(sport); temp = lpuart32_read(sport->port.membase + UARTCTRL); @@ -2367,6 +2375,7 @@ static inline void lpuart32_resume_init(struct lpuart_port *sport) temp &= ~(UARTCTRL_TIE | UARTCTRL_TE); lpuart32_write(temp, sport->port.membase + UARTCTRL); + spin_unlock_irqrestore(&sport->port.lock, flags); if (sport->lpuart_dma_rx_use && sport->port.irq_wake && tty_port_initialized(port)) { @@ -2405,7 +2414,9 @@ static inline void lpuart_resume_init(struct lpuart_port *sport) { struct tty_port *port = &sport->port.state->port; unsigned char temp; + unsigned long flags; + spin_lock_irqsave(&sport->port.lock, flags); lpuart_setup_watermark(sport); temp = readb(sport->port.membase + UARTCR2); temp |= (UARTCR2_RIE | UARTCR2_TIE | UARTCR2_RE | UARTCR2_TE); @@ -2417,6 +2428,7 @@ static inline void lpuart_resume_init(struct lpuart_port *sport) temp &= ~(UARTCR2_TIE | UARTCR2_TE); writeb(temp, sport->port.membase + UARTCR2); + spin_unlock_irqrestore(&sport->port.lock, flags); if (sport->lpuart_dma_rx_use && sport->port.irq_wake && tty_port_initialized(port)) { |