From 9169ff6a15fe65ba4af134b470dbf89220274c19 Mon Sep 17 00:00:00 2001 From: Jussi Kivilinna Date: Wed, 17 May 2017 06:50:46 -0600 Subject: [PATCH] stm32_serial: fix freezing serial port. Serial interrupt enable/disable functions do not disable interrupts and can freeze device when serial interrupt is received while execution is at those functions. Trivially triggered with two or more threads write to regular syslog stream and to emergency stream. In this case, freeze happens because of mismatch of priv->ie (TXEIE == 0) and actually enabled interrupts in USART registers (TXEIE == 1), which leads to unhandled TXE interrupt and causes interrupt storm for USART. --- arch/arm/src/stm32/stm32_serial.c | 29 +++++++++++++++++++---- arch/arm/src/stm32f0/stm32f0_serial.c | 32 +++++++++++++++++++++---- arch/arm/src/stm32f7/stm32_serial.c | 30 +++++++++++++++++++---- arch/arm/src/stm32l4/stm32l4_serial.c | 34 ++++++++++++++++++++++----- 4 files changed, 106 insertions(+), 19 deletions(-) diff --git a/arch/arm/src/stm32/stm32_serial.c b/arch/arm/src/stm32/stm32_serial.c index 77c07ea68e0..7aa362c38f5 100644 --- a/arch/arm/src/stm32/stm32_serial.c +++ b/arch/arm/src/stm32/stm32_serial.c @@ -1050,10 +1050,10 @@ static inline void up_serialout(struct up_dev_s *priv, int offset, uint32_t valu } /**************************************************************************** - * Name: up_restoreusartint + * Name: up_setusartint ****************************************************************************/ -static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie) +static inline void up_setusartint(struct up_dev_s *priv, uint16_t ie) { uint32_t cr; @@ -1074,12 +1074,31 @@ static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie) up_serialout(priv, STM32_USART_CR3_OFFSET, cr); } +/**************************************************************************** + * Name: up_restoreusartint + ****************************************************************************/ + +static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + up_setusartint(priv, ie); + + leave_critical_section(flags); +} + /**************************************************************************** * Name: up_disableusartint ****************************************************************************/ -static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie) +static void up_disableusartint(struct up_dev_s *priv, uint16_t *ie) { + irqstate_t flags; + + flags = enter_critical_section(); + if (ie) { uint32_t cr1; @@ -1116,7 +1135,9 @@ static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie) /* Disable all interrupts */ - up_restoreusartint(priv, 0); + up_setusartint(priv, 0); + + leave_critical_section(flags); } /**************************************************************************** diff --git a/arch/arm/src/stm32f0/stm32f0_serial.c b/arch/arm/src/stm32f0/stm32f0_serial.c index f0975fad2ca..788967c231d 100644 --- a/arch/arm/src/stm32f0/stm32f0_serial.c +++ b/arch/arm/src/stm32f0/stm32f0_serial.c @@ -769,10 +769,10 @@ static inline void stm32f0serial_putreg(FAR struct stm32f0_serial_s *priv, } /**************************************************************************** - * Name: stm32f0serial_restoreusartint + * Name: stm32f0serial_setusartint ****************************************************************************/ -static void stm32f0serial_restoreusartint(FAR struct stm32f0_serial_s *priv, +static void stm32f0serial_setusartint(FAR struct stm32f0_serial_s *priv, uint16_t ie) { uint32_t cr; @@ -794,13 +794,33 @@ static void stm32f0serial_restoreusartint(FAR struct stm32f0_serial_s *priv, stm32f0serial_putreg(priv, STM32F0_USART_CR3_OFFSET, cr); } +/**************************************************************************** + * Name: stm32f0serial_restoreusartint + ****************************************************************************/ + +static void stm32f0serial_restoreusartint(FAR struct stm32f0_serial_s *priv, + uint16_t ie) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + stm32f0serial_setusartint(priv, ie); + + leave_critical_section(flags); +} + /**************************************************************************** * Name: stm32f0serial_disableusartint ****************************************************************************/ -static inline void stm32f0serial_disableusartint(FAR struct stm32f0_serial_s *priv, - FAR uint16_t *ie) +static void stm32f0serial_disableusartint(FAR struct stm32f0_serial_s *priv, + FAR uint16_t *ie) { + irqstate_t flags; + + flags = enter_critical_section(); + if (ie) { uint32_t cr1; @@ -837,7 +857,9 @@ static inline void stm32f0serial_disableusartint(FAR struct stm32f0_serial_s *pr /* Disable all interrupts */ - stm32f0serial_restoreusartint(priv, 0); + stm32f0serial_setusartint(priv, 0); + + leave_critical_section(flags); } /**************************************************************************** diff --git a/arch/arm/src/stm32f7/stm32_serial.c b/arch/arm/src/stm32f7/stm32_serial.c index ce6e7db9a72..f400a9b379c 100644 --- a/arch/arm/src/stm32f7/stm32_serial.c +++ b/arch/arm/src/stm32f7/stm32_serial.c @@ -1096,10 +1096,10 @@ static inline void up_serialout(struct up_dev_s *priv, int offset, uint32_t valu } /**************************************************************************** - * Name: up_restoreusartint + * Name: up_setusartint ****************************************************************************/ -static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie) +static inline void up_setusartint(struct up_dev_s *priv, uint16_t ie) { uint32_t cr; @@ -1120,12 +1120,31 @@ static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie) up_serialout(priv, STM32_USART_CR3_OFFSET, cr); } +/**************************************************************************** + * Name: up_restoreusartint + ****************************************************************************/ + +static void up_restoreusartint(struct up_dev_s *priv, uint16_t ie) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + up_setusartint(priv, ie); + + leave_critical_section(flags); +} + /**************************************************************************** * Name: up_disableusartint ****************************************************************************/ -static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie) +static void up_disableusartint(struct up_dev_s *priv, uint16_t *ie) { + irqstate_t flags; + + flags = enter_critical_section(); + if (ie) { uint32_t cr1; @@ -1162,7 +1181,9 @@ static inline void up_disableusartint(struct up_dev_s *priv, uint16_t *ie) /* Disable all interrupts */ - up_restoreusartint(priv, 0); + up_setusartint(priv, 0); + + leave_critical_section(flags); } /**************************************************************************** @@ -2868,6 +2889,7 @@ int up_putc(int ch) up_lowputc(ch); up_restoreusartint(priv, ie); + #endif return ch; } diff --git a/arch/arm/src/stm32l4/stm32l4_serial.c b/arch/arm/src/stm32l4/stm32l4_serial.c index 15b9cbd120c..f1a5550212c 100644 --- a/arch/arm/src/stm32l4/stm32l4_serial.c +++ b/arch/arm/src/stm32l4/stm32l4_serial.c @@ -765,11 +765,11 @@ static inline void stm32l4serial_putreg(FAR struct stm32l4_serial_s *priv, } /**************************************************************************** - * Name: stm32l4serial_restoreusartint + * Name: stm32l4serial_setusartint ****************************************************************************/ -static void stm32l4serial_restoreusartint(FAR struct stm32l4_serial_s *priv, - uint16_t ie) +static inline void stm32l4serial_setusartint(FAR struct stm32l4_serial_s *priv, + uint16_t ie) { uint32_t cr; @@ -790,13 +790,33 @@ static void stm32l4serial_restoreusartint(FAR struct stm32l4_serial_s *priv, stm32l4serial_putreg(priv, STM32L4_USART_CR3_OFFSET, cr); } +/**************************************************************************** + * Name: up_restoreusartint + ****************************************************************************/ + +static void stm32l4serial_restoreusartint(FAR struct stm32l4_serial_s *priv, + uint16_t ie) +{ + irqstate_t flags; + + flags = enter_critical_section(); + + stm32l4serial_setusartint(priv, ie); + + leave_critical_section(flags); +} + /**************************************************************************** * Name: stm32l4serial_disableusartint ****************************************************************************/ -static inline void stm32l4serial_disableusartint(FAR struct stm32l4_serial_s *priv, - FAR uint16_t *ie) +static void stm32l4serial_disableusartint(FAR struct stm32l4_serial_s *priv, + FAR uint16_t *ie) { + irqstate_t flags; + + flags = enter_critical_section(); + if (ie) { uint32_t cr1; @@ -833,7 +853,9 @@ static inline void stm32l4serial_disableusartint(FAR struct stm32l4_serial_s *pr /* Disable all interrupts */ - stm32l4serial_restoreusartint(priv, 0); + stm32l4serial_setusartint(priv, 0); + + leave_critical_section(flags); } /****************************************************************************