This is an automated email from the ASF dual-hosted git repository.

xiaoxiang pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/nuttx.git


The following commit(s) were added to refs/heads/master by this push:
     new e2083354f1 arch/arm/sama5: Use a recursive mutex to fix OHCI deadlock.
e2083354f1 is described below

commit e2083354f14d9f3f6dc1c783ce18a6ea44f73ad4
Author: Lwazi Dube <[email protected]>
AuthorDate: Tue May 2 21:16:36 2023 -0400

    arch/arm/sama5: Use a recursive mutex to fix OHCI deadlock.
    
    Unplugging a USB device from an OHCI root hub will cause
    a deadlock if DRVR_EPFREE is called from sam_rhsc_bottomhalf. A
    typical call chain looks like this: sam_rhsc_bottomhalf->
    CLASS_DISCONNECTED->usbhost_destroy->DRVR_EPFREE. In this case
    DRVR_EPFREE tries to lock a locked mutex. A recursive mutex
    prevents this deadlock.
---
 arch/arm/src/sama5/sam_ohci.c | 58 +++++++++++++++++++++----------------------
 1 file changed, 29 insertions(+), 29 deletions(-)

diff --git a/arch/arm/src/sama5/sam_ohci.c b/arch/arm/src/sama5/sam_ohci.c
index d4e195aad3..de7814327b 100644
--- a/arch/arm/src/sama5/sam_ohci.c
+++ b/arch/arm/src/sama5/sam_ohci.c
@@ -256,7 +256,7 @@ struct sam_ohci_s
   uint8_t outinterval;         /* Minimum periodic IN EP polling interval: 2, 
4, 6, 16, or 32 */
 #endif
 
-  mutex_t lock;                /* Support mutually exclusive access */
+  rmutex_t lock;               /* Support mutually exclusive access */
   sem_t pscsem;                /* Semaphore to wait Writeback Done Head event 
*/
   struct work_s work;          /* Supports interrupt bottom half */
 
@@ -461,7 +461,7 @@ static void sam_disconnect(struct usbhost_driver_s *drvr,
 
 static struct sam_ohci_s g_ohci =
 {
-  .lock = NXMUTEX_INITIALIZER,
+  .lock = NXRMUTEX_INITIALIZER,
   .pscsem = SEM_INITIALIZER(0),
 };
 
@@ -1871,7 +1871,7 @@ static int sam_ctrltd(struct sam_rhport_s *rhport,
        * wakes this thread up needs the lock).
        */
 #warning REVISIT
-      nxmutex_unlock(&g_ohci.lock);
+      nxrmutex_unlock(&g_ohci.lock);
 
       /* Wait for the Writeback Done Head interrupt  Loop to handle any false
        * alarm semaphore counts.
@@ -1886,7 +1886,7 @@ static int sam_ctrltd(struct sam_rhport_s *rhport,
        * this upon return.
        */
 
-      ret2 = nxmutex_lock(&g_ohci.lock);
+      ret2 = nxrmutex_lock(&g_ohci.lock);
       if (ret2 < 0)
         {
           ret = ret2;
@@ -2242,7 +2242,7 @@ static void sam_ohci_bottomhalf(void *arg)
    * real option (other than to reschedule and delay).
    */
 
-  nxmutex_lock(&g_ohci.lock);
+  nxrmutex_lock(&g_ohci.lock);
 
   /* Root hub status change interrupt */
 
@@ -2295,7 +2295,7 @@ static void sam_ohci_bottomhalf(void *arg)
   /* Now re-enable interrupts */
 
   sam_putreg(OHCI_INT_MIE, SAM_USBHOST_INTEN);
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
 }
 
 /****************************************************************************
@@ -2591,7 +2591,7 @@ static int sam_ep0configure(struct usbhost_driver_s 
*drvr, usbhost_ep_t ep0,
 
   /* We must have exclusive access to EP0 and the control list */
 
-  ret = nxmutex_lock(&g_ohci.lock);
+  ret = nxrmutex_lock(&g_ohci.lock);
   if (ret < 0)
     {
       return ret;
@@ -2614,7 +2614,7 @@ static int sam_ep0configure(struct usbhost_driver_s 
*drvr, usbhost_ep_t ep0,
 
   up_clean_dcache((uintptr_t)edctrl,
                   (uintptr_t)edctrl + sizeof(struct ohci_ed_s));
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
 
   usbhost_vtrace2(OHCI_VTRACE2_EP0CTRLED, RHPORT(rhport),
                   (uint16_t)edctrl->hw.ctrl);
@@ -2683,7 +2683,7 @@ static int sam_epalloc(struct usbhost_driver_s *drvr,
    * periodic list, and the interrupt table.
    */
 
-  ret = nxmutex_lock(&g_ohci.lock);
+  ret = nxrmutex_lock(&g_ohci.lock);
   if (ret < 0)
     {
       goto errout_with_eplist;
@@ -2814,7 +2814,7 @@ static int sam_epalloc(struct usbhost_driver_s *drvr,
   /* Success.. return an opaque reference to the endpoint list container */
 
   *ep = (usbhost_ep_t)eplist;
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
   return OK;
 
 errout_with_td:
@@ -2822,7 +2822,7 @@ errout_with_td:
 errout_with_ed:
   sam_edfree(ed);
 errout_with_lock:
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
 errout_with_eplist:
   kmm_free(eplist);
 errout:
@@ -2869,7 +2869,7 @@ static int sam_epfree(struct usbhost_driver_s *drvr, 
usbhost_ep_t ep)
    * periodic list and the interrupt table.
    */
 
-  ret2 = nxmutex_lock(&g_ohci.lock);
+  ret2 = nxrmutex_lock(&g_ohci.lock);
 
   /* Remove the ED to the correct list depending on the transfer type */
 
@@ -2905,7 +2905,7 @@ static int sam_epfree(struct usbhost_driver_s *drvr, 
usbhost_ep_t ep)
 
   nxsem_destroy(&eplist->wdhsem);
   kmm_free(eplist);
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
   return ret < 0 ? ret : ret2;
 }
 
@@ -2951,7 +2951,7 @@ static int sam_alloc(struct usbhost_driver_s *drvr,
 
   /* We must have exclusive access to the transfer buffer pool */
 
-  ret = nxmutex_lock(&g_ohci.lock);
+  ret = nxrmutex_lock(&g_ohci.lock);
   if (ret < 0)
     {
       return ret;
@@ -2966,7 +2966,7 @@ static int sam_alloc(struct usbhost_driver_s *drvr,
       ret = OK;
     }
 
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
   return ret;
 }
 
@@ -3002,9 +3002,9 @@ static int sam_free(struct usbhost_driver_s *drvr, 
uint8_t *buffer)
 
   /* We must have exclusive access to the transfer buffer pool */
 
-  ret = nxmutex_lock(&g_ohci.lock);
+  ret = nxrmutex_lock(&g_ohci.lock);
   sam_tbfree(buffer);
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
   return ret;
 }
 
@@ -3140,7 +3140,7 @@ static int sam_ctrlin(struct usbhost_driver_s *drvr, 
usbhost_ep_t ep0,
 
   /* We must have exclusive access to EP0 and the control list */
 
-  ret = nxmutex_lock(&g_ohci.lock);
+  ret = nxrmutex_lock(&g_ohci.lock);
   if (ret < 0)
     {
       return ret;
@@ -3166,7 +3166,7 @@ static int sam_ctrlin(struct usbhost_driver_s *drvr, 
usbhost_ep_t ep0,
    * it to be reloaded from RAM after the DMA.
    */
 
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
   up_invalidate_dcache((uintptr_t)buffer, (uintptr_t)buffer + len);
   return ret;
 }
@@ -3194,7 +3194,7 @@ static int sam_ctrlout(struct usbhost_driver_s *drvr, 
usbhost_ep_t ep0,
 
   /* We must have exclusive access to EP0 and the control list */
 
-  ret = nxmutex_lock(&g_ohci.lock);
+  ret = nxrmutex_lock(&g_ohci.lock);
   if (ret < 0)
     {
       return ret;
@@ -3217,7 +3217,7 @@ static int sam_ctrlout(struct usbhost_driver_s *drvr, 
usbhost_ep_t ep0,
         }
     }
 
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
   return ret;
 }
 
@@ -3366,7 +3366,7 @@ static ssize_t sam_transfer(struct usbhost_driver_s 
*drvr, usbhost_ep_t ep,
    * table.
    */
 
-  ret = nxmutex_lock(&g_ohci.lock);
+  ret = nxrmutex_lock(&g_ohci.lock);
   if (ret < 0)
     {
       return (ssize_t)ret;
@@ -3403,7 +3403,7 @@ static ssize_t sam_transfer(struct usbhost_driver_s 
*drvr, usbhost_ep_t ep,
    */
 
 #warning REVISIT
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
 
   /* Wait for the Writeback Done Head interrupt  Loop to handle any false
    * alarm semaphore counts.
@@ -3418,7 +3418,7 @@ static ssize_t sam_transfer(struct usbhost_driver_s 
*drvr, usbhost_ep_t ep,
    * this upon return.
    */
 
-  ret2 = nxmutex_lock(&g_ohci.lock);
+  ret2 = nxrmutex_lock(&g_ohci.lock);
   if (ret2 < 0)
     {
       ret = ret2;
@@ -3451,7 +3451,7 @@ static ssize_t sam_transfer(struct usbhost_driver_s 
*drvr, usbhost_ep_t ep,
       nbytes = eplist->xfrd;
       DEBUGASSERT(nbytes >= 0 && nbytes <= buflen);
 
-      nxmutex_unlock(&g_ohci.lock);
+      nxrmutex_unlock(&g_ohci.lock);
       return nbytes;
     }
 
@@ -3478,7 +3478,7 @@ errout:
   /* Make sure that there is no outstanding request on this endpoint */
 
   eplist->wdhwait = false;
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
   return (ssize_t)ret;
 }
 
@@ -3634,7 +3634,7 @@ static int sam_asynch(struct usbhost_driver_s *drvr, 
usbhost_ep_t ep,
    * table.
    */
 
-  ret = nxmutex_lock(&g_ohci.lock);
+  ret = nxrmutex_lock(&g_ohci.lock);
   if (ret < 0)
     {
       return ret;
@@ -3664,7 +3664,7 @@ static int sam_asynch(struct usbhost_driver_s *drvr, 
usbhost_ep_t ep,
    * when the transfer completes.
    */
 
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
   return OK;
 
 errout:
@@ -3673,7 +3673,7 @@ errout:
 
   eplist->callback = NULL;
   eplist->arg      = NULL;
-  nxmutex_unlock(&g_ohci.lock);
+  nxrmutex_unlock(&g_ohci.lock);
   return ret;
 }
 #endif /* CONFIG_USBHOST_ASYNCH */

Reply via email to