serial: max310x: fix breaks not reaching the wire in RS485 mode

The chip's auto-RTS (MODE1.TRNSCVCTRL) asserts the RS485 transceiver
only while FIFO data is shifting out, and a break is not FIFO data: on
an RS485 port a requested break sets the TX break bit but the
transceiver is never enabled, so the break never reaches the wire.
Break-led protocols cannot work at all.

Disable auto-RTS for the break duration and drive RTS manually via the
LCR RTS bit, then restore auto-RTS when the break ends. Track the break
in tx_break and leave MODE1 alone in the rs485-config worker while it
is set - a TIOCSRS485 arriving mid-break would otherwise re-enable
auto-RTS on top of the manual RTS and release the transceiver before
the break ends; break_ctl() restores auto-RTS from the then-current
configuration when the break completes. The worker runs under
port->mutex - break_ctl() and set_termios() already do - so the
tx_break test and the MODE1 write cannot straddle a break starting or
ending, and startup() clears tx_break alongside the latched TXBREAK
bit, since a port can be closed with a break still asserted.

Only the break assertion is gated on RS485 being enabled; the restore
at break end runs unconditionally and derives MODE1 from the current
configuration. Returning early for a port whose RS485 was disabled
mid-break - that reconfigure is deferred like any other - would leak
the manually driven RTS and leave the transceiver holding the bus
indefinitely after the break ends. On a non-RS485 port the restore is
a no-op: nothing else writes the LCR RTS bit.

Fixes: 55367c620a ("serial: max310x: Add support for RS-485 mode")
Assisted-by: Claude:claude-fable-5
Signed-off-by: Tapio Reijonen <tapio.reijonen@vaisala.com>
Link: https://patch.msgid.link/20261008-max310x-rs485-sw-delay-v8-2-6ba881f81e1f@vaisala.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
This commit is contained in:
Tapio Reijonen 2026-10-08 09:48:25 +00:00 committed by Greg Kroah-Hartman
parent 3b2de448ec
commit 4efacb600b

View File

@ -296,6 +296,7 @@ struct max310x_one {
struct work_struct md_work;
struct work_struct rs_work;
struct regmap *regmap;
bool tx_break; /* break_ctl() owns the transceiver */
u8 rx_buf[MAX310X_FIFO_SIZE];
};
@ -680,6 +681,12 @@ static void max310x_batch_read(struct uart_port *port, u8 *rxbuf, unsigned int l
regmap_noinc_read(one->regmap, MAX310X_RHR_REG, rxbuf, len);
}
static void max310x_rts_ctl(struct uart_port *port, bool rts_state)
{
max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_RTS_BIT,
rts_state ? MAX310X_LCR_RTS_BIT : 0);
}
static void max310x_handle_rx(struct uart_port *port, unsigned int rxlen)
{
struct max310x_one *one = to_max310x_port(port);
@ -927,9 +934,32 @@ static void max310x_set_mctrl(struct uart_port *port, unsigned int mctrl)
static void max310x_break_ctl(struct uart_port *port, int break_state)
{
struct max310x_one *one = to_max310x_port(port);
one->tx_break = break_state;
max310x_port_update(port, MAX310X_LCR_REG,
MAX310X_LCR_TXBREAK_BIT,
break_state ? MAX310X_LCR_TXBREAK_BIT : 0);
/*
* The chip's auto-RTS asserts the transceiver only while FIFO data is
* shifting out, and a break is not FIFO data. Disable auto-RTS for the
* break duration and drive RTS manually so the break reaches the wire;
* restore auto-RTS when the break ends.
*/
if (break_state) {
if (!(port->rs485.flags & SER_RS485_ENABLED))
return;
max310x_port_update(port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT, 0);
} else {
max310x_port_update(port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT,
(port->rs485.flags & SER_RS485_ENABLED) ?
MAX310X_MODE1_TRNSCVCTRL_BIT : 0);
}
max310x_rts_ctl(port, break_state);
}
static void max310x_set_termios(struct uart_port *port,
@ -1053,6 +1083,13 @@ static void max310x_rs_proc(struct work_struct *ws)
struct max310x_one *one = container_of(ws, struct max310x_one, rs_work);
unsigned int delay, mode1 = 0, mode2 = 0;
/*
* Serialize against break_ctl() and set_termios(), which run under
* port->mutex: the tx_break test below and the MODE1 write must not
* straddle a break starting or ending.
*/
guard(mutex)(&one->port.state->port.mutex);
delay = (one->port.rs485.delay_rts_before_send << 4) |
one->port.rs485.delay_rts_after_send;
max310x_port_write(&one->port, MAX310X_HDPIXDELAY_REG, delay);
@ -1064,8 +1101,14 @@ static void max310x_rs_proc(struct work_struct *ws)
mode2 = MAX310X_MODE2_ECHOSUPR_BIT;
}
max310x_port_update(&one->port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
/*
* A break owns the transceiver: break_ctl() disabled auto-RTS and
* drives RTS manually, and restores it when the break ends. Leave
* MODE1 alone meanwhile or the break goes undriven mid-way.
*/
if (!one->tx_break)
max310x_port_update(&one->port, MAX310X_MODE1_REG,
MAX310X_MODE1_TRNSCVCTRL_BIT, mode1);
max310x_port_update(&one->port, MAX310X_MODE2_REG,
MAX310X_MODE2_ECHOSUPR_BIT, mode2);
}
@ -1088,6 +1131,7 @@ static int max310x_rs485_config(struct uart_port *port, struct ktermios *termios
static int max310x_startup(struct uart_port *port)
{
struct max310x_one *one = to_max310x_port(port);
unsigned int val;
max310x_power(port, 1);
@ -1097,6 +1141,7 @@ static int max310x_startup(struct uart_port *port)
* closed with a break still asserted, and set_termios() no longer
* rewrites it.
*/
one->tx_break = false;
max310x_port_update(port, MAX310X_LCR_REG, MAX310X_LCR_TXBREAK_BIT, 0);
/* Configure MODE1 register */