diff mbox series

[2/2] xhci: Use more than one Event Ring segment

Message ID 97f42cbb432ed38a327f02ef37348bd07765e0f5.1692085657.git.lukas@wunner.de (mailing list archive)
State Superseded
Headers show
Series Multi-segment Event Ring support for XHCI | expand

Commit Message

Lukas Wunner Aug. 15, 2023, 12:40 p.m. UTC
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.

An alternative to increasing the number of Event Ring segments would be
an increase of the segment size.  But that requires allocating multiple
contiguous pages, which may be impossible if memory is fragmented.

Link: https://forums.raspberrypi.com/viewtopic.php?t=246263
Signed-off-by: Jonathan Bell <jonathan@raspberrypi.com>
Signed-off-by: Lukas Wunner <lukas@wunner.de>
---
 drivers/usb/host/xhci-mem.c | 10 +++++++---
 drivers/usb/host/xhci.h     |  5 +++--
 2 files changed, 10 insertions(+), 5 deletions(-)

Comments

Mathias Nyman Aug. 17, 2023, 1:46 p.m. UTC | #1
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 mbox series

Patch

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 */