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

    drivers/usbhost: Carry the xHCI transfer chain across the ring join.
    
    A transfer described by more than one TRB can reach the end of the ring
    part way through, so the link that sends the controller back to the
    beginning falls inside the transfer rather than between two of them.
    Written without the chain bit, that link ends the transfer where it
    stands: the controller follows it, considers the work finished, and
    reports nothing, because the TRB that asked for the completion interrupt
    is on the far side of the join.  Nothing waiting is woken, and transfers
    have no timeout, so the symptom is a read that never returns.
    
    Carry the chain bit onto the link when the TRB it follows has it.
    
    Reading 1MiB from a USB drive, where the last two sizes did not complete
    at all before:
    
        512 byte blocks     166 KB/s
        4 KiB blocks       1333 KB/s
        32 KiB blocks     10666 KB/s
        64 KiB blocks     15515 KB/s
    
    Assisted-by: Claude:claude-opus-5
    Signed-off-by: Justin Hammond <[email protected]>
---
 drivers/usbhost/usbhost_xhci.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/drivers/usbhost/usbhost_xhci.c b/drivers/usbhost/usbhost_xhci.c
index 377791bce5c..e1461ccfbd2 100644
--- a/drivers/usbhost/usbhost_xhci.c
+++ b/drivers/usbhost/usbhost_xhci.c
@@ -990,6 +990,19 @@ static void xhci_add_trb(FAR struct usbhost_xhci_s *priv,
                    XHCI_TRB_D2_TYPE_SET(XHCI_TRB_TYPE_LINK);
             }
 
+          /* Carry the chain forward across the join.
+           *
+           * A multi-TRB transfer can reach the end of the ring part way
+           * through, putting the link inside it.  A link without the
+           * chain bit ends the transfer where it stands, and the TRB that
+           * asked for the completion interrupt is never reached.
+           */
+
+          if ((trb[i].d2 & XHCI_TRB_D2_CH) != 0)
+            {
+              d2 |= XHCI_TRB_D2_CH;
+            }
+
           /* Other parameters are already correct for this TRB */
 
           ring->ring[ring->i].d2 = htole32(d2);

Reply via email to