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: Nava kishore Manne <navam@xilinx.com> Signed-off-by: Michal Simek <michal.simek@xilinx.com> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
parent
77ec669f25
commit
4b9d33c6a3
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user