[PATCH] serial: 8250_port: Fix imprecise external abort for mctrl if inactive

From: Tony Lindgren
Date: Mon Jun 01 2020 - 20:18:25 EST


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