drivers/usbhost: Set the xHCI interrupter moderation interval.

The interval was left at its reset value of 4000, a millisecond, which is
how long the controller waits after an event before reporting it.  Every
completion paid that, and mass storage spends three transfers on a
request.

Set it to 160, which is 40us, as Linux does.  Zero puts no bound on how
often a controller may interrupt: a keyboard on an interrupt endpoint then
takes them continuously and occupies a processor.

Measured on a DWC3 with a USB 2.0 drive, doorbell to interrupt 986-1021us
before and 13-56us after:

    reading 1MiB          before        after
    512 byte blocks      166 KB/s     775 KB/s
    32 KiB blocks      10666 KB/s   18618 KB/s

    mounting a FAT32 volume: 92.7s before, 21.1s after

Assisted-by: Claude:claude-opus-5
Signed-off-by: Justin Hammond <justin@dynam.ac>
This commit is contained in:
Justin Hammond 2026-08-16 17:10:58 +08:00 • committed by Xiang Xiao
parent de440f910a
commit 8f88d73275
2 changed files with 15 additions and 0 deletions

View file

@ -1141,6 +1141,10 @@ static int xhci_ctrl_start(FAR struct usbhost_xhci_s *priv)
xhci_oper_putreg_8b(priv, XHCI_CRCR,
up_addrenv_va_to_pa(priv->cmd.ring) | XHCI_CRCR_RCS);
/* Do not sit on completions; see XHCI_IMOD_INTERVAL */
xhci_runt_putreg(priv, XHCI_IMOD(0), XHCI_IMOD_DEFAULT);
/* Enable interrupts */
regval = xhci_runt_getreg(priv, XHCI_IMAN(0));

View file

@ -315,6 +315,17 @@
#define XHCI_IMOD_IMODI_SHIFT (0) /* Bits 0-15: Interrupt Moderation Interval */
#define XHCI_IMOD_IMODC_SHIFT (16) /* Bits 16-31: Interrupt Moderation Counter */
/* What to set the moderation interval to, in 250ns units.
*
* The reset default is 4000, a millisecond, which is far too long to wait
* to be told a transfer finished. Zero is too short: it puts no bound on
* how often a controller may interrupt, and a polled device such as a
* keyboard on an interrupt endpoint will then occupy a processor. 160 is
* 40us, which is what Linux uses.
*/
#define XHCI_IMOD_DEFAULT (160)
/* Event Ring Segment Table Size */
#define XHCI_ERSTS_MASK (0xffff) /* Bit 0-15: Event Ring Segment Table Size */