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 648aa30e37bdcaab6cc2eaa7a2c89384a5149eb3
Author: Justin Hammond <[email protected]>
AuthorDate: Sun Aug 16 17:09:58 2026 +0800

    drivers/usbhost: Attach the xHCI interrupt after the controller starts.
    
    The handler defers to a worker that walks the event ring, and the ring is
    not allocated until the controller is started, several steps later.  A
    controller left running by a boot loader has an interrupt pending as soon
    as the line is enabled, so attaching earlier is a race with nothing able
    to answer it.
    
    Attach after the start, and clear USBSTS and the interrupter pending flag
    once the handler is in place: a message signalled interrupt is sent on the
    flag's clear to set transition, so a flag raised before the handler
    existed would never produce another.
    
    Assisted-by: Claude:claude-opus-5
    Signed-off-by: Justin Hammond <[email protected]>
---
 drivers/usbhost/usbhost_xhci.c | 37 +++++++++++++++++++++++++++++--------
 1 file changed, 29 insertions(+), 8 deletions(-)

diff --git a/drivers/usbhost/usbhost_xhci.c b/drivers/usbhost/usbhost_xhci.c
index ff628cf31fd..efea0fb89dd 100644
--- a/drivers/usbhost/usbhost_xhci.c
+++ b/drivers/usbhost/usbhost_xhci.c
@@ -4545,14 +4545,6 @@ static int xhci_hw_initialize(FAR struct usbhost_xhci_s 
*priv)
       goto errout;
     }
 
-  /* Configure interrupts */
-
-  ret = xhci_irq_initialize(priv);
-  if (ret < 0)
-    {
-      goto errout;
-    }
-
   /* Halt controller */
 
   ret = xhci_ctrl_halt(priv);
@@ -4697,6 +4689,7 @@ xhci_initialize(FAR const char *name, uintptr_t base,
 {
   FAR struct usbhost_conn_xhci_s *conn = NULL;
   FAR struct usbhost_xhci_s      *priv = NULL;
+  uint32_t                        regval;
   int                             ret;
 
   DEBUGASSERT(name != NULL && base != 0 && ops != NULL &&
@@ -4756,6 +4749,34 @@ xhci_initialize(FAR const char *name, uintptr_t base,
       goto errout;
     }
 
+  /* Take the interrupt only now.
+   *
+   * The handler defers to a worker that walks the event ring, and the ring
+   * does not exist until the controller has been started.  A controller
+   * left running by a boot loader can have an interrupt pending the moment
+   * the line is enabled, so attaching any earlier is a race with nothing
+   * to answer it.
+   */
+
+  ret = xhci_irq_initialize(priv);
+  if (ret < 0)
+    {
+      uerr("failed to attach interrupt: %d\n", ret);
+      goto errout;
+    }
+
+  /* Acknowledge anything the controller raised before the handler was
+   * attached.  A message is sent once, on the transition, so a bit set in
+   * that window would never produce another.  Clear them, so the next
+   * event is a fresh assertion.
+   */
+
+  regval = xhci_oper_getreg(priv, XHCI_USBSTS);
+  xhci_oper_putreg(priv, XHCI_USBSTS, regval);
+
+  regval = xhci_runt_getreg(priv, XHCI_IMAN(0));
+  xhci_runt_putreg(priv, XHCI_IMAN(0), regval | XHCI_IMAN_IP);
+
 #ifdef CONFIG_DEBUG_USB_INFO
   xhci_dump_mem(priv, "after init");
 #endif

Reply via email to