MLK-17218 tty: serial: imx: add lock for register save/restore
authorFugang Duan <fugang.duan@nxp.com>
Thu, 14 Dec 2017 09:52:50 +0000 (17:52 +0800)
committerNitin Garg <nitin.garg@nxp.com>
Tue, 20 Mar 2018 19:51:34 +0000 (14:51 -0500)
The driver save/restore registers in system suspend/resume noirq stage
to support no_console_suspend in power lost case.

In noirq stage with no_console_suspend, .imx_console_write() _maybe_
called to print out log_buf message in .printk() or console_unlock()
called by other drivers.
It should add port.lock to protect the registers save/restore in noirq
stage since .imx_console_write() also access them.

Reported-by: Anson Huang <Anson.Huang@nxp.com>
Signed-off-by: Fugang Duan <fugang.duan@nxp.com>
drivers/tty/serial/imx.c

index b95b3b2..2c208a8 100644 (file)
@@ -2242,9 +2242,12 @@ static int serial_imx_remove(struct platform_device *pdev)
 
 static void serial_imx_restore_context(struct imx_port *sport)
 {
+       unsigned long flags = 0;
+
        if (!sport->context_saved)
                return;
 
+       spin_lock_irqsave(&sport->port.lock, flags);
        writel(sport->saved_reg[4], sport->port.membase + UFCR);
        writel(sport->saved_reg[5], sport->port.membase + UESC);
        writel(sport->saved_reg[6], sport->port.membase + UTIM);
@@ -2256,11 +2259,15 @@ static void serial_imx_restore_context(struct imx_port *sport)
        writel(sport->saved_reg[2], sport->port.membase + UCR3);
        writel(sport->saved_reg[3], sport->port.membase + UCR4);
        sport->context_saved = false;
+       spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 static void serial_imx_save_context(struct imx_port *sport)
 {
+       unsigned long flags = 0;
+
        /* Save necessary regs */
+       spin_lock_irqsave(&sport->port.lock, flags);
        sport->saved_reg[0] = readl(sport->port.membase + UCR1);
        sport->saved_reg[1] = readl(sport->port.membase + UCR2);
        sport->saved_reg[2] = readl(sport->port.membase + UCR3);
@@ -2272,6 +2279,10 @@ static void serial_imx_save_context(struct imx_port *sport)
        sport->saved_reg[8] = readl(sport->port.membase + UBMR);
        sport->saved_reg[9] = readl(sport->port.membase + IMX21_UTS);
        sport->context_saved = true;
+
+       if (uart_console(&sport->port) && sport->port.sysrq)
+               sport->saved_reg[0] |= UCR1_RRDYEN;
+       spin_unlock_irqrestore(&sport->port.lock, flags);
 }
 
 static void serial_imx_enable_wakeup(struct imx_port *sport, bool on)