summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNiklas Neronin <niklas.neronin@linux.intel.com>2026-04-02 16:13:23 +0300
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2026-04-02 16:55:37 +0300
commit0837c87f95295798bcb16981271fbb9adf766eb1 (patch)
treec9629b3b90233afb7fcc3226ed41143242dcfab2
parentab915ec99c06f04edfac40976613a809e0edbfa6 (diff)
downloadlinux-0837c87f95295798bcb16981271fbb9adf766eb1.tar.xz
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 <niklas.neronin@linux.intel.com> Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com> Link: https://patch.msgid.link/20260402131342.2628648-7-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/usb/host/xhci-mem.c50
1 files changed, 29 insertions, 21 deletions
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;