MLK-16086 tty: serial: lpuart: add port.lock to protect registers accessing in suspend
authorFugang Duan <fugang.duan@nxp.com>
Wed, 26 Jul 2017 06:16:11 +0000 (14:16 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Mon, 19 Mar 2018 20:33:48 +0000 (15:33 -0500)
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>
drivers/tty/serial/fsl_lpuart.c

index 37f10bb..8d637fb 100644 (file)
@@ -257,6 +257,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;
@@ -813,7 +814,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);
        } else if (!(crdma & UARTBAUD_RDMAE) && (sts & UARTSTAT_IDLE)) {
                lpuart32_write(UARTSTAT_IDLE, sport->port.membase + UARTSTAT);
@@ -849,7 +850,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;
@@ -859,9 +860,11 @@ static void lpuart_dma_stop(struct lpuart_port *sport)
                crdma = lpuart32_read(sport->port.membase + UARTBAUD);
                lpuart32_write(crdma & ~(UARTBAUD_RDMAE | UARTBAUD_RIDMAE),
                                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);
@@ -903,7 +906,7 @@ static void lpuart_dma_rx_complete(void *arg)
        }
 
        if (!sport->dma_eeop && count < sport->rxfifo_watermark)
-               lpuart_dma_stop(sport);
+               lpuart_dma_stop(sport, true);
        else
                lpuart_dma_rx(sport);
 
@@ -929,7 +932,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);
 }
@@ -961,6 +964,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);
 
@@ -1251,6 +1255,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;
 }
@@ -2374,6 +2379,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);
@@ -2383,12 +2389,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);
@@ -2396,8 +2400,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);
                if (!sport->dma_eeop)
                        del_timer_sync(&sport->lpuart_timer);
@@ -2426,7 +2432,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);
@@ -2440,6 +2448,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)) {
@@ -2480,7 +2489,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);
@@ -2492,6 +2503,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)) {