This is a note to let you know that I've just added the patch titled serial: stm32: prevent TDR register overwrite when sending x_char to the 5.16-stable tree which can be found at: http://www.kernel.org/git/?p=linux/kernel/git/stable/stable-queue.git;a=summary The filename of the patch is: serial-stm32-prevent-tdr-register-overwrite-when-sen.patch and it can be found in the queue-5.16 subdirectory. If you, or anyone else, feels it should not be added to the stable tree, please let <stable@xxxxxxxxxxxxxxx> know about it. commit 36807348826799579605d1c23d7af6b7b253d0fa Author: Valentin Caron <valentin.caron@xxxxxxxxxxx> Date: Tue Jan 11 17:44:40 2022 +0100 serial: stm32: prevent TDR register overwrite when sending x_char [ Upstream commit d3d079bde07e1b7deaeb57506dc0b86010121d17 ] When sending x_char in stm32_usart_transmit_chars(), driver can overwrite the value of TDR register by the value of x_char. If this happens, the previous value that was present in TDR register will not be sent through uart. This code checks if the previous value in TDR register is sent before writing the x_char value into register. Fixes: 48a6092fb41f ("serial: stm32-usart: Add STM32 USART Driver") Cc: stable <stable@xxxxxxxxxxxxxxx> Signed-off-by: Valentin Caron <valentin.caron@xxxxxxxxxxx> Link: https://lore.kernel.org/r/20220111164441.6178-2-valentin.caron@xxxxxxxxxxx Signed-off-by: Greg Kroah-Hartman <gregkh@xxxxxxxxxxxxxxxxxxx> Signed-off-by: Sasha Levin <sashal@xxxxxxxxxx> diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c index 2d3fbcbfaf108..93c2a5c956540 100644 --- a/drivers/tty/serial/stm32-usart.c +++ b/drivers/tty/serial/stm32-usart.c @@ -520,10 +520,22 @@ static void stm32_usart_transmit_chars(struct uart_port *port) struct stm32_port *stm32_port = to_stm32_port(port); const struct stm32_usart_offsets *ofs = &stm32_port->info->ofs; struct circ_buf *xmit = &port->state->xmit; + u32 isr; + int ret; if (port->x_char) { if (stm32_port->tx_dma_busy) stm32_usart_clr_bits(port, ofs->cr3, USART_CR3_DMAT); + + /* Check that TDR is empty before filling FIFO */ + ret = + readl_relaxed_poll_timeout_atomic(port->membase + ofs->isr, + isr, + (isr & USART_SR_TXE), + 10, 1000); + if (ret) + dev_warn(port->dev, "1 character may be erased\n"); + writel_relaxed(port->x_char, port->membase + ofs->tdr); port->x_char = 0; port->icount.tx++;