From: Niklas Neronin Date: Thu, 2 Apr 2026 13:13:23 +0000 (+0300) Subject: usb: xhci: factor out roothub bandwidth cleanup X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=0837c87f95295798bcb16981271fbb9adf766eb1;p=thirdparty%2Fkernel%2Fstable.git usb: xhci: factor out roothub bandwidth cleanup Introduce xhci_rh_bw_cleanup() to release all bandwidth tracking structures associated with xHCI roothub ports. The new helper clears: * TT bandwidth entries * Per-interval endpoint lists This refactors and consolidates the existing per-port cleanup logic previously embedded in xhci_mem_cleanup(), reducing duplication and making the teardown sequence easier to follow. The helper will also be reused for upcoming S4 resume handling. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://patch.msgid.link/20260402131342.2628648-7-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 75bc1eb98b76..d4a9dbed8f16 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -1895,10 +1895,36 @@ void xhci_remove_secondary_interrupter(struct usb_hcd *hcd, struct xhci_interrup } EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter); +/* Cleanup roothub bandwidth data */ +static void xhci_rh_bw_cleanup(struct xhci_hcd *xhci) +{ + struct xhci_root_port_bw_info *rh_bw; + struct xhci_tt_bw_info *tt_info, *tt_next; + struct list_head *eps, *ep, *ep_next; + + for (int i = 0; i < xhci->max_ports; i++) { + rh_bw = &xhci->rh_bw[i]; + + /* Clear and free all TT bandwidth entries */ + list_for_each_entry_safe(tt_info, tt_next, &rh_bw->tts, tt_list) { + list_del(&tt_info->tt_list); + kfree(tt_info); + } + + /* Clear per-interval endpoint lists */ + for (int j = 0; j < XHCI_MAX_INTERVAL; j++) { + eps = &rh_bw->bw_table.interval_bw[j].endpoints; + + list_for_each_safe(ep, ep_next, eps) + list_del_init(ep); + } + } +} + void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - int i, j; + int i; cancel_delayed_work_sync(&xhci->cmd_timer); @@ -1917,15 +1943,6 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed command ring"); xhci_cleanup_command_queue(xhci); - for (i = 0; i < xhci->max_ports && xhci->rh_bw; i++) { - struct xhci_interval_bw_table *bwt = &xhci->rh_bw[i].bw_table; - for (j = 0; j < XHCI_MAX_INTERVAL; j++) { - struct list_head *ep = &bwt->interval_bw[j].endpoints; - while (!list_empty(ep)) - list_del_init(ep->next); - } - } - for (i = xhci->max_slots; i > 0; i--) xhci_free_virt_devices_depth_first(xhci, i); @@ -1959,18 +1976,9 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) scratchpad_free(xhci); - if (!xhci->rh_bw) - goto no_bw; - - for (i = 0; i < xhci->max_ports; i++) { - struct xhci_tt_bw_info *tt, *n; - list_for_each_entry_safe(tt, n, &xhci->rh_bw[i].tts, tt_list) { - list_del(&tt->tt_list); - kfree(tt); - } - } + if (xhci->rh_bw) + xhci_rh_bw_cleanup(xhci); -no_bw: xhci->cmd_ring_reserved_trbs = 0; xhci->usb2_rhub.num_ports = 0; xhci->usb3_rhub.num_ports = 0;