SAMA5 Serial: Reading IMR and disabling interrupt must be atomic

This commit is contained in:
Gregory Nutt 2015-04-08 15:27:31 -06:00
parent 2a9bd3ad73
commit e113be1bff
4 changed files with 35 additions and 14 deletions

View File

@ -10122,3 +10122,7 @@
interrupts disabled (2015-04-08)
* arch/arm/src/sama5/sam_serial.c: Backport support for flowcontrol and
termios from SAM3/4 -- UNVERIFIED. (2015-04-08).
* arch/arm/src/sam34/sam_serial.c and samv7/sam_serial.c: The IMR
register is read-only. This means that sam_restoreints() did not
actually re-enable UART interrupts (2015-04-08).

View File

@ -650,7 +650,7 @@ static inline void up_serialout(struct up_dev_s *priv, int offset, uint32_t valu
static inline void up_restoreusartint(struct up_dev_s *priv, uint32_t imr)
{
/* Restore the previous interrupt state */
/* Restore the previous interrupt state (assuming all interrupts disabled) */
up_serialout(priv, SAM_UART_IER_OFFSET, imr);
}

View File

@ -727,11 +727,22 @@ static inline void up_serialout(struct up_dev_s *priv, int offset, uint32_t valu
putreg32(value, priv->usartbase + offset);
}
/****************************************************************************
* Name: up_restoreusartint
****************************************************************************/
static inline void up_restoreusartint(struct up_dev_s *priv, uint32_t imr)
{
/* Restore the previous interrupt state (assuming all interrupts disabled) */
up_serialout(priv, SAM_UART_IER_OFFSET, imr);
}
/****************************************************************************
* Name: up_disableallints
****************************************************************************/
static void up_disableallints(struct up_dev_s *priv)
static void up_disableallints(struct up_dev_s *priv, uint32_t *imr)
{
irqstate_t flags;
@ -739,6 +750,13 @@ static void up_disableallints(struct up_dev_s *priv)
flags = irqsave();
/* Return the current interrupt state */
if (imr)
{
*imr = up_serialin(priv, SAM_UART_IMR_OFFSET);
}
/* Disable all interrupts */
up_serialout(priv, SAM_UART_IDR_OFFSET, UART_INT_ALLINTS);
@ -887,7 +905,7 @@ static void up_shutdown(struct uart_dev_s *dev)
/* Disable all interrupts */
up_disableallints(priv);
up_disableallints(priv, NULL);
}
/****************************************************************************
@ -1243,13 +1261,12 @@ static int up_ioctl(struct file *filep, int cmd, unsigned long arg)
* implement TCSADRAIN / TCSAFLUSH
*/
imr = up_serialin(priv, SAM_UART_IMR_OFFSET);
up_disableallints(priv);
up_disableallints(priv, &imr);
ret = up_setup(dev);
/* Restore the interrupt state */
up_serialout(priv, SAM_UART_IER_OFFSET, imr);
up_restoreusartint(priv, imr);
}
}
break;
@ -1437,25 +1454,25 @@ void sam_earlyserialinit(void)
/* Disable all USARTS */
#ifdef TTYS0_DEV
up_disableallints(TTYS0_DEV.priv);
up_disableallints(TTYS0_DEV.priv, NULL);
#endif
#ifdef TTYS1_DEV
up_disableallints(TTYS1_DEV.priv);
up_disableallints(TTYS1_DEV.priv, NULL);
#endif
#ifdef TTYS2_DEV
up_disableallints(TTYS2_DEV.priv);
up_disableallints(TTYS2_DEV.priv, NULL);
#endif
#ifdef TTYS3_DEV
up_disableallints(TTYS3_DEV.priv);
up_disableallints(TTYS3_DEV.priv, NULL);
#endif
#ifdef TTYS4_DEV
up_disableallints(TTYS4_DEV.priv);
up_disableallints(TTYS4_DEV.priv, NULL);
#endif
#ifdef TTYS5_DEV
up_disableallints(TTYS5_DEV.priv);
up_disableallints(TTYS5_DEV.priv, NULL);
#endif
#ifdef TTYS6_DEV
up_disableallints(TTYS6_DEV.priv);
up_disableallints(TTYS6_DEV.priv, NULL);
#endif
/* Configuration whichever one is the console */

View File

@ -710,7 +710,7 @@ static inline void sam_serialout(struct sam_dev_s *priv, int offset, uint32_t va
static inline void sam_restoreusartint(struct sam_dev_s *priv, uint32_t imr)
{
/* Restore the previous interrupt state */
/* Restore the previous interrupt state (assuming all interrupts disabled) */
sam_serialout(priv, SAM_UART_IER_OFFSET, imr);
}