]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
xhci: Add helper to find trb from its dma address
authorMathias Nyman <mathias.nyman@linux.intel.com>
Wed, 19 Nov 2025 14:23:56 +0000 (16:23 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 21 Nov 2025 13:52:59 +0000 (14:52 +0100)
Add a xhci_dma_to_trb() helper, and use it to find the transfer TRB
early in handle_tx_event() based on the dma address found in the
event TRB.

With this helper we can avoid using 'ep_seg' transfer TRB segment
variable as both a a boolean to indicate if the transfer TRB is part
of the next queued TD, and to actually find the transfer TRB based
on ep_seg and ep_trb_dma.

This is a first step in reworking and cleaning up trb_in_td() and
handle_tx_event()

Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://patch.msgid.link/20251119142417.2820519-3-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-ring.c

index 8e209aa33ea75796629dae81a8aa6267ba54f76f..7fccca7e1c629bcb8e544e19efec82eceadda47a 100644 (file)
@@ -82,6 +82,23 @@ dma_addr_t xhci_trb_virt_to_dma(struct xhci_segment *seg,
        return seg->dma + (segment_offset * sizeof(*trb));
 }
 
+static union xhci_trb *xhci_dma_to_trb(struct xhci_segment *start_seg,
+                                      dma_addr_t dma,
+                                      struct xhci_segment **match_seg)
+{
+       struct xhci_segment *seg;
+
+       xhci_for_each_ring_seg(start_seg, seg) {
+               if (in_range(dma, seg->dma, TRB_SEGMENT_SIZE)) {
+                       if (match_seg)
+                               *match_seg = seg;
+                       return &seg->trbs[(dma - seg->dma) / sizeof(union xhci_trb)];
+               }
+       }
+
+       return NULL;
+}
+
 static bool trb_is_noop(union xhci_trb *trb)
 {
        return TRB_TYPE_NOOP_LE32(trb->generic.field[3]);
@@ -2658,7 +2675,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
        int ep_index;
        struct xhci_td *td = NULL;
        dma_addr_t ep_trb_dma;
-       struct xhci_segment *ep_seg;
        union xhci_trb *ep_trb;
        int status = -EINPROGRESS;
        struct xhci_ep_ctx *ep_ctx;
@@ -2689,6 +2705,9 @@ static int handle_tx_event(struct xhci_hcd *xhci,
        if (!ep_ring)
                return handle_transferless_tx_event(xhci, ep, trb_comp_code);
 
+       /* find the transfer trb this events points to */
+       ep_trb = xhci_dma_to_trb(ep_ring->deq_seg, ep_trb_dma, NULL);
+
        /* Look for common error cases */
        switch (trb_comp_code) {
        /* Skip codes that require special handling depending on
@@ -2862,10 +2881,8 @@ static int handle_tx_event(struct xhci_hcd *xhci,
                td = list_first_entry(&ep_ring->td_list, struct xhci_td,
                                      td_list);
 
-               /* Is this a TRB in the currently executing TD? */
-               ep_seg = trb_in_td(td, ep_trb_dma);
-
-               if (!ep_seg) {
+               /* Is this TRB not part of the currently executing TD? */
+               if (!trb_in_td(td, ep_trb_dma)) {
 
                        if (ep->skip && usb_endpoint_xfer_isoc(&td->urb->ep->desc)) {
                                /* this event is unlikely to match any TD, don't skip them all */
@@ -2948,7 +2965,6 @@ static int handle_tx_event(struct xhci_hcd *xhci,
        if (ring_xrun_event)
                return 0;
 
-       ep_trb = &ep_seg->trbs[(ep_trb_dma - ep_seg->dma) / sizeof(*ep_trb)];
        trace_xhci_handle_transfer(ep_ring, (struct xhci_generic_trb *) ep_trb, ep_trb_dma);
 
        /*