From: Niklas Neronin Date: Wed, 19 Nov 2025 14:24:11 +0000 (+0200) Subject: usb: xhci: limit number of interrupts to 128 X-Git-Tag: v6.19-rc1~63^2~44 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=8e9a3a1ea1b6e95e4503b258e7d6b1c4790c2e82;p=thirdparty%2Flinux.git usb: xhci: limit number of interrupts to 128 The xHCI driver defines only 128 interrupter register slots, yet allows up to 2047 interrupters. According to the xHCI specification, the maximum valid number of interrupters is 1024. These mismatches can lead to out-of-range accesses and excessive memory use. The Number of Interrupters (MaxIntrs) field occupies bits 18:8 of the HCSPARAMS1 register, which can yield a value up to 2047, although the specification limits it to 1024. Cap the value using the 'MAX_HC_INTRS' macro. Set 'xhci->max_intrs' to the minimum of the value reported by the HCSPARAMS1 register and 'MAX_HC_INTRS'. The interrupter register slot array is defined for 1024 entries, serving only as a structural template and not increasing memory usage. Although the xHCI specification allows up to 1024 interrupters, raising 'MAX_HC_INTRS' above 128 provides no practical benefit. The driver only uses the primary interrupter (0), and secondary interrupters (1+) are rarely, if ever, used in practice. No reports exist of usage beyond 128. Therefore, I have limited it to 128. Summary: * Interrupter allocations are now limited to 128 from 2047. * Interrupter Register template slots are set to 1024 from 128. * Macro 'MAX_HC_INTRS' can be modified to set the interrupter limit. ==== Detailed interrupter explanation ==== There are two relevant components: Interrupter array: This holds the software interrupter structures and is allocated by the xhci driver. The number of interrupters allocated is determined by the HCSPARAMS1 register field, which specifies the supported interrupter count. Interrupter register slots: This is a template struct used to access the hardware's runtime registers. It is not allocated by the driver, the hardware defines and owns this memory region, and the driver only maps it for MMIO access. Each entry in the interrupter array points to its corresponding interrupter register slot in the hardware region once that interrupter is enabled. Signed-off-by: Niklas Neronin Signed-off-by: Mathias Nyman Link: https://patch.msgid.link/20251119142417.2820519-18-mathias.nyman@linux.intel.com Signed-off-by: Greg Kroah-Hartman --- diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c index cb82b15fc2034..1e4032bf12237 100644 --- a/drivers/usb/host/xhci.c +++ b/drivers/usb/host/xhci.c @@ -250,7 +250,6 @@ static void xhci_zero_64b_regs(struct xhci_hcd *xhci) struct iommu_domain *domain; int err, i; u64 val; - u32 intrs; /* * Some Renesas controllers get into a weird state if they are @@ -291,9 +290,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, xhci->max_interrupters, ARRAY_SIZE(xhci->run_regs->ir_set)); - - for (i = 0; i < intrs; i++) { + for (i = 0; i < xhci->max_interrupters; i++) { struct xhci_intr_reg __iomem *ir; ir = &xhci->run_regs->ir_set[i]; @@ -5450,7 +5447,9 @@ int xhci_gen_setup(struct usb_hcd *hcd, xhci_get_quirks_t get_quirks) xhci->max_slots = HCS_MAX_SLOTS(hcs_params1); xhci->max_ports = min(HCS_MAX_PORTS(hcs_params1), MAX_HC_PORTS); /* xhci-plat or xhci-pci might have set max_interrupters already */ - if ((!xhci->max_interrupters) || xhci->max_interrupters > HCS_MAX_INTRS(hcs_params1)) + if (!xhci->max_interrupters) + xhci->max_interrupters = min(HCS_MAX_INTRS(hcs_params1), MAX_HC_INTRS); + else if (xhci->max_interrupters > HCS_MAX_INTRS(hcs_params1)) xhci->max_interrupters = HCS_MAX_INTRS(hcs_params1); xhci->quirks |= quirks; @@ -5670,8 +5669,8 @@ static int __init xhci_hcd_init(void) BUILD_BUG_ON(sizeof(struct xhci_erst_entry) != 4*32/8); BUILD_BUG_ON(sizeof(struct xhci_cap_regs) != 8*32/8); BUILD_BUG_ON(sizeof(struct xhci_intr_reg) != 8*32/8); - /* xhci_run_regs has eight fields and embeds 128 xhci_intr_regs */ - BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*128)*32/8); + /* xhci_run_regs has eight fields and embeds 1024 xhci_intr_regs */ + BUILD_BUG_ON(sizeof(struct xhci_run_regs) != (8+8*1024)*32/8); if (usb_disabled()) return -ENODEV; diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index e04bc491a22b9..2b0796f6d00ea 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -39,6 +39,11 @@ * Valid values are in the range of 1 to 255. */ #define MAX_HC_PORTS 127 +/* + * Max number of Interrupter Register Sets. xHCI specification section 5.3.3 + * Valid values are in the range of 1 to 1024. + */ +#define MAX_HC_INTRS 128 /* * xHCI register interface. @@ -278,7 +283,7 @@ struct xhci_intr_reg { struct xhci_run_regs { __le32 microframe_index; __le32 rsvd[7]; - struct xhci_intr_reg ir_set[128]; + struct xhci_intr_reg ir_set[1024]; }; /**