From a93913c0f4ea3808f7548b13b63a96d2ae5542ae Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 8 Apr 2015 15:27:31 -0600 Subject: [PATCH] SAMA5 Serial: Reading IMR and disabling interrupt must be atomic --- arch/arm/src/sam34/sam_serial.c | 2 +- arch/arm/src/sama5/sam_serial.c | 41 +++++++++++++++++++++++---------- arch/arm/src/samv7/sam_serial.c | 2 +- 3 files changed, 31 insertions(+), 14 deletions(-) diff --git a/arch/arm/src/sam34/sam_serial.c b/arch/arm/src/sam34/sam_serial.c index b2f98a5828..d264aa3496 100644 --- a/arch/arm/src/sam34/sam_serial.c +++ b/arch/arm/src/sam34/sam_serial.c @@ -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); } diff --git a/arch/arm/src/sama5/sam_serial.c b/arch/arm/src/sama5/sam_serial.c index 2f5f54870b..935ee0e563 100644 --- a/arch/arm/src/sama5/sam_serial.c +++ b/arch/arm/src/sama5/sam_serial.c @@ -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 */ diff --git a/arch/arm/src/samv7/sam_serial.c b/arch/arm/src/samv7/sam_serial.c index 896fcd4059..1ffa8539bc 100644 --- a/arch/arm/src/samv7/sam_serial.c +++ b/arch/arm/src/samv7/sam_serial.c @@ -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); }