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

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

commit c94fbeebcb9164c800a72bd3490abb9379ae3fa7
Author: Justin Hammond <[email protected]>
AuthorDate: Sun Aug 16 16:03:56 2026 +0800

    drivers/usbhost: Stop an xHCI controller only when it is running.
    
    xhci_ctrl_halt() wrote USBCMD zero unconditionally and then waited for
    HCH.  A controller that was never started is already halted, so the wait
    ran to its full length, and clearing the whole register also dropped
    INTE and HSEE.
    
    Test HCH first, clear only R/S when it is set, bound the wait with
    XHCI_HALT_TIMEOUT_MS, and report USBCMD and USBSTS on failure.
    
    Assisted-by: Claude:claude-opus-5
    Signed-off-by: Justin Hammond <[email protected]>
---
 drivers/usbhost/usbhost_xhci_pci.c | 51 +++++++++++++++++++++++++++-----------
 1 file changed, 37 insertions(+), 14 deletions(-)

diff --git a/drivers/usbhost/usbhost_xhci_pci.c 
b/drivers/usbhost/usbhost_xhci_pci.c
index 0f31007d9bb..8f8348a6ad1 100644
--- a/drivers/usbhost/usbhost_xhci_pci.c
+++ b/drivers/usbhost/usbhost_xhci_pci.c
@@ -68,6 +68,12 @@
 #define XHCI_CMD_MAX             (16)
 #define XHCI_EVENT_MAX           (232)
 #define XHCI_TD_MAX              (8)
+
+/* Milliseconds allowed for the controller to halt.  The specification
+ * asks for 16.
+ */
+
+#define XHCI_HALT_TIMEOUT_MS     (100)
 #define XHCI_BUFSIZE             (512)
 
 /* Port numbers macros */
@@ -1104,9 +1110,12 @@ static int xhci_ctrl_start(FAR struct usbhost_xhci_s 
*priv)
 
   xhci_oper_putreg(priv, XHCI_CONFIG, priv->no_slots);
 
-  /* Slot 0 in Device Context is reserved for Scratchpad Buffer Array */
+  /* Slot 0 of the Device Context array points at the Scratchpad Buffer
+   * Array, or is zero when the controller asked for none.
+   */
 
-  priv->pg_ctx[0] = htole64(up_addrenv_va_to_pa(priv->pg_sb));
+  priv->pg_ctx[0] = priv->pg_sb ?
+                    htole64(up_addrenv_va_to_pa(priv->pg_sb)) : 0;
 
   /* Device Context Base Address Array Pointer */
 
@@ -1227,27 +1236,41 @@ static int xhci_ctrl_start(FAR struct usbhost_xhci_s 
*priv)
 
 static int xhci_ctrl_halt(FAR struct usbhost_xhci_s *priv)
 {
-  int ret = -EAGAIN;
-  int i;
+  uint32_t regval;
+  int      i;
 
-  /* Halt controller */
+  /* A controller that was never started is already halted and says so.
+   * There is no transition to wait for, so check before waiting.
+   */
+
+  regval = xhci_oper_getreg(priv, XHCI_USBSTS);
+  if ((regval & XHCI_USBSTS_HCH) != 0)
+    {
+      return OK;
+    }
 
-  xhci_oper_putreg(priv, XHCI_USBCMD, 0);
+  /* Clear Run/Stop and leave the rest of the register alone.  Writing the
+   * whole of it zero would clear the interrupt and host system error
+   * enables along with it.
+   */
 
-  /* Wait for controller halted */
+  regval  = xhci_oper_getreg(priv, XHCI_USBCMD);
+  regval &= ~XHCI_USBCMD_RS;
+  xhci_oper_putreg(priv, XHCI_USBCMD, regval);
 
-  for (i = 0; i < 10; i++)
+  for (i = 0; i < XHCI_HALT_TIMEOUT_MS; i++)
     {
-      up_mdelay(100);
-
-      if (xhci_oper_getreg(priv, XHCI_USBSTS) & XHCI_USBSTS_HCH)
+      regval = xhci_oper_getreg(priv, XHCI_USBSTS);
+      if ((regval & XHCI_USBSTS_HCH) != 0)
         {
-          ret = OK;
-          break;
+          return OK;
         }
+
+      up_udelay(1000);
     }
 
-  return ret;
+  pcierr("controller will not halt, USBSTS %08" PRIx32 "\n", regval);
+  return -EAGAIN;
 }
 
 /****************************************************************************

Reply via email to