drivers/serial/serial.c: In DMA mode, the use of uart_disablexinit() is insufficient to protect a critical section. enter/leave_critical_section() must be used in those cases if CONFIG_SERIAL_DMA=y

This commit is contained in:
Xiang Xiao
2018-08-26 10:30:48 -06:00
committed by Gregory Nutt
parent 9e922873d4
commit ea62b13fd0
+28 -10
View File
@@ -887,33 +887,45 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
else else
{ {
#ifdef CONFIG_SERIAL_DMA
/* Disable all interrupts and test again...
* uart_disablerxint() is insufficient for the check in DMA mode.
*/
flags = enter_critical_section();
#else
/* Disable Rx interrupts and test again... */ /* Disable Rx interrupts and test again... */
uart_disablerxint(dev); uart_disablerxint(dev);
#endif
/* If the Rx ring buffer still empty? Bytes may have been addded /* If the Rx ring buffer still empty? Bytes may have been added
* between the last time that we checked and when we disabled Rx * between the last time that we checked and when we disabled
* interrupts. * interrupts.
*/ */
if (rxbuf->head == rxbuf->tail) if (rxbuf->head == rxbuf->tail)
{ {
/* Yes.. the buffer is still empty. Wait for some characters /* Yes.. the buffer is still empty. We will need to wait for
* to be received into the buffer with the RX interrupt re- * additional data to be received.
* enabled. All interrupts are disabled briefly to assure
* that the following operations are atomic.
*/ */
flags = enter_critical_section();
#ifdef CONFIG_SERIAL_DMA #ifdef CONFIG_SERIAL_DMA
/* Notify DMA that there is free space in the RX buffer */ /* Notify DMA that there is free space in the RX buffer */
uart_dmarxfree(dev); uart_dmarxfree(dev);
#endif #else
/* Wait with the RX interrupt re-enabled. All interrupts are
* disabled briefly to assure that the following operations
* are atomic.
*/
flags = enter_critical_section();
/* Re-enable UART Rx interrupts */ /* Re-enable UART Rx interrupts */
uart_enablerxint(dev); uart_enablerxint(dev);
#endif
#ifdef CONFIG_SERIAL_REMOVABLE #ifdef CONFIG_SERIAL_REMOVABLE
/* Check again if the removable device is still connected /* Check again if the removable device is still connected
@@ -928,7 +940,7 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
else else
#endif #endif
{ {
/* Now wait with the Rx interrupt re-enabled. NuttX will /* Now wait with the Rx interrupt enabled. NuttX will
* automatically re-enable global interrupts when this * automatically re-enable global interrupts when this
* thread goes to sleep. * thread goes to sleep.
*/ */
@@ -979,7 +991,11 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
* the loop. * the loop.
*/ */
#ifdef CONFIG_SERIAL_DMA
leave_critical_section(flags);
#else
uart_enablerxint(dev); uart_enablerxint(dev);
#endif
} }
} }
} }
@@ -992,9 +1008,11 @@ static ssize_t uart_read(FAR struct file *filep, FAR char *buffer, size_t buflen
leave_critical_section(flags); leave_critical_section(flags);
#endif #endif
#ifndef CONFIG_SERIAL_DMA
/* RX interrupt could be disabled by RX buffer overflow. Enable it now. */ /* RX interrupt could be disabled by RX buffer overflow. Enable it now. */
uart_enablerxint(dev); uart_enablerxint(dev);
#endif
#ifdef CONFIG_SERIAL_IFLOWCONTROL #ifdef CONFIG_SERIAL_IFLOWCONTROL
#ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS #ifdef CONFIG_SERIAL_IFLOWCONTROL_WATERMARKS