mirror of
https://github.com/hathach/tinyusb.git
synced 2025-01-17 05:32:55 +08:00
nrf5x: Fix DMA access race condition
In multi-thread mode starting DMA in thread mode was prone to race condition resulting in infinite loop. It may happen on single core CPU with strict priority based tasks scheduler where ready high prio task never yields to ready low prio task (Mynewt). Sequence that failed (T1 - low priority task, T2 - high priority task) - T1 called start_dma() - T1 set _dcd.dma_running (DMA not started yet, context switch happens) - T2 took CPU and saw that _dcd.dma_running is set, so waits for _dcd.dma_running to be 0 - T1 never gets CPU again, DMA is not started T2 waits forever OSAL mutex resolves problem of DMA starting from thread-context.
This commit is contained in:
parent
0b6b4f2441
commit
980ffe3b4e
@ -79,6 +79,9 @@ typedef struct
|
||||
|
||||
} xfer_td_t;
|
||||
|
||||
static osal_mutex_def_t dcd_mutex_def;
|
||||
static osal_mutex_t dcd_mutex;
|
||||
|
||||
// Data for managing dcd
|
||||
static struct
|
||||
{
|
||||
@ -154,6 +157,7 @@ static void edpt_dma_start(volatile uint32_t* reg_startep)
|
||||
// Should be safe to blocking wait until previous DMA transfer complete
|
||||
uint8_t const rhport = 0;
|
||||
bool started = false;
|
||||
osal_mutex_lock(dcd_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
|
||||
while(!started)
|
||||
{
|
||||
// LDREX/STREX may be needed in form of std atomic (required C11) or
|
||||
@ -170,6 +174,7 @@ static void edpt_dma_start(volatile uint32_t* reg_startep)
|
||||
|
||||
// osal_yield();
|
||||
}
|
||||
osal_mutex_unlock(dcd_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@ -243,6 +248,7 @@ static void xact_in_dma(uint8_t epnum)
|
||||
void dcd_init (uint8_t rhport)
|
||||
{
|
||||
TU_LOG1("dcd init\r\n");
|
||||
dcd_mutex = osal_mutex_create(&dcd_mutex_def);
|
||||
(void) rhport;
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user