Skip to content

Commit 980ffe3

Browse files
committed
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.
1 parent 0b6b4f2 commit 980ffe3

File tree

1 file changed

+6
-0
lines changed

1 file changed

+6
-0
lines changed

src/portable/nordic/nrf5x/dcd_nrf5x.c

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,9 @@ typedef struct
7979

8080
} xfer_td_t;
8181

82+
static osal_mutex_def_t dcd_mutex_def;
83+
static osal_mutex_t dcd_mutex;
84+
8285
// Data for managing dcd
8386
static struct
8487
{
@@ -154,6 +157,7 @@ static void edpt_dma_start(volatile uint32_t* reg_startep)
154157
// Should be safe to blocking wait until previous DMA transfer complete
155158
uint8_t const rhport = 0;
156159
bool started = false;
160+
osal_mutex_lock(dcd_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
157161
while(!started)
158162
{
159163
// 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)
170174

171175
// osal_yield();
172176
}
177+
osal_mutex_unlock(dcd_mutex);
173178
}
174179
}
175180

@@ -243,6 +248,7 @@ static void xact_in_dma(uint8_t epnum)
243248
void dcd_init (uint8_t rhport)
244249
{
245250
TU_LOG1("dcd init\r\n");
251+
dcd_mutex = osal_mutex_create(&dcd_mutex_def);
246252
(void) rhport;
247253
}
248254

0 commit comments

Comments
 (0)