[PATCH v2 1/3] serial: core: Forget the RS485 GPIO descriptors when a port is removed

From: Tapio Reijonen

Date: Thu Nov 05 2026 - 02:13:15 EST


The RS485 termination and RX-during-TX GPIO descriptors are acquired
with devm on behalf of the port's device in uart_get_rs485_mode() and
stored in struct uart_port, but nothing ever clears them. A uart_port
can outlive the device it was registered with: the 8250 core keeps its
ports in a static array, re-adds an unregistered entry as a placeholder
and hands it to the next device that claims the slot. If that device
has no RS485 support or no firmware node, uart_get_rs485_mode() returns
before acquiring anything and the stale descriptors stay in place,
pointing at lines that devres has already released. Enabling RS485 on
such a port then drives GPIO lines the port no longer owns. The same
happens when uart_get_rs485_mode() itself fails after the first
descriptor was acquired.

Forget the descriptors when a port is removed, on entry to
uart_get_rs485_mode() and on its error paths, so a port only ever
carries descriptors acquired for its current device.

Signed-off-by: Tapio Reijonen <tapio.reijonen@xxxxxxxxxxx>
---
drivers/tty/serial/serial_core.c | 28 ++++++++++++++++++++++++----
1 file changed, 24 insertions(+), 4 deletions(-)

diff --git a/drivers/tty/serial/serial_core.c b/drivers/tty/serial/serial_core.c
index c0deec0e6af41db10de15ccca4169c603d9cebf6..9516f50a72139c73d70826f4bb0627aed2d3d310 100644
--- a/drivers/tty/serial/serial_core.c
+++ b/drivers/tty/serial/serial_core.c
@@ -1415,6 +1415,17 @@ static void uart_sanitize_serial_rs485(struct uart_port *port, struct serial_rs4
memset(rs485->padding1, 0, sizeof(rs485->padding1));
}

+/*
+ * Drop the port's references to the RS485 GPIOs. Do not touch the
+ * descriptors themselves: they are devres-managed and may already have
+ * been released if the port struct outlived the device it was set up for.
+ */
+static void uart_forget_rs485_gpios(struct uart_port *port)
+{
+ port->rs485_term_gpio = NULL;
+ port->rs485_rx_during_tx_gpio = NULL;
+}
+
static void uart_set_rs485_termination(struct uart_port *port,
const struct serial_rs485 *rs485)
{
@@ -3265,6 +3276,7 @@ static void serial_core_remove_one_port(struct uart_driver *drv,
*/
uport->type = PORT_UNKNOWN;
uport->port_dev = NULL;
+ uart_forget_rs485_gpios(uport);

guard(mutex)(&port->mutex);
WARN_ON(atomic_dec_return(&state->refcount) < 0);
@@ -3579,6 +3591,8 @@ int uart_get_rs485_mode(struct uart_port *port)
u32 rs485_delay[2];
int ret;

+ uart_forget_rs485_gpios(port);
+
if (!(port->rs485_supported.flags & SER_RS485_ENABLED))
return 0;

@@ -3628,8 +3642,11 @@ int uart_get_rs485_mode(struct uart_port *port)
* Works fine for short cables and users may enable for longer cables.
*/
desc = devm_gpiod_get_optional(dev, "rs485-term", GPIOD_OUT_LOW);
- if (IS_ERR(desc))
- return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-term-gpios\n");
+ if (IS_ERR(desc)) {
+ uart_forget_rs485_gpios(port);
+ return dev_err_probe(dev, PTR_ERR(desc),
+ "Cannot get rs485-term-gpios\n");
+ }
port->rs485_term_gpio = desc;
if (port->rs485_term_gpio)
port->rs485_supported.flags |= SER_RS485_TERMINATE_BUS;
@@ -3637,8 +3654,11 @@ int uart_get_rs485_mode(struct uart_port *port)
dflags = (rs485conf->flags & SER_RS485_RX_DURING_TX) ?
GPIOD_OUT_HIGH : GPIOD_OUT_LOW;
desc = devm_gpiod_get_optional(dev, "rs485-rx-during-tx", dflags);
- if (IS_ERR(desc))
- return dev_err_probe(dev, PTR_ERR(desc), "Cannot get rs485-rx-during-tx-gpios\n");
+ if (IS_ERR(desc)) {
+ uart_forget_rs485_gpios(port);
+ return dev_err_probe(dev, PTR_ERR(desc),
+ "Cannot get rs485-rx-during-tx-gpios\n");
+ }
port->rs485_rx_during_tx_gpio = desc;
if (port->rs485_rx_during_tx_gpio)
port->rs485_supported.flags |= SER_RS485_RX_DURING_TX;

--
2.47.3