]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
usb: xhci: limit number of interrupts to 128
authorNiklas Neronin <niklas.neronin@linux.intel.com>
Wed, 19 Nov 2025 14:24:11 +0000 (16:24 +0200)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 21 Nov 2025 13:53:00 +0000 (14:53 +0100)
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 <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://patch.msgid.link/20251119142417.2820519-18-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci.c
drivers/usb/host/xhci.h

index cb82b15fc20347a6787cf8b9e057a1cfd8dc8525..1e4032bf1223709f012fc398db009d7020399b58 100644 (file)
@@ -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;
index e04bc491a22b9b0d97d5de834dc9c82dbb286a54..2b0796f6d00eaefb530df70e7c21b61a17004734 100644 (file)
  * 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];
 };
 
 /**