提交 30cfa3eb 编写于 作者: N Nava kishore Manne 提交者: Greg Kroah-Hartman

serial: uartps: Fix suspend functionality

[ Upstream commit 4b9d33c6a30688344a3e95179654ea31b07f59b7 ]

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: NNava kishore Manne <navam@xilinx.com>
Signed-off-by: NMichal Simek <michal.simek@xilinx.com>
Signed-off-by: NGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: NSasha Levin <sashal@kernel.org>
上级 bad4e6d3
......@@ -1279,24 +1279,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);
......@@ -1311,7 +1298,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);
}
/**
......@@ -1325,17 +1316,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;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册