| From 1b90fadcc21c175df62ba72ff1fc78d932715d52 Mon Sep 17 00:00:00 2001 |
| From: Sasha Levin <sashal@kernel.org> |
| Date: Thu, 4 Mar 2021 17:23:02 +0100 |
| Subject: serial: stm32: fix a deadlock in set_termios |
| |
| From: Erwan Le Ray <erwan.leray@foss.st.com> |
| |
| [ Upstream commit 436c97936001776f16153771ee887f125443e974 ] |
| |
| CTS/RTS GPIOs support that has been added recently to STM32 UART driver has |
| introduced scheduled code in a set_termios part protected by a spin lock. |
| This generates a potential deadlock scenario: |
| |
| Chain exists of: |
| &irq_desc_lock_class --> console_owner --> &port_lock_key |
| |
| Possible unsafe locking scenario: |
| |
| CPU0 CPU1 |
| ---- ---- |
| lock(&port_lock_key); |
| lock(console_owner); |
| lock(&port_lock_key); |
| lock(&irq_desc_lock_class); |
| |
| *** DEADLOCK *** |
| 4 locks held by stty/766: |
| |
| Move the scheduled code after the spinlock. |
| |
| Fixes: 6cf61b9bd7cc ("tty: serial: Add modem control gpio support for STM32 UART") |
| Signed-off-by: Erwan Le Ray <erwan.leray@foss.st.com> |
| Link: https://lore.kernel.org/r/20210304162308.8984-8-erwan.leray@foss.st.com |
| Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> |
| Signed-off-by: Sasha Levin <sashal@kernel.org> |
| --- |
| drivers/tty/serial/stm32-usart.c | 12 ++++++------ |
| 1 file changed, 6 insertions(+), 6 deletions(-) |
| |
| diff --git a/drivers/tty/serial/stm32-usart.c b/drivers/tty/serial/stm32-usart.c |
| index 85e9a4d4e91d..44522ddc7e6d 100644 |
| --- a/drivers/tty/serial/stm32-usart.c |
| +++ b/drivers/tty/serial/stm32-usart.c |
| @@ -827,12 +827,6 @@ static void stm32_usart_set_termios(struct uart_port *port, |
| cr3 |= USART_CR3_CTSE | USART_CR3_RTSE; |
| } |
| |
| - /* Handle modem control interrupts */ |
| - if (UART_ENABLE_MS(port, termios->c_cflag)) |
| - stm32_usart_enable_ms(port); |
| - else |
| - stm32_usart_disable_ms(port); |
| - |
| usartdiv = DIV_ROUND_CLOSEST(port->uartclk, baud); |
| |
| /* |
| @@ -914,6 +908,12 @@ static void stm32_usart_set_termios(struct uart_port *port, |
| |
| stm32_usart_set_bits(port, ofs->cr1, BIT(cfg->uart_enable_bit)); |
| spin_unlock_irqrestore(&port->lock, flags); |
| + |
| + /* Handle modem control interrupts */ |
| + if (UART_ENABLE_MS(port, termios->c_cflag)) |
| + stm32_usart_enable_ms(port); |
| + else |
| + stm32_usart_disable_ms(port); |
| } |
| |
| static const char *stm32_usart_type(struct uart_port *port) |
| -- |
| 2.30.2 |
| |