This is an automated email from the ASF dual-hosted git repository. xiaoxiang781216 pushed a commit to branch releases/13.1 in repository https://gitbox.apache.org/repos/asf/nuttx.git
commit 39f3447bbde17328662f11692acf75273f6e4679 Author: Marco Casaroli <[email protected]> AuthorDate: Sun Oct 11 20:14:13 2026 +0200 drivers/serial/uart_pl011.c: Send the TX buffer with interrupts disabled. pl011_txint() enabled the TX interrupt and then called uart_xmitchars() with interrupts enabled. uart_write() calls it from a task, so the TX interrupt could run uart_xmitchars() in the middle of that call. Both moved xmit.tail, the tail passed the head, and the driver sent the whole TX buffer again: on the console, a program that echoed each key printed the last 256 bytes of output again with each key. Call uart_xmitchars() in a critical section, as uart_16550.c does. The spinlock still covers only the register access. Assisted-by: Claude Code:claude-opus-5-5 Signed-off-by: Marco Casaroli <[email protected]> --- drivers/serial/uart_pl011.c | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/drivers/serial/uart_pl011.c b/drivers/serial/uart_pl011.c index f89ad19c9fc..4583343a075 100644 --- a/drivers/serial/uart_pl011.c +++ b/drivers/serial/uart_pl011.c @@ -743,17 +743,24 @@ static void pl011_txint(FAR struct uart_dev_s *dev, bool enable) FAR struct pl011_uart_port_s *sport = dev->priv; irqstate_t flags; - flags = spin_lock_irqsave(&sport->lock); - if (enable) { + /* Fake a TX interrupt with interrupts disabled, so that the TX + * interrupt cannot run uart_xmitchars() during this call. + */ + + flags = enter_critical_section(); + + spin_lock(&sport->lock); pl011_irq_tx_enable(sport); - spin_unlock_irqrestore(&sport->lock, flags); + spin_unlock(&sport->lock); uart_xmitchars(dev); + leave_critical_section(flags); } else { + flags = spin_lock_irqsave(&sport->lock); pl011_irq_tx_disable(sport); spin_unlock_irqrestore(&sport->lock, flags); }
