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.
