serial: amba-pl011: fix indefinite RS485 post-send delay

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: 2c1fd53af2 ("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>
This commit is contained in:
Fan Wu 2026-07-31 08:59:13 +00:00 committed by Greg Kroah-Hartman
parent a7ad003445
commit dcb2f7576c

View 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);