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 cd30b682a4f5590ef8a00318967ca56c5acd10d2
Author: Justin Hammond <[email protected]>
AuthorDate: Sun Aug 16 17:12:25 2026 +0800

    drivers/usbhost: Flush the xHCI rings and structures by address.
    
    xhci_ctrl_start() published the event ring segment table, the device
    context base address array and the scratchpad pointers with
    up_flush_dcache_all(), which an architecture whose cache can only be
    maintained by address implements as a barrier and nothing more, so none of
    them reached memory.  The controller then reads whatever those addresses
    held before, which presents as every command timing out with no events
    arriving.  Flush each structure by address.
    
    xhci_ring_init() has the same fault from the other direction: it clears a
    whole ring and flushes only the link entry it writes afterwards, leaving
    the rest of the clearing in the cache.  The controller writes into that
    memory itself, so a line written back later lands on top of an event
    somebody is waiting for.  Flush the whole ring.
    
    Assisted-by: Claude:claude-opus-5
    Signed-off-by: Justin Hammond <[email protected]>
---
 drivers/usbhost/usbhost_xhci.c | 33 ++++++++++++++++++++++++++++-----
 1 file changed, 28 insertions(+), 5 deletions(-)

diff --git a/drivers/usbhost/usbhost_xhci.c b/drivers/usbhost/usbhost_xhci.c
index 2c3d3ad559a..7b076098a97 100644
--- a/drivers/usbhost/usbhost_xhci.c
+++ b/drivers/usbhost/usbhost_xhci.c
@@ -808,9 +808,16 @@ static int xhci_ring_init(FAR struct xhci_ring_s *ring, 
size_t len)
       ring->len = len;
     }
 
-  /* Reset data in ring */
+  /* Reset data in ring.
+   *
+   * Clearing dirties every line, and the controller writes into this
+   * memory itself.  Flush now, or a later writeback lands on top of an
+   * event somebody is waiting for.
+   */
 
   memset(ring->ring, 0, ring->len * sizeof(struct xhci_trb_s));
+  up_flush_dcache((uintptr_t)ring->ring,
+                  (uintptr_t)(ring->ring + ring->len));
 
   /* Fill Link TRB */
 
@@ -1112,9 +1119,22 @@ static int xhci_ctrl_start(FAR struct usbhost_xhci_s 
*priv)
   evnt->size = XHCI_EVENT_MAX;
   evnt->res  = 0;
 
-  /* Flush all memory before write to ERDP so xhci sees correct data */
+  /* Push the structures the controller is about to be pointed at.
+   *
+   * Flush by address: up_flush_dcache_all() is a no-op on architectures
+   * whose cache can only be maintained by address.
+   */
 
-  up_flush_dcache_all();
+  up_flush_dcache((uintptr_t)priv->pg_erst,
+                  (uintptr_t)priv->pg_erst +
+                  sizeof(struct xhci_event_ring_s) * priv->no_erst);
+  up_flush_dcache((uintptr_t)priv->pg_ctx,
+                  (uintptr_t)(priv->pg_ctx + priv->no_slots + 1));
+  if (priv->pg_sb != NULL)
+    {
+      up_flush_dcache((uintptr_t)priv->pg_sb,
+                      (uintptr_t)(priv->pg_sb + priv->no_scratch));
+    }
 
   xhci_runt_putreg_8b(priv, XHCI_ERDP(0),
                       up_addrenv_va_to_pa(priv->evnt.ring));
@@ -1151,9 +1171,12 @@ static int xhci_ctrl_start(FAR struct usbhost_xhci_s 
*priv)
   regval |= XHCI_IMAN_IE;
   xhci_runt_putreg(priv, XHCI_IMAN(0), regval);
 
-  /* Flush all memory once again */
+  /* And the command ring, whose last entry was just made to point back at
+   * its own beginning.
+   */
 
-  up_flush_dcache_all();
+  up_flush_dcache((uintptr_t)priv->cmd.ring,
+                  (uintptr_t)(priv->cmd.ring + XHCI_CMD_MAX));
 
   /* Turn the host controller ON, enable interrupts and system errors */
 

Reply via email to