From: Fugang Duan <fugang.d...@nxp.com>

commit e67c139c488e84e7eae6c333231e791f0e89b3fb upstream.

For below code, there has chance to cause deadlock in SMP system:
Thread 1:
clk_enable_lock();
pr_info("debug message");
clk_enable_unlock();

Thread 2:
imx_uart_console_write()
        clk_enable()
                clk_enable_lock();

Thread 1:
Acuired clk enable_lock -> printk -> console_trylock_spinning
Thread 2:
console_unlock() -> imx_uart_console_write -> clk_disable -> Acquite clk 
enable_lock

So the patch is to keep console port clocks always on like
other console drivers.

Fixes: 1cf93e0d5488 ("serial: imx: remove the uart_console() check")
Acked-by: Uwe Kleine-König <u.kleine-koe...@pengutronix.de>
Signed-off-by: Fugang Duan <fugang.d...@nxp.com>
Link: https://lore.kernel.org/r/20201111025136.29818-1-fugang.d...@nxp.com
Cc: stable <sta...@vger.kernel.org>
[fix up build warning - gregkh]
Signed-off-by: Greg Kroah-Hartman <gre...@linuxfoundation.org>

---
 drivers/tty/serial/imx.c |   20 +++-----------------
 1 file changed, 3 insertions(+), 17 deletions(-)

--- a/drivers/tty/serial/imx.c
+++ b/drivers/tty/serial/imx.c
@@ -1942,16 +1942,6 @@ imx_uart_console_write(struct console *c
        unsigned int ucr1;
        unsigned long flags = 0;
        int locked = 1;
-       int retval;
-
-       retval = clk_enable(sport->clk_per);
-       if (retval)
-               return;
-       retval = clk_enable(sport->clk_ipg);
-       if (retval) {
-               clk_disable(sport->clk_per);
-               return;
-       }
 
        if (sport->port.sysrq)
                locked = 0;
@@ -1987,9 +1977,6 @@ imx_uart_console_write(struct console *c
 
        if (locked)
                spin_unlock_irqrestore(&sport->port.lock, flags);
-
-       clk_disable(sport->clk_ipg);
-       clk_disable(sport->clk_per);
 }
 
 /*
@@ -2090,15 +2077,14 @@ imx_uart_console_setup(struct console *c
 
        retval = uart_set_options(&sport->port, co, baud, parity, bits, flow);
 
-       clk_disable(sport->clk_ipg);
        if (retval) {
-               clk_unprepare(sport->clk_ipg);
+               clk_disable_unprepare(sport->clk_ipg);
                goto error_console;
        }
 
-       retval = clk_prepare(sport->clk_per);
+       retval = clk_prepare_enable(sport->clk_per);
        if (retval)
-               clk_unprepare(sport->clk_ipg);
+               clk_disable_unprepare(sport->clk_ipg);
 
 error_console:
        return retval;


Reply via email to