]> www.infradead.org Git - linux.git/commitdiff
usb: xhci: set requested IMODI to the closest supported value
authorNiklas Neronin <niklas.neronin@linux.intel.com>
Thu, 15 May 2025 13:56:11 +0000 (16:56 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 21 May 2025 10:35:32 +0000 (12:35 +0200)
The function configures the Interrupt Moderation Interval (IMODI) via bits
15:0 in the Interrupt Moderation Register. The IMODI value is specified in
increments of 250 nanoseconds. For instance, an IMODI register value of 16
corresponds to 4000 nanoseconds, resulting in an interrupt every ~1ms.

Currently, the function fails when a requested IMODI value is too large,
only logging a warning message for secondary interrupters. Prevent this by
automatically adjusting the IMODI value to the nearest supported value.

Signed-off-by: Niklas Neronin <niklas.neronin@linux.intel.com>
Signed-off-by: Mathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20250515135621.335595-15-mathias.nyman@linux.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/usb/host/xhci-mem.c
drivers/usb/host/xhci.c

index 08513e5d321ad7f6072c24ad957b80f092de882c..dcfe7774e9ed256bdb9376d69de94d9ae98eaedd 100644 (file)
@@ -2393,10 +2393,7 @@ xhci_create_secondary_interrupter(struct usb_hcd *hcd, unsigned int segs,
                return NULL;
        }
 
-       err = xhci_set_interrupter_moderation(ir, imod_interval);
-       if (err)
-               xhci_warn(xhci, "Failed to set interrupter %d moderation to %uns\n",
-                         i, imod_interval);
+       xhci_set_interrupter_moderation(ir, imod_interval);
 
        xhci_dbg(xhci, "Add secondary interrupter %d, max interrupters %d\n",
                 ir->intr_num, xhci->max_interrupters);
index c6b517401c9431ceee7a3c7af6ebf3214a14374c..c3a1a67b65632ddce339fd7c25cb01a4d595c13b 100644 (file)
@@ -355,12 +355,15 @@ int xhci_set_interrupter_moderation(struct xhci_interrupter *ir,
 {
        u32 imod;
 
-       if (!ir || !ir->ir_set || imod_interval > U16_MAX * 250)
+       if (!ir || !ir->ir_set)
                return -EINVAL;
 
+       /* IMODI value in IMOD register is in 250ns increments */
+       imod_interval = umin(imod_interval / 250, ER_IRQ_INTERVAL_MASK);
+
        imod = readl(&ir->ir_set->irq_control);
        imod &= ~ER_IRQ_INTERVAL_MASK;
-       imod |= (imod_interval / 250) & ER_IRQ_INTERVAL_MASK;
+       imod |= imod_interval;
        writel(imod, &ir->ir_set->irq_control);
 
        return 0;