]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/commitdiff
serial: stm32: fix a deadlock in set_termios
authorErwan Le Ray <erwan.leray@foss.st.com>
Thu, 4 Mar 2021 16:23:02 +0000 (17:23 +0100)
committerKelsey Skunberg <kelsey.skunberg@canonical.com>
Mon, 24 May 2021 23:46:18 +0000 (17:46 -0600)
BugLink: https://bugs.launchpad.net/bugs/1929455
[ 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>
Signed-off-by: Kamal Mostafa <kamal@canonical.com>
Signed-off-by: Kelsey Skunberg <kelsey.skunberg@canonical.com>
drivers/tty/serial/stm32-usart.c

index 85e9a4d4e91d2ee165dfed05cf9bc0ad22d9cb17..44522ddc7e6dbece8fd529ccaca3156ddb959508 100644 (file)
@@ -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)