[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