From: Niklas Neronin Date: Wed, 3 Jun 2026 09:11:19 +0000 (+0300) Subject: usb: xhci: remove legacy 'num_trbs_free' tracking X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7ee645963075651d72f8d85bee428a9b7f1f148c;p=thirdparty%2Fkernel%2Flinux.git usb: xhci: remove legacy 'num_trbs_free' tracking Keeping track of free TRBs in a ring by adding and subtracting each time a enqueue or dequeue pointer is modified has proven to be buggy and complicated, especially over long periods of time. The xhci driver has already moved to calculating free TRBs dynamically based on ring size and the enqueue/dequeue positions. The DbC path is the last user of 'num_trbs_free'. Rather than maintaining two separate accounting mechanisms, remove the field entirely and switch DbC to use xhci_num_trbs_free(). Since 'num_trbs_free' undercounts by one, and xhci_num_trbs_free() does not, the check for sufficient free TRBs is adjusted. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://patch.msgid.link/20260603091132.1110849-3-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/usb/host/xhci-dbgcap.c b/drivers/usb/host/xhci-dbgcap.c index 7e6f7d72f03e..6a9f73fecb73 100644 --- a/drivers/usb/host/xhci-dbgcap.c +++ b/drivers/usb/host/xhci-dbgcap.c @@ -275,7 +275,6 @@ xhci_dbc_queue_trb(struct xhci_ring *ring, u32 field1, trace_xhci_dbc_gadget_ep_queue(ring, &trb->generic, xhci_trb_virt_to_dma(ring->enq_seg, ring->enqueue)); - ring->num_trbs_free--; next = ++(ring->enqueue); if (TRB_TYPE_LINK_LE32(next->link.control)) { next->link.control ^= cpu_to_le32(TRB_CYCLE); @@ -296,7 +295,7 @@ static int xhci_dbc_queue_bulk_tx(struct dbc_ep *dep, num_trbs = count_trbs(req->dma, req->length); WARN_ON(num_trbs != 1); - if (ring->num_trbs_free < num_trbs) + if (xhci_num_trbs_free(ring) <= num_trbs) return -EBUSY; addr = req->dma; @@ -796,7 +795,6 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event) } if (r->status == -COMP_STALL_ERROR) { dev_warn(dbc->dev, "Give back stale stalled req\n"); - ring->num_trbs_free++; xhci_dbc_giveback(r, 0); } } @@ -861,7 +859,6 @@ static void dbc_handle_xfer_event(struct xhci_dbc *dbc, union xhci_trb *event) break; } - ring->num_trbs_free++; req->actual = req->length - remain_length; xhci_dbc_giveback(req, status); } diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 997fe90f54e5..289461c06bf9 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -324,12 +324,6 @@ void xhci_initialize_ring_info(struct xhci_ring *ring) * handling ring expansion, set the cycle state equal to the old ring. */ ring->cycle_state = 1; - - /* - * Each segment has a link TRB, and leave an extra TRB for SW - * accounting purpose - */ - ring->num_trbs_free = ring->num_segs * (TRBS_PER_SEGMENT - 1) - 1; } EXPORT_SYMBOL_GPL(xhci_initialize_ring_info); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index e47e644b296e..f62db238276d 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -340,7 +340,7 @@ static bool trb_in_td(struct xhci_td *td, dma_addr_t suspect_dma) * Only for transfer and command rings where driver is the producer, not for * event rings. */ -static unsigned int xhci_num_trbs_free(struct xhci_ring *ring) +unsigned int xhci_num_trbs_free(struct xhci_ring *ring) { struct xhci_segment *enq_seg = ring->enq_seg; union xhci_trb *enq = ring->enqueue; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index aeecd301f207..e73c498449e8 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1376,7 +1376,6 @@ struct xhci_ring { u32 cycle_state; unsigned int stream_id; unsigned int num_segs; - unsigned int num_trbs_free; /* used only by xhci DbC */ unsigned int bounce_buf_len; enum xhci_ring_type type; u32 old_trb_comp_code; @@ -1955,6 +1954,7 @@ void xhci_ring_doorbell_for_active_rings(struct xhci_hcd *xhci, void xhci_cleanup_command_queue(struct xhci_hcd *xhci); void inc_deq(struct xhci_hcd *xhci, struct xhci_ring *ring); unsigned int count_trbs(u64 addr, u64 len); +unsigned int xhci_num_trbs_free(struct xhci_ring *ring); int xhci_stop_endpoint_sync(struct xhci_hcd *xhci, struct xhci_virt_ep *ep, int suspend, gfp_t gfp_flags); void xhci_process_cancelled_tds(struct xhci_virt_ep *ep);