[linux-yocto] [PATCH 06/15] serial: core: add support of runtime PM
Nilesh Bacchewar
nilesh.bacchewar at intel.com
Thu Nov 17 15:06:22 PST 2016
From: Andy Shevchenko <andriy.shevchenko at linux.intel.com>
Backport:
- Upstream-Status: Pending.
- Backport fix.
[https://bitbucket.org/andy-shev/linux/commits/8517d7ba8853e79bf2f4583b1653526d2927dbf2?at=master]
Should be cleaned up and split at least to two patches.
One is preventing warning from static analyzers (unbalanced lock).
Signed-off-by: Andy Shevchenko <andriy.shevchenko at linux.intel.com>
Signed-off-by: Nilesh Bacchewar <nilesh.bacchewar at intel.com>
---
drivers/tty/serial/serial_core.c | 73 +++++++++++++++++++++++++++++++++++++++-
1 file changed, 72 insertions(+), 1 deletion(-)
diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index 84c26d5..b3b11c4 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -34,6 +34,7 @@
#include <linux/serial_core.h>
#include <linux/delay.h>
#include <linux/mutex.h>
+#include <linux/pm_runtime.h>
#include <asm/irq.h>
#include <asm/uaccess.h>
@@ -116,12 +117,15 @@ uart_update_mctrl(struct uart_port *port, unsigned int set, unsigned int clear)
unsigned long flags;
unsigned int old;
+ pm_runtime_get_sync(port->dev);
spin_lock_irqsave(&port->lock, flags);
old = port->mctrl;
port->mctrl = (old & ~clear) | set;
if (old != port->mctrl)
port->ops->set_mctrl(port, port->mctrl);
spin_unlock_irqrestore(&port->lock, flags);
+ pm_runtime_mark_last_busy(port->dev);
+ pm_runtime_put_autosuspend(port->dev);
}
#define uart_set_mctrl(port, set) uart_update_mctrl(port, set, 0)
@@ -160,7 +164,11 @@ static int uart_port_startup(struct tty_struct *tty, struct uart_state *state,
uart_circ_clear(&state->xmit);
}
+ pm_runtime_get_sync(uport->dev);
retval = uport->ops->startup(uport);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
+
if (retval == 0) {
if (uart_console(uport) && uport->cons->cflag) {
tty->termios.c_cflag = uport->cons->cflag;
@@ -455,6 +463,8 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
return;
termios = &tty->termios;
+
+ pm_runtime_get_sync(uport->dev);
uport->ops->set_termios(uport, termios, old_termios);
/*
@@ -483,6 +493,8 @@ static void uart_change_speed(struct tty_struct *tty, struct uart_state *state,
__uart_start(tty);
}
spin_unlock_irq(&uport->lock);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
}
static inline int __uart_put_char(struct uart_port *port,
@@ -955,7 +967,10 @@ static int uart_get_lsr_info(struct tty_struct *tty,
struct uart_port *uport = state->uart_port;
unsigned int result;
+ pm_runtime_get_sync(uport->dev);
result = uport->ops->tx_empty(uport);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
/*
* If we're about to load something into the transmit
@@ -981,9 +996,13 @@ static int uart_tiocmget(struct tty_struct *tty)
mutex_lock(&port->mutex);
if (!(tty->flags & (1 << TTY_IO_ERROR))) {
result = uport->mctrl;
+
+ pm_runtime_get_sync(uport->dev);
spin_lock_irq(&uport->lock);
result |= uport->ops->get_mctrl(uport);
spin_unlock_irq(&uport->lock);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
}
mutex_unlock(&port->mutex);
@@ -1015,9 +1034,13 @@ static int uart_break_ctl(struct tty_struct *tty, int break_state)
mutex_lock(&port->mutex);
+ pm_runtime_get_sync(uport->dev);
if (uport->type != PORT_UNKNOWN)
uport->ops->break_ctl(uport, break_state);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
+
mutex_unlock(&port->mutex);
return 0;
}
@@ -1058,7 +1081,10 @@ static int uart_do_autoconfig(struct tty_struct *tty,struct uart_state *state)
* This will claim the ports resources if
* a port is found.
*/
+ pm_runtime_get_sync(uport->dev);
uport->ops->config_port(uport, flags);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
ret = uart_startup(tty, state, 1);
}
@@ -1309,7 +1335,10 @@ static void uart_set_ldisc(struct tty_struct *tty)
if (uport->ops->set_ldisc) {
mutex_lock(&state->port.mutex);
+ pm_runtime_get_sync(uport->dev);
uport->ops->set_ldisc(uport, &tty->termios);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
mutex_unlock(&state->port.mutex);
}
}
@@ -1546,7 +1575,10 @@ static void uart_port_shutdown(struct tty_port *port)
/*
* Free the IRQ and disable the port.
*/
+ pm_runtime_get_sync(uport->dev);
uport->ops->shutdown(uport);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
/*
* Ensure that the IRQ handler isn't running on another CPU.
@@ -1690,9 +1722,12 @@ static void uart_line_info(struct seq_file *m, struct uart_driver *drv, int i)
pm_state = state->pm_state;
if (pm_state != UART_PM_STATE_ON)
uart_change_pm(state, UART_PM_STATE_ON);
+ pm_runtime_get_sync(uport->dev);
spin_lock_irq(&uport->lock);
status = uport->ops->get_mctrl(uport);
spin_unlock_irq(&uport->lock);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
if (pm_state != UART_PM_STATE_ON)
uart_change_pm(state, pm_state);
mutex_unlock(&port->mutex);
@@ -1976,7 +2011,15 @@ uart_set_options(struct uart_port *port, struct console *co,
*/
port->mctrl |= TIOCM_DTR;
- port->ops->set_termios(port, &termios, &dummy);
+ /* At early stage device is not created yet, we can't do PM */
+ if (port->dev) {
+ pm_runtime_get_sync(port->dev);
+ port->ops->set_termios(port, &termios, &dummy);
+ pm_runtime_mark_last_busy(port->dev);
+ pm_runtime_put_autosuspend(port->dev);
+ } else
+ port->ops->set_termios(port, &termios, &dummy);
+
/*
* Allow the setting of the UART parameters with a NULL console
* too:
@@ -2056,11 +2099,14 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
set_bit(ASYNCB_SUSPENDED, &port->flags);
clear_bit(ASYNCB_INITIALIZED, &port->flags);
+ pm_runtime_get_sync(uport->dev);
spin_lock_irq(&uport->lock);
ops->stop_tx(uport);
ops->set_mctrl(uport, 0);
ops->stop_rx(uport);
spin_unlock_irq(&uport->lock);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
/*
* Wait for the transmitter to empty.
@@ -2072,7 +2118,10 @@ int uart_suspend_port(struct uart_driver *drv, struct uart_port *uport)
drv->dev_name,
drv->tty_driver->name_base + uport->line);
+ pm_runtime_get_sync(uport->dev);
ops->shutdown(uport);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
}
/*
@@ -2129,7 +2178,12 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
if (console_suspend_enabled)
uart_change_pm(state, UART_PM_STATE_ON);
+
+ pm_runtime_get_sync(uport->dev);
uport->ops->set_termios(uport, &termios, NULL);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
+
if (console_suspend_enabled)
console_start(uport->cons);
}
@@ -2139,20 +2193,31 @@ int uart_resume_port(struct uart_driver *drv, struct uart_port *uport)
int ret;
uart_change_pm(state, UART_PM_STATE_ON);
+ pm_runtime_get_sync(uport->dev);
spin_lock_irq(&uport->lock);
ops->set_mctrl(uport, 0);
spin_unlock_irq(&uport->lock);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
+
if (console_suspend_enabled || !uart_console(uport)) {
/* Protected by port mutex for now */
struct tty_struct *tty = port->tty;
+
+ pm_runtime_get_sync(uport->dev);
ret = ops->startup(uport);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
if (ret == 0) {
if (tty)
uart_change_speed(tty, state, NULL);
+ pm_runtime_get_sync(uport->dev);
spin_lock_irq(&uport->lock);
ops->set_mctrl(uport, uport->mctrl);
ops->start_tx(uport);
spin_unlock_irq(&uport->lock);
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
set_bit(ASYNCB_INITIALIZED, &port->flags);
} else {
/*
@@ -2246,9 +2311,12 @@ uart_configure_port(struct uart_driver *drv, struct uart_state *state,
* keep the DTR setting that is set in uart_set_options()
* We probably don't need a spinlock around this, but
*/
+ pm_runtime_get_sync(port->dev);
spin_lock_irqsave(&port->lock, flags);
port->ops->set_mctrl(port, port->mctrl & TIOCM_DTR);
spin_unlock_irqrestore(&port->lock, flags);
+ pm_runtime_mark_last_busy(port->dev);
+ pm_runtime_put_autosuspend(port->dev);
/*
* If this driver supports console, and it hasn't been
@@ -2890,6 +2958,7 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->icount.cts++;
if (uart_softcts_mode(uport)) {
+ pm_runtime_get_sync(uport->dev);
if (uport->hw_stopped) {
if (status) {
uport->hw_stopped = 0;
@@ -2902,6 +2971,8 @@ void uart_handle_cts_change(struct uart_port *uport, unsigned int status)
uport->ops->stop_tx(uport);
}
}
+ pm_runtime_mark_last_busy(uport->dev);
+ pm_runtime_put_autosuspend(uport->dev);
}
}
--
1.9.1
More information about the linux-yocto
mailing list