Commit 28084d3f authored by Jonathan Bell's avatar Jonathan Bell Committed by Greg Kroah-Hartman

xhci: Use more than one Event Ring segment

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 dc0ffbea ("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 2 (configurable through the
ERST_MAX_SEGS macro), which seems like a reasonable quantity.  It is
supported by any xHC because the limit in the HCSPARAMS2 register is
defined as a power of 2.  Renesas uPD720201 and VIA VL805 controllers
do not support more than 2 ERST entries.

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.
Signed-off-by: default avatarJonathan Bell <jonathan@raspberrypi.com>
Signed-off-by: default avatarLukas Wunner <lukas@wunner.de>
Signed-off-by: default avatarMathias Nyman <mathias.nyman@linux.intel.com>
Link: https://lore.kernel.org/r/20231019102924.2797346-6-mathias.nyman@linux.intel.comSigned-off-by: default avatarGreg Kroah-Hartman <gregkh@linuxfoundation.org>
parent 044818a6
...@@ -2235,14 +2235,18 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags) ...@@ -2235,14 +2235,18 @@ xhci_alloc_interrupter(struct xhci_hcd *xhci, gfp_t flags)
{ {
struct device *dev = xhci_to_hcd(xhci)->self.sysdev; struct device *dev = xhci_to_hcd(xhci)->self.sysdev;
struct xhci_interrupter *ir; struct xhci_interrupter *ir;
unsigned int num_segs;
int ret; int ret;
ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev)); ir = kzalloc_node(sizeof(*ir), flags, dev_to_node(dev));
if (!ir) if (!ir)
return NULL; return NULL;
ir->event_ring = xhci_ring_alloc(xhci, ERST_NUM_SEGS, 1, TYPE_EVENT, num_segs = min_t(unsigned int, 1 << HCS_ERST_MAX(xhci->hcs_params2),
0, flags); ERST_MAX_SEGS);
ir->event_ring = xhci_ring_alloc(xhci, num_segs, 1, TYPE_EVENT, 0,
flags);
if (!ir->event_ring) { if (!ir->event_ring) {
xhci_warn(xhci, "Failed to allocate interrupter event ring\n"); xhci_warn(xhci, "Failed to allocate interrupter event ring\n");
kfree(ir); kfree(ir);
...@@ -2278,7 +2282,7 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir, ...@@ -2278,7 +2282,7 @@ xhci_add_interrupter(struct xhci_hcd *xhci, struct xhci_interrupter *ir,
/* set ERST count with the number of entries in the segment table */ /* set ERST count with the number of entries in the segment table */
erst_size = readl(&ir->ir_set->erst_size); erst_size = readl(&ir->ir_set->erst_size);
erst_size &= ERST_SIZE_MASK; 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); writel(erst_size, &ir->ir_set->erst_size);
erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base); erst_base = xhci_read_64(xhci, &ir->ir_set->erst_base);
......
...@@ -1647,8 +1647,9 @@ struct urb_priv { ...@@ -1647,8 +1647,9 @@ struct urb_priv {
* Each segment table entry is 4*32bits long. 1K seems like an ok size: * 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, * (1K bytes * 8bytes/bit) / (4*32 bits) = 64 segment entries in the table,
* meaning 64 ring segments. * meaning 64 ring segments.
* Initial allocated size of the ERST, in number of entries */ * Reasonable limit for number of Event Ring segments (spec allows 32k)
#define ERST_NUM_SEGS 1 */
#define ERST_MAX_SEGS 2
/* Poll every 60 seconds */ /* Poll every 60 seconds */
#define POLL_TIMEOUT 60 #define POLL_TIMEOUT 60
/* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */ /* Stop endpoint command timeout (secs) for URB cancellation watchdog timer */
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment