[PATCH v6 5/9] serial: max310x: wait for TX to drain before powering down in shutdown
From: Tapio Reijonen
Date: Sun Oct 04 2026 - 08:21:59 EST
max310x_tx_empty() reports the chip TX FIFO level and nothing else, so
both tcdrain() and the tty layer's wait-until-sent on close() return
while the final character is still clocking out of the transmit shift
register. max310x_shutdown() then powers the port down mid-character
and the last byte is truncated on the wire. At 9600 baud the ~1 ms
window is easy to miss; at 1200 baud a write()-then-close() reliably
corrupts the final byte (observed on the wire: 0x24 transmitted as a
0x04 frame with a framing error).
Wait in shutdown() for the FIFO to drain, bounded by one character
duration per FIFO word, plus one more character for the byte in the
shift register, before powering the port down. The per-character
duration is computed in set_termios() from the frame size and baud
rate.
Fixes: f65444187a66 ("serial: New serial driver MAX310X")
Assisted-by: Claude:claude-fable-5
Signed-off-by: Tapio Reijonen <tapio.reijonen@xxxxxxxxxxx>
---
drivers/tty/serial/max310x.c | 25 +++++++++++++++++++++++--
1 file changed, 23 insertions(+), 2 deletions(-)
diff --git a/drivers/tty/serial/max310x.c b/drivers/tty/serial/max310x.c
index 2456a2af891f5296cfec833d6406916073d2865f..9dcc817b9794537385aa9ca726cb1cc1b2af6b4c 100644
--- a/drivers/tty/serial/max310x.c
+++ b/drivers/tty/serial/max310x.c
@@ -302,6 +302,7 @@ struct max310x_one {
struct work_struct md_work;
struct work_struct rs_work;
struct regmap *regmap;
+ unsigned int char_time_us;
unsigned int baud;
bool tx_break; /* break_ctl() owns the transceiver */
@@ -1012,6 +1013,7 @@ static void max310x_set_termios(struct uart_port *port,
struct ktermios *termios,
const struct ktermios *old)
{
+ unsigned int frame_bits = tty_get_frame_size(termios->c_cflag);
unsigned int lcr = 0, flow = 0;
int baud;
@@ -1124,10 +1126,13 @@ static void max310x_set_termios(struct uart_port *port,
uart_update_timeout(port, termios->c_cflag, baud);
/*
- * Cache the new baud rate and reprogram the RS485 RTS delays, whose
- * millisecond-to-bit-time conversion depends on it.
+ * Cache the new baud rate and the time it takes to clock out one
+ * character before reprogramming the RS485 RTS delays: the
+ * millisecond-to-bit-time conversion divides by the baud rate.
*/
to_max310x_port(port)->baud = baud;
+ to_max310x_port(port)->char_time_us =
+ DIV_ROUND_UP(USEC_PER_SEC * frame_bits, baud);
max310x_set_rts_ctl_params(to_max310x_port(port));
}
@@ -1223,6 +1228,22 @@ static int max310x_startup(struct uart_port *port)
static void max310x_shutdown(struct uart_port *port)
{
+ struct max310x_one *one = to_max310x_port(port);
+ unsigned int tries = port->fifosize + 1;
+
+ /*
+ * The tty layer's wait-until-sent is bounded by closing_wait, which
+ * can be configured to none, and a hangup reaches here with no wait
+ * at all, so the FIFO may still hold anything up to its full size.
+ * tx_empty() also only reflects the chip TX FIFO - the last character
+ * may still be in the transmit shift register. Let the FIFO drain and
+ * the final character clock out before the port is powered down,
+ * otherwise the transfer is truncated on the wire.
+ */
+ while (!max310x_tx_empty(port) && tries-- > 0)
+ fsleep(one->char_time_us);
+ fsleep(one->char_time_us);
+
/* Disable all interrupts */
max310x_port_write(port, MAX310X_IRQEN_REG, 0);
--
2.47.3