We can get an imprecise external abort on uart_shutdown() at serial8250_do_set_mctrl() if the UART is autoidled. We don't want to add PM runtime calls to serial8250_do_set_mctrl() beyond checking the usage count as it gets called from interrupts disabled and spinlock held from uart_update_mctrl(). We can just bail out early from serial8250_do_set_mctrl() if the UART is inactive. We have uart_shutdown() call uart_port_dtr_rts() with value of 0 just to disable DTR and RTS. Cc: Andy Shevchenko <andriy.shevchenko@xxxxxxxxxxxxxxx> Cc: Merlijn Wajer <merlijn@xxxxxxxxxx> Cc: Pavel Machek <pavel@xxxxxx> Cc: Sebastian Reichel <sre@xxxxxxxxxx> Cc: Vignesh Raghavendra <vigneshr@xxxxxx> Signed-off-by: Tony Lindgren <tony@xxxxxxxxxxx> --- drivers/tty/serial/8250/8250_port.c | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/drivers/tty/serial/8250/8250_port.c b/drivers/tty/serial/8250/8250_port.c --- a/drivers/tty/serial/8250/8250_port.c +++ b/drivers/tty/serial/8250/8250_port.c @@ -2001,11 +2001,20 @@ static unsigned int serial8250_get_mctrl(struct uart_port *port) return serial8250_do_get_mctrl(port); } +/* + * Called from uart_update_mctrl() with spinlock held, so we don't want + * add PM runtime calls here beyond checking the usage count. If the + * UART is not active, we can just bail out early. + */ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) { struct uart_8250_port *up = up_to_u8250p(port); unsigned char mcr; + if (up->capabilities & UART_CAP_RPM && + !pm_runtime_get_if_in_use(up->port.dev)) + return; + if (port->rs485.flags & SER_RS485_ENABLED) { if (serial8250_in_MCR(up) & UART_MCR_RTS) mctrl |= TIOCM_RTS; @@ -2018,6 +2027,9 @@ void serial8250_do_set_mctrl(struct uart_port *port, unsigned int mctrl) mcr = (mcr & up->mcr_mask) | up->mcr_force | up->mcr; serial8250_out_MCR(up, mcr); + + if (up->capabilities & UART_CAP_RPM) + pm_runtime_put(up->port.dev); } EXPORT_SYMBOL_GPL(serial8250_do_set_mctrl); -- 2.26.2