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.
This commit is contained in:
Jussi Kivilinna 2017-05-17 06:50:46 -06:00 committed by Gregory Nutt
parent 5ce2ece134
commit 9169ff6a15
4 changed files with 106 additions and 19 deletions

View File

@ -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);
}
/****************************************************************************

View File

@ -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);
}
/****************************************************************************

View File

@ -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;
}

View File

@ -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);
}
/****************************************************************************