Просмотр исходного кода

Merge pull request #1280 from kasjer/kasjer/nrf5x-dma-race

nrf5x: Fix DMA access race condition
Ha Thach 4 лет назад
Родитель
Сommit
e04f15ff3d
1 измененных файлов с 14 добавлено и 2 удалено
  1. 14 2
      src/portable/nordic/nrf5x/dcd_nrf5x.c

+ 14 - 2
src/portable/nordic/nrf5x/dcd_nrf5x.c

@@ -79,6 +79,9 @@ typedef struct
 
 
 } xfer_td_t;
 } xfer_td_t;
 
 
+static osal_mutex_def_t dcd_mutex_def;
+static osal_mutex_t dcd_mutex;
+
 // Data for managing dcd
 // Data for managing dcd
 static struct
 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
     // Should be safe to blocking wait until previous DMA transfer complete
     uint8_t const rhport = 0;
     uint8_t const rhport = 0;
     bool started = false;
     bool started = false;
+    osal_mutex_lock(dcd_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
     while(!started)
     while(!started)
     {
     {
       // LDREX/STREX may be needed in form of std atomic (required C11) or
       // 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_yield();
     }
     }
+    osal_mutex_unlock(dcd_mutex);
   }
   }
 }
 }
 
 
@@ -243,6 +248,7 @@ static void xact_in_dma(uint8_t epnum)
 void dcd_init (uint8_t rhport)
 void dcd_init (uint8_t rhport)
 {
 {
   TU_LOG1("dcd init\r\n");
   TU_LOG1("dcd init\r\n");
+  dcd_mutex = osal_mutex_create(&dcd_mutex_def);
   (void) rhport;
   (void) rhport;
 }
 }
 
 
@@ -457,11 +463,17 @@ bool dcd_edpt_xfer (uint8_t rhport, uint8_t ep_addr, uint8_t * buffer, uint16_t
 
 
   xfer_td_t* xfer = get_td(epnum, dir);
   xfer_td_t* xfer = get_td(epnum, dir);
 
 
-  dcd_int_disable(rhport);
+  if (!is_in_isr()) {
+    osal_mutex_lock(dcd_mutex, OSAL_TIMEOUT_WAIT_FOREVER);
+    dcd_int_disable(rhport);
+  }
   xfer->buffer     = buffer;
   xfer->buffer     = buffer;
   xfer->total_len  = total_bytes;
   xfer->total_len  = total_bytes;
   xfer->actual_len = 0;
   xfer->actual_len = 0;
-  dcd_int_enable(rhport);
+  if (!is_in_isr()) {
+    dcd_int_enable(rhport);
+    osal_mutex_unlock(dcd_mutex);
+  }
 
 
   // Control endpoint with zero-length packet and opposite direction to 1st request byte --> status stage
   // Control endpoint with zero-length packet and opposite direction to 1st request byte --> status stage
   bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE));
   bool const control_status = (epnum == 0 && total_bytes == 0 && dir != tu_edpt_dir(NRF_USBD->BMREQUESTTYPE));