]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
serial: amba-pl011: fix indefinite RS485 post-send delay
authorFan Wu <fanwu01@zju.edu.cn>
Fri, 31 Jul 2026 08:59:13 +0000 (08:59 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Mon, 3 Aug 2026 14:31:15 +0000 (16:31 +0200)
The RS485 stop hrtimer is used both to drain the transmitter and to wait
out delay_rts_after_send. The callback cannot tell the two apart, so it
restarts the post-send delay on every expiry and the timer never stops.

Add a WAIT_AFTER_SEND_DELAY state so its expiry ends the stop sequence
instead of restarting the delay.

Fixes: 2c1fd53af21b ("serial: amba-pl011: Fix RTS handling in RS485 mode")
Cc: stable <stable@kernel.org>
Assisted-by: Codex:gpt-5.6
Signed-off-by: Fan Wu <fanwu01@zju.edu.cn>
Link: https://patch.msgid.link/20260731085915.326775-2-fanwu01@zju.edu.cn
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/tty/serial/amba-pl011.c

index 8ed91e1da22be8895686e51d44826aca96ba3206..d88c1242e6d880e543790714c90ae7ab9e3163c2 100644 (file)
@@ -309,6 +309,7 @@ enum pl011_rs485_tx_state {
        WAIT_AFTER_RTS,
        SEND,
        WAIT_AFTER_SEND,
+       WAIT_AFTER_SEND_DELAY,
 };
 
 /*
@@ -1350,6 +1351,7 @@ static void pl011_rs485_tx_stop(struct uart_amba_port *uap)
                        return;
                }
                if (port->rs485.delay_rts_after_send > 0) {
+                       uap->rs485_tx_state = WAIT_AFTER_SEND_DELAY;
                        hrtimer_start(&uap->trigger_stop_tx,
                                      ms_to_ktime(port->rs485.delay_rts_after_send),
                                      HRTIMER_MODE_REL);
@@ -1415,7 +1417,8 @@ static void pl011_rs485_tx_start(struct uart_amba_port *uap)
                uap->rs485_tx_state = SEND;
                return;
        }
-       if (uap->rs485_tx_state == WAIT_AFTER_SEND) {
+       if (uap->rs485_tx_state == WAIT_AFTER_SEND ||
+           uap->rs485_tx_state == WAIT_AFTER_SEND_DELAY) {
                hrtimer_try_to_cancel(&uap->trigger_stop_tx);
                uap->rs485_tx_state = SEND;
                return;
@@ -1482,7 +1485,8 @@ static enum hrtimer_restart pl011_trigger_stop_tx(struct hrtimer *t)
        unsigned long flags;
 
        uart_port_lock_irqsave(&uap->port, &flags);
-       if (uap->rs485_tx_state == WAIT_AFTER_SEND)
+       if (uap->rs485_tx_state == WAIT_AFTER_SEND ||
+           uap->rs485_tx_state == WAIT_AFTER_SEND_DELAY)
                pl011_rs485_tx_stop(uap);
        uart_port_unlock_irqrestore(&uap->port, flags);