]> asedeno.scripts.mit.edu Git - linux.git/commitdiff
serial: uartps: Fix suspend functionality
authorNava kishore Manne <nava.manne@xilinx.com>
Mon, 3 Sep 2018 13:10:51 +0000 (15:10 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Tue, 18 Sep 2018 14:07:22 +0000 (16:07 +0200)
The driver's suspend/resume functions were buggy.
If UART node contains any child node in the DT and
the child is established a communication path with
the parent UART. The relevant /dev/ttyPS* node will
be not available for other operations.
If the driver is trying to do any operations like
suspend/resume without checking the tty->dev status
it leads to the kernel crash/hang.

This patch fix this issue by call the device_may_wake()
with the generic parameter of type struct device.
in the uart suspend and resume paths.

It also fixes a race condition in the uart suspend
path(i.e uart_suspend_port() should be called at the
end of cdns_uart_suspend API this path updates the same)

Signed-off-by: Nava kishore Manne <navam@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/xilinx_uartps.c

index edb9c2aeee7245d7ac9640a9fbbc96989bf1549b..251d061c00fe184774b62a1a308479db15dead8e 100644 (file)
@@ -1273,24 +1273,11 @@ static struct uart_driver cdns_uart_uart_driver = {
 static int cdns_uart_suspend(struct device *device)
 {
        struct uart_port *port = dev_get_drvdata(device);
-       struct tty_struct *tty;
-       struct device *tty_dev;
-       int may_wake = 0;
-
-       /* Get the tty which could be NULL so don't assume it's valid */
-       tty = tty_port_tty_get(&port->state->port);
-       if (tty) {
-               tty_dev = tty->dev;
-               may_wake = device_may_wakeup(tty_dev);
-               tty_kref_put(tty);
-       }
+       int may_wake;
 
-       /*
-        * Call the API provided in serial_core.c file which handles
-        * the suspend.
-        */
-       uart_suspend_port(&cdns_uart_uart_driver, port);
-       if (!(console_suspend_enabled && !may_wake)) {
+       may_wake = device_may_wakeup(device);
+
+       if (console_suspend_enabled && may_wake) {
                unsigned long flags = 0;
 
                spin_lock_irqsave(&port->lock, flags);
@@ -1305,7 +1292,11 @@ static int cdns_uart_suspend(struct device *device)
                spin_unlock_irqrestore(&port->lock, flags);
        }
 
-       return 0;
+       /*
+        * Call the API provided in serial_core.c file which handles
+        * the suspend.
+        */
+       return uart_suspend_port(&cdns_uart_uart_driver, port);
 }
 
 /**
@@ -1319,17 +1310,9 @@ static int cdns_uart_resume(struct device *device)
        struct uart_port *port = dev_get_drvdata(device);
        unsigned long flags = 0;
        u32 ctrl_reg;
-       struct tty_struct *tty;
-       struct device *tty_dev;
-       int may_wake = 0;
-
-       /* Get the tty which could be NULL so don't assume it's valid */
-       tty = tty_port_tty_get(&port->state->port);
-       if (tty) {
-               tty_dev = tty->dev;
-               may_wake = device_may_wakeup(tty_dev);
-               tty_kref_put(tty);
-       }
+       int may_wake;
+
+       may_wake = device_may_wakeup(device);
 
        if (console_suspend_enabled && !may_wake) {
                struct cdns_uart *cdns_uart = port->private_data;