From 80839635abdc1c7cff0b3f5d2b31cc300f68fb7b Mon Sep 17 00:00:00 2001 From: Gregory Nutt Date: Wed, 8 Apr 2015 15:27:31 -0600 Subject: SAMA5 Serial: Reading IMR and disabling interrupt must be atomic --- nuttx/ChangeLog | 4 ++++ nuttx/arch/arm/src/sam34/sam_serial.c | 2 +- nuttx/arch/arm/src/sama5/sam_serial.c | 41 +++++++++++++++++++++++++---------- nuttx/arch/arm/src/samv7/sam_serial.c | 2 +- 4 files changed, 35 insertions(+), 14 deletions(-) diff --git a/nuttx/ChangeLog b/nuttx/ChangeLog index efa398960..e8383ba8f 100755 --- a/nuttx/ChangeLog +++ b/nuttx/ChangeLog @@ -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). + diff --git a/nuttx/arch/arm/src/sam34/sam_serial.c b/nuttx/arch/arm/src/sam34/sam_serial.c index b2f98a582..d264aa349 100644 --- a/nuttx/arch/arm/src/sam34/sam_serial.c +++ b/nuttx/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/nuttx/arch/arm/src/sama5/sam_serial.c b/nuttx/arch/arm/src/sama5/sam_serial.c index 2f5f54870..935ee0e56 100644 --- a/nuttx/arch/arm/src/sama5/sam_serial.c +++ b/nuttx/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/nuttx/arch/arm/src/samv7/sam_serial.c b/nuttx/arch/arm/src/samv7/sam_serial.c index 896fcd405..1ffa8539b 100644 --- a/nuttx/arch/arm/src/samv7/sam_serial.c +++ b/nuttx/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); } -- cgit v1.2.3