From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from smtp.kernel.org (aws-us-west-2-korg-mail-alma10-1.taild15c8.ts.net [100.103.45.18]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by smtp.subspace.kernel.org (Postfix) with ESMTPS id 94D6136EAB1 for ; Mon, 31 Aug 2026 16:42:37 +0000 (UTC) Authentication-Results: smtp.subspace.kernel.org; arc=none smtp.client-ip=100.103.45.18 ARC-Seal:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788194559; cv=none; b=rgoSvOxkYSlW2ADIGuKbcT8DpCCWJH8bk+FHLiQrvEgXZfNAXr3yTxU3PD4V+AhQJeMzRBHXMXgXy+oj73KQVYhctlJSNveOXAOXiZIIevRGbuLHU0Vf5ADNW3ZCrO12LuoCR4IecbVKf52hCth+gIINW/W2rfSS/B5i1xVQR6c= ARC-Message-Signature:i=1; a=rsa-sha256; d=subspace.kernel.org; s=arc-20240116; t=1788194559; c=relaxed/simple; bh=vt836vVUJP3fojS0GJ5+MhW+WRfl/SQJovkx/wdSqE4=; h=From:To:Cc:Subject:Date:Message-ID:In-Reply-To:References: MIME-Version; b=JHpS+BTUWiwSWyGv91vf6DpQ/HbtJ+YKuLnGQy6Ta66cLBX+acWLtmi7cE+ORsWOmpEhPfRa+2Ukeq22espLIlTRW26UlkavEF/98GRpH1Otof9CYYXqnJN6pdVrC5fWfSgm1mHN7M4Y0UM4zWlQ7A7/WHjY9ehX9J/d8V3cjQU= ARC-Authentication-Results:i=1; smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b=Os7WyJ3P; arc=none smtp.client-ip=100.103.45.18 Authentication-Results: smtp.subspace.kernel.org; dkim=pass (2048-bit key) header.d=kernel.org header.i=@kernel.org header.b="Os7WyJ3P" Received: by smtp.kernel.org (Postfix) with ESMTPSA id 8D4921F000E9; Mon, 31 Aug 2026 16:42:36 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=kernel.org; s=k20260515; t=1788194557; bh=dfj+G1SY1m8VGV6HUryCG/APWQQAB29OWgKLADRwmi0=; h=From:To:Cc:Subject:Date:In-Reply-To:References; b=Os7WyJ3PkRr1nC4AteHWWrqTtBtm3XMW6Don/0rxXqaI/4AR7WTChV+5omc9LUvs7 rKvAhaLqSh9dem1fWPC0RAUBTQhpsZEI9NSSEQ+hHi28uW/yZLsx787QUVrF2si0Uk l/4BLxV+xsFbjTyziNGOx9TsxVopKG4sYBxN0dHInOoRj0MdV1IR0Gm4fWZq+JcD2v R+rR3Ep8+MfvIRM9ESa5isr3wEcmUzTStNxBjuUNBcjWzxkRv3+V/7GwLytWZSUMDc 4s+/r3MoyhPJjeDoHPT5juI0NG8bfrrmKnqSgUV5LSj01z7LiqBvXH2LhOYzhbnpt4 hbx3HYG63wCpQ== From: Sasha Levin To: stable@vger.kernel.org Cc: Niklas Neronin , Mathias Nyman , Greg Kroah-Hartman , Sasha Levin Subject: [PATCH 6.12.y 3/4] usb: xhci: simplify handling of Structural Parameters 1 values Date: Mon, 31 Aug 2026 12:42:32 -0400 Message-ID: <20260831164233.269066-3-sashal@kernel.org> X-Mailer: git-send-email 2.53.0 In-Reply-To: <20260831164233.269066-1-sashal@kernel.org> References: <2026083120-autism-gerbil-efbb@gregkh> <20260831164233.269066-1-sashal@kernel.org> Precedence: bulk X-Mailing-List: stable@vger.kernel.org List-Id: List-Subscribe: List-Unsubscribe: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit From: Niklas Neronin [ Upstream commit df08973556851b29bd78e79db696d992ed1b43f0 ] The 32-bit read-only HCSPARAMS1 register contains the following fields: Bits 7:0 - Number of Device Slots (MaxSlots) Bits 18:8 - Number of Interrupters (MaxIntrs) Bits 23:19 - Reserved Bits 31:24 - Number of Ports (MaxPorts) Since the register value is constant for the lifetime of the controller, it is cached in 'xhci->hcs_params1'. However, platform drivers may override the number of interrupters through a separate variable, 'xhci->max_interrupters', leaving only the maximum slots and ports values still derived from the cached register. To simplify the code and improve readability, replace 'xhci->hcs_params1' with two dedicated 'u8' fields: 'xhci->max_slots' and 'xhci->max_ports'. These values are initialized once and used directly instead of calling 'HCS_MAX_SLOTS()' and 'HCS_MAX_PORTS()' macros. This change reduces code clutter without increasing memory usage. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://patch.msgid.link/20251119142417.2820519-16-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman [ Adjusted for 6.12, which lacks several later xhci cleanups: - The xhci_init() split into xhci_hcd_page_size(), xhci_enable_max_dev_slots(), xhci_set_cmd_ring_deq(), xhci_set_doorbell_ptr() and xhci_set_dev_notifications() is not present, so the xhci_enable_max_dev_slots() hunk is dropped. The equivalent 6.12 code in xhci_mem_init() reads HCSPARAMS1 straight from cap_regs and never touched xhci->hcs_params1, so it needs no change. - The port bandwidth debugfs files (xhci_port_bw_show() and friends) do not exist, so that xhci-debugfs.c hunk is dropped. - struct xhci_port still uses the 'addr' pointer to PORTSC rather than the 'port_reg' pointer to the whole register set, so only the loop bound is converted in xhci_setup_port_arrays(). - 6.12 has one extra user of the removed xhci->hcs_params1 field, xhci_try_enable_msi() in xhci-pci.c, which upstream had already converted to xhci->max_interrupters before this commit. Convert it here as well, otherwise removing the field breaks the build. It is equivalent: xhci_try_enable_msi() runs from the ->start() callback, i.e. after xhci_gen_setup() has clamped xhci->max_interrupters to HCS_MAX_INTRS(HCSPARAMS1), and nothing in 6.12 presets it. ] Stable-dep-of: 78203d5b54a4 ("usb: xhci: bail out of setup if the controller is inaccessible") Signed-off-by: Sasha Levin --- drivers/usb/host/xhci-debugfs.c | 10 +++------- drivers/usb/host/xhci-hub.c | 2 +- drivers/usb/host/xhci-mem.c | 31 +++++++++++++------------------ drivers/usb/host/xhci-pci.c | 9 ++++----- drivers/usb/host/xhci-ring.c | 6 ++---- drivers/usb/host/xhci.c | 15 ++++++++------- drivers/usb/host/xhci.h | 3 ++- 7 files changed, 33 insertions(+), 43 deletions(-) diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c index 570210e8a8e87..8e334b7553012 100644 --- a/drivers/usb/host/xhci-debugfs.c +++ b/drivers/usb/host/xhci-debugfs.c @@ -629,20 +629,16 @@ void xhci_debugfs_remove_slot(struct xhci_hcd *xhci, int slot_id) static void xhci_debugfs_create_ports(struct xhci_hcd *xhci, struct dentry *parent) { - unsigned int num_ports; char port_name[8]; struct xhci_port *port; struct dentry *dir; - num_ports = HCS_MAX_PORTS(xhci->hcs_params1); - parent = debugfs_create_dir("ports", parent); - while (num_ports--) { - scnprintf(port_name, sizeof(port_name), "port%02d", - num_ports + 1); + for (int i = 0; i < xhci->max_ports; i++) { + scnprintf(port_name, sizeof(port_name), "port%02d", i + 1); dir = debugfs_create_dir(port_name, parent); - port = &xhci->hw_ports[num_ports]; + port = &xhci->hw_ports[i]; debugfs_create_file("portsc", 0644, dir, port, &port_fops); } } diff --git a/drivers/usb/host/xhci-hub.c b/drivers/usb/host/xhci-hub.c index 49cba1cdd91bb..e2ea59b1bd24f 100644 --- a/drivers/usb/host/xhci-hub.c +++ b/drivers/usb/host/xhci-hub.c @@ -700,7 +700,7 @@ static int xhci_enter_test_mode(struct xhci_hcd *xhci, /* Disable all Device Slots */ xhci_dbg(xhci, "Disable all slots\n"); spin_unlock_irqrestore(&xhci->lock, *flags); - for (i = 1; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) { + for (i = 1; i <= xhci->max_slots; i++) { if (!xhci->devs[i]) continue; diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index 3ef311ca224bc..afe47a79d2528 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -918,7 +918,7 @@ static void xhci_free_virt_devices_depth_first(struct xhci_hcd *xhci, int slot_i /* is this a hub device that added a tt_info to the tts list */ if (tt_info->slot_id == slot_id) { /* are any devices using this tt_info? */ - for (i = 1; i < HCS_MAX_SLOTS(xhci->hcs_params1); i++) { + for (i = 1; i < xhci->max_slots; i++) { vdev = xhci->devs[i]; if (vdev && (vdev->tt_info == tt_info)) xhci_free_virt_devices_depth_first( @@ -1864,7 +1864,7 @@ EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter); void xhci_mem_cleanup(struct xhci_hcd *xhci) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - int i, j, num_ports; + int i, j; cancel_delayed_work_sync(&xhci->cmd_timer); @@ -1883,8 +1883,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed command ring"); xhci_cleanup_command_queue(xhci); - num_ports = HCS_MAX_PORTS(xhci->hcs_params1); - for (i = 0; i < num_ports && xhci->rh_bw; i++) { + 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; @@ -1893,7 +1892,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) } } - for (i = HCS_MAX_SLOTS(xhci->hcs_params1); i > 0; i--) + for (i = xhci->max_slots; i > 0; i--) xhci_free_virt_devices_depth_first(xhci, i); dma_pool_destroy(xhci->segment_pool); @@ -1924,7 +1923,7 @@ void xhci_mem_cleanup(struct xhci_hcd *xhci) if (!xhci->rh_bw) goto no_bw; - for (i = 0; i < num_ports; i++) { + 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); @@ -2125,7 +2124,7 @@ static void xhci_create_rhub_port_array(struct xhci_hcd *xhci, if (!rhub->ports) return; - for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) { + for (i = 0; i < xhci->max_ports; i++) { if (xhci->hw_ports[i].rhub != rhub || xhci->hw_ports[i].hcd_portnum == DUPLICATE_ENTRY) continue; @@ -2148,19 +2147,17 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) { void __iomem *base; u32 offset; - unsigned int num_ports; int i, j; int cap_count = 0; u32 cap_start; struct device *dev = xhci_to_hcd(xhci)->self.sysdev; - num_ports = HCS_MAX_PORTS(xhci->hcs_params1); - xhci->hw_ports = kcalloc_node(num_ports, sizeof(*xhci->hw_ports), - flags, dev_to_node(dev)); + xhci->hw_ports = kcalloc_node(xhci->max_ports, sizeof(*xhci->hw_ports), + flags, dev_to_node(dev)); if (!xhci->hw_ports) return -ENOMEM; - for (i = 0; i < num_ports; i++) { + for (i = 0; i < xhci->max_ports; i++) { xhci->hw_ports[i].addr = &xhci->op_regs->port_regs[i].portsc; xhci->hw_ports[i].hw_portnum = i; @@ -2168,11 +2165,10 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) init_completion(&xhci->hw_ports[i].u3exit_done); } - xhci->rh_bw = kcalloc_node(num_ports, sizeof(*xhci->rh_bw), flags, - dev_to_node(dev)); + xhci->rh_bw = kcalloc_node(xhci->max_ports, sizeof(*xhci->rh_bw), flags, dev_to_node(dev)); if (!xhci->rh_bw) return -ENOMEM; - for (i = 0; i < num_ports; i++) { + for (i = 0; i < xhci->max_ports; i++) { struct xhci_interval_bw_table *bw_table; INIT_LIST_HEAD(&xhci->rh_bw[i].tts); @@ -2204,9 +2200,8 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) offset = cap_start; while (offset) { - xhci_add_in_port(xhci, num_ports, base + offset, cap_count); - if (xhci->usb2_rhub.num_ports + xhci->usb3_rhub.num_ports == - num_ports) + xhci_add_in_port(xhci, xhci->max_ports, base + offset, cap_count); + if (xhci->usb2_rhub.num_ports + xhci->usb3_rhub.num_ports == xhci->max_ports) break; offset = xhci_find_next_ext_cap(base, offset, XHCI_EXT_CAPS_PROTOCOL); diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c index bd33cf6769cf6..2c4dc54b0fcaa 100644 --- a/drivers/usb/host/xhci-pci.c +++ b/drivers/usb/host/xhci-pci.c @@ -163,13 +163,12 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd) /* * calculate number of MSI-X vectors supported. - * - HCS_MAX_INTRS: the max number of interrupts the host can handle, - * with max number of interrupters based on the xhci HCSPARAMS1. + * - max_interrupters: the max number of interrupters requested, capped + * to the number the host can handle based on the xhci HCSPARAMS1. * - num_online_cpus: maximum MSI-X vectors per CPUs core. * Add additional 1 vector to ensure always available interrupt. */ - xhci->nvecs = min(num_online_cpus() + 1, - HCS_MAX_INTRS(xhci->hcs_params1)); + xhci->nvecs = min(num_online_cpus() + 1, xhci->max_interrupters); /* TODO: Check with MSI Soc for sysdev */ xhci->nvecs = pci_alloc_irq_vectors(pdev, 1, xhci->nvecs, @@ -898,7 +897,7 @@ static int xhci_pci_poweroff_late(struct usb_hcd *hcd, bool do_wakeup) if (!(xhci->quirks & XHCI_RESET_TO_DEFAULT)) return 0; - for (i = 0; i < HCS_MAX_PORTS(xhci->hcs_params1); i++) { + for (i = 0; i < xhci->max_ports; i++) { port = &xhci->hw_ports[i]; portsc = readl(port->addr); diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c index 9d506409fdf69..62c997d445fcc 100644 --- a/drivers/usb/host/xhci-ring.c +++ b/drivers/usb/host/xhci-ring.c @@ -1324,7 +1324,7 @@ void xhci_hc_died(struct xhci_hcd *xhci) xhci_cleanup_command_queue(xhci); /* return any pending urbs, remove may be waiting for them */ - for (i = 0; i <= HCS_MAX_SLOTS(xhci->hcs_params1); i++) { + for (i = 0; i <= xhci->max_slots; i++) { if (!xhci->devs[i]) continue; for (j = 0; j < 31; j++) @@ -1954,7 +1954,6 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event) struct usb_hcd *hcd; u32 port_id; u32 portsc, cmd_reg; - int max_ports; unsigned int hcd_portnum; struct xhci_bus_state *bus_state; bool bogus_port_status = false; @@ -1966,9 +1965,8 @@ static void handle_port_status(struct xhci_hcd *xhci, union xhci_trb *event) "WARN: xHC returned failed port status event\n"); port_id = GET_PORT_ID(le32_to_cpu(event->generic.field[0])); - max_ports = HCS_MAX_PORTS(xhci->hcs_params1); - if ((port_id <= 0) || (port_id > max_ports)) { + if ((port_id <= 0) || (port_id > xhci->max_ports)) { xhci_warn(xhci, "Port change event with invalid port ID %d\n", port_id); return; diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index 70b7c97e615ff..1c414b89b099c 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -276,8 +276,7 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci) if (upper_32_bits(val)) xhci_write_64(xhci, 0, &xhci->op_regs->cmd_ring); - intrs = min_t(u32, HCS_MAX_INTRS(xhci->hcs_params1), - ARRAY_SIZE(xhci->run_regs->ir_set)); + intrs = min_t(u32, xhci->max_interrupters, ARRAY_SIZE(xhci->run_regs->ir_set)); for (i = 0; i < intrs; i++) { struct xhci_intr_reg __iomem *ir; @@ -4040,7 +4039,7 @@ int xhci_alloc_dev(struct usb_hcd *hcd, struct usb_device *udev) xhci_err(xhci, "Error while assigning device slot ID: %s\n", xhci_trb_comp_code_string(command->status)); xhci_err(xhci, "Max number of devices this xHCI host supports is %u.\n", - HCS_MAX_SLOTS(xhci->hcs_params1)); + xhci->max_slots); xhci_free_command(xhci, command); return 0; } @@ -5225,6 +5224,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) */ struct device *dev = hcd->self.sysdev; int retval; + u32 hcs_params1; /* Accept arbitrarily long scatter-gather lists */ hcd->self.sg_tablesize = ~0; @@ -5250,7 +5250,7 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) xhci->run_regs = hcd->regs + (readl(&xhci->cap_regs->run_regs_off) & RTSOFF_MASK); /* Cache read-only capability registers */ - xhci->hcs_params1 = readl(&xhci->cap_regs->hcs_params1); + hcs_params1 = readl(&xhci->cap_regs->hcs_params1); xhci->hcs_params2 = readl(&xhci->cap_regs->hcs_params2); xhci->hcs_params3 = readl(&xhci->cap_regs->hcs_params3); xhci->hci_version = HC_VERSION(readl(&xhci->cap_regs->hc_capbase)); @@ -5259,10 +5259,11 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) xhci->hcc_params2 = readl(&xhci->cap_regs->hcc_params2); xhci->dma_mask_bits = 64; + xhci->max_slots = HCS_MAX_SLOTS(hcs_params1); + xhci->max_ports = HCS_MAX_PORTS(hcs_params1); /* xhci-plat or xhci-pci might have set max_interrupters already */ - if ((!xhci->max_interrupters) || - xhci->max_interrupters > HCS_MAX_INTRS(xhci->hcs_params1)) - xhci->max_interrupters = HCS_MAX_INTRS(xhci->hcs_params1); + if ((!xhci->max_interrupters) || xhci->max_interrupters > HCS_MAX_INTRS(hcs_params1)) + xhci->max_interrupters = HCS_MAX_INTRS(hcs_params1); xhci->quirks |= quirks; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index ccc43473ad90a..2e9a7fa981c20 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1492,7 +1492,6 @@ struct xhci_hcd { struct xhci_doorbell_array __iomem *dba; /* Cached register copies of read-only HC data */ - __u32 hcs_params1; __u32 hcs_params2; __u32 hcs_params3; __u32 hcc_params; @@ -1503,6 +1502,8 @@ struct xhci_hcd { /* packed release number */ u16 hci_version; u16 max_interrupters; + u8 max_slots; + u8 max_ports; /* imod_interval in ns (I * 250ns) */ u32 imod_interval; u32 page_size; -- 2.53.0