Message ID | 97f42cbb432ed38a327f02ef37348bd07765e0f5.1692085657.git.lukas@wunner.de |
---|---|
State | Superseded |
Headers | show |
Series | Multi-segment Event Ring support for XHCI | expand |
On 15.8.2023 15.40, Lukas Wunner wrote: > From: Jonathan Bell <jonathan@raspberrypi.com> > > Users have reported log spam created by "Event Ring Full" xHC event > TRBs. These are caused by interrupt latency in conjunction with a very > busy set of devices on the bus. The errors are benign, but throughput > will suffer as the xHC will pause processing of transfers until the > Event Ring is drained by the kernel. > > Commit dc0ffbea5729 ("usb: host: xhci: update event ring dequeue pointer > on purpose") mitigated the issue by advancing the Event Ring Dequeue > Pointer already after half a segment has been processed. Nevertheless, > providing a larger Event Ring would be useful to cope with load peaks. > > Expand the number of event TRB slots available by increasing the number > of Event Ring segments in the ERST. > > Controllers have a hardware-defined limit as to the number of ERST > entries they can process, but with up to 32k it can be excessively high > (sec 5.3.4). So cap the actual number at 8 (configurable through the > ERST_MAX_SEGS macro), which seems like a reasonable quantity. Making the new event ring default size 8 times bigger seems a bit over the top, especially when most systems worked fine with just one segment. How about doubling the current size as a default, and then think about adding more segments dynamically if we get "Event Ring Full" events? Thanks Mathias
diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c index c265425..cb50bf8 100644 --- a/drivers/usb/host/xhci-mem.c +++ b/drivers/usb/host/xhci-mem.c @@ -2238,14 +2238,18 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) { struct device *dev = xhci_to_hcd(xhci)->self.sysdev; struct xhci_interrupter *ir; + unsigned int num_segs; int ret; ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev)); if (!ir) return NULL; - ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, - 0, flags); + num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2), + ERST_MAX_SEGS); + + ir->event_ring = xhci_ring_alloc(xhci, num_segs, 1, TYPE_EVENT, 0, + flags); if (!ir->event_ring) { xhci_warn(xhci, "Failed to allocate interrupter event ring\n"); kfree(ir); @@ -2281,7 +2285,7 @@ static int xhci_setup_port_arrays(struct xhci_hcd *xhci, gfp_t flags) /* set ERST count with the number of entries in the segment table */ erst_size = readl(&ir->ir_set->erst_size); erst_size &= ERST_SIZE_MASK; - erst_size |= ERST_NUM_SEGS; + erst_size |= ir->event_ring->num_segs; writel(erst_size, &ir->ir_set->erst_size); erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h index 45c9177..0948d51 100644 --- a/drivers/usb/host/xhci.h +++ b/drivers/usb/host/xhci.h @@ -1674,8 +1674,9 @@ struct urb_priv { * Each segment table entry is 4*32bits long. 1K seems like an ok size: * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table, * meaning 64 ring segments. - * Initial allocated size of the ERST, in number of entries */ -#define ERST_NUM_SEGS 1 + * + * Reasonable limit for number of Event Ring segments (spec allows 32k) */ +#define ERST_MAX_SEGS 8 /* Poll every 60 seconds */ #define POLL_TIMEOUT 60 /* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */