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

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

commit 18c834b7d3d2fdb912ec423a87db06e86c0ebf86
Author: Justin Hammond <[email protected]>
AuthorDate: Sat Aug 8 12:37:50 2026 +0800

    drivers/usbhost: Release the xHCI slot when enumeration fails.
    
    A device slot is a finite controller resource: HCSPARAMS1 reports how many
    exist and Enable Slot fails with No Slots Available once they are gone.
    Two paths took one and returned without giving it back.
    
    xhci_device_init() enables a slot before initialising the transfer ring,
    the slot context and the device address, and each of those returned
    directly on failure.  It also treated a slot number larger than the
    controller supports as success, since Enable Slot itself had succeeded.
    
    xhci_enumerate() is the larger leak: the device is addressed by the time
    usbhost_enumerate() runs, so a device whose descriptor cannot be read, or
    that no class driver claims, leaves the slot held.  That path clears
    hport->connected so the port is retried, taking another slot each time.
    
    Release the slot on both paths with xhci_device_deinit(), which issues
    Disable Slot, clears the DCBAA entry and resets the context.  The endpoint
    ring is left allocated; xhci_ring_init() reuses an existing one.
    
    Tested on an EIC7700X board with a device no class driver claims, so the
    port retries indefinitely: previously the eighth attempt failed with
    completion code 9 and the controller enumerated nothing further on either
    port; now 1104 consecutive attempts produced no slot failure.
    
    Assisted-by: Claude:claude-opus-5
    Signed-off-by: Justin Hammond <[email protected]>
---
 drivers/usbhost/usbhost_xhci.c | 42 ++++++++++++++++++++++++++++++++++++++----
 1 file changed, 38 insertions(+), 4 deletions(-)

diff --git a/drivers/usbhost/usbhost_xhci.c b/drivers/usbhost/usbhost_xhci.c
index 4f27a735e6c..31a70d98440 100644
--- a/drivers/usbhost/usbhost_xhci.c
+++ b/drivers/usbhost/usbhost_xhci.c
@@ -1810,7 +1810,15 @@ static int xhci_device_init(FAR struct usbhost_xhci_s 
*priv,
   ret = xhci_cmd_sloten(priv, &slot);
   if (ret < 0 || slot > priv->no_slots)
     {
-      /* Something goes wrong ! */
+      /* A slot the controller cannot address is no more usable than no
+       * slot at all, and the command itself succeeds in that case, so the
+       * caller needs an error either way.
+       */
+
+      if (ret >= 0)
+        {
+          ret = -EINVAL;
+        }
 
       usbhost_vtrace1(XHCI_TRACE1_SLOTEN_FAILED, ret);
       return ret;
@@ -1834,7 +1842,7 @@ static int xhci_device_init(FAR struct usbhost_xhci_s 
*priv,
   if (ret < 0)
     {
       uerr("ep0 ring init failed\n");
-      return ret;
+      goto errout_with_slot;
     }
 
   rhport->ep0.slot = slot;
@@ -1845,7 +1853,7 @@ static int xhci_device_init(FAR struct usbhost_xhci_s 
*priv,
   ret = xhci_slot_init(priv, dev);
   if (ret < 0)
     {
-      return ret;
+      goto errout_with_slot;
     }
 
   /* Step 6: Assign and address to the device and enable its Default
@@ -1860,12 +1868,21 @@ static int xhci_device_init(FAR struct usbhost_xhci_s 
*priv,
   if (ret < 0)
     {
       uerr("failed to set address %d\n", ret);
-      return ret;
+      goto errout_with_slot;
     }
 
   /* Steps 7-12 don't belong here! */
 
   return OK;
+
+errout_with_slot:
+
+  /* Nothing else gives the slot back, and the controller has a fixed
+   * number of them.
+   */
+
+  xhci_device_deinit(priv, rhport);
+  return ret;
 }
 
 /****************************************************************************
@@ -3770,6 +3787,23 @@ static int xhci_enumerate(FAR struct 
usbhost_connection_s *conn,
     {
       /* Failed to enumerate */
 
+      /* The device is addressed by now, so it holds a slot, and the retry
+       * below asks for another.
+       */
+
+#ifdef CONFIG_USBHOST_HUB
+      if (ROOTHUB(hport))
+#endif
+        {
+          FAR struct usbhost_xhci_s *priv = XHCI_PRIV_FROM_CONN(conn);
+          FAR struct xhci_rhport_s  *rhport = &priv->rhport[hport->port];
+
+          if (rhport->dev != NULL)
+            {
+              xhci_device_deinit(priv, rhport);
+            }
+        }
+
       /* If this is a root hub port, then marking the hub port not connected
        * will cause xhci_wait() to return and we will try the connection
        * again.

Reply via email to