Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 4b9d33c6 authored by Nava kishore Manne's avatar Nava kishore Manne Committed by Greg Kroah-Hartman
Browse files

serial: uartps: Fix suspend functionality



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: default avatarNava kishore Manne <navam@xilinx.com>
Signed-off-by: default avatarMichal Simek <michal.simek@xilinx.com>
Signed-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 77ec669f
Loading
Loading
Loading
Loading
+12 −29
Original line number Diff line number Diff line
@@ -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;
	int may_wake;

	/* 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);
	}
	may_wake = device_may_wakeup(device);

	/*
	 * 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)) {
	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;
	int may_wake;

	/* 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);
	}
	may_wake = device_may_wakeup(device);

	if (console_suspend_enabled && !may_wake) {
		struct cdns_uart *cdns_uart = port->private_data;