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 */
