public inbox for linux-usb@vger.kernel.org
 help / color / mirror / Atom feed
* [PATCH v3] usb: xhci: route endpoints to secondary interrupters
@ 2025-12-17  9:46 raoxu
  2025-12-18  7:57 ` Michal Pecio
  2025-12-18 15:49 ` Mathias Nyman
  0 siblings, 2 replies; 6+ messages in thread
From: raoxu @ 2025-12-17  9:46 UTC (permalink / raw)
  To: mathias.nyman
  Cc: gregkh, linux-usb, michal.pecio, niklas.neronin, raoxu, zhanjun

From: Xu Rao <raoxu@uniontech.com>

Some xHCI hosts expose multiple MSI/MSI-X vectors, but the driver
currently routes all transfer completions through interrupter 0.
This can lead to unnecessary contention on the primary event ring
and IRQ vector.

If the host reports more than one interrupter, allocate secondary
interrupters [1..max_interrupters-1] and cap the number of created
interrupters by num_online_cpus(). Each secondary interrupter has
its own event ring and can be requested as a separate IRQ vector.

An interrupter is bound to each endpoint once at endpoint enable
time. EP0 is always kept on interrupter 0, while all other endpoints
are assigned in a round-robin fashion over the enabled secondary
interrupters. Multiple endpoints may therefore share the same
interrupter.

Interrupt routing is performed by programming TRB_INTR_TARGET()
from the endpoint's bound interrupter number when queueing TRBs.
As a result, transfer completions are delivered to the event ring
(and IRQ vector) of the selected interrupter instead of always
landing on interrupter 0.

All interrupters share a common IRQ handler. STS_EINT is only
checked and cleared for interrupter 0, as it is only meaningful
for the primary interrupter. Secondary MSI/MSI-X vectors may fire
independently and simply process their associated event rings.

When requesting IRQs, the usb_hcd pointer is used as the dev_id
for both primary and secondary vectors. Although each secondary
interrupter has its own event ring, using per-interrupter dev_id
objects complicates teardown ordering in xhci_cleanup_msix().
In particular, IRQs must be freed before the corresponding
interrupter structures are removed, and the existing cleanup
sequence imposes constraints on dev_id lifetime. Using a common
dev_id avoids dev_id mismatches during free_irq() and keeps the
IRQ teardown consistent with the current xHCI removal flow.

Testing on an MSI-X capable host controller shows that interrupts
are effectively distributed across secondary vectors. For example,
after sustained USB transfers:

  /proc/interrupts (filtered):
    32:          0          0          0          0          0          0 \
          0        522  IR-PCI-MSIX-0000:03:00.3  0-edge  xhci_hcd
    33:      12297          0          0          0          0          0 \
          0          0  IR-PCI-MSIX-0000:03:00.3  1-edge  xhci_hcd
    34:          0      17082          0          0          0          0 \
          0          0  IR-PCI-MSIX-0000:03:00.3  2-edge  xhci_hcd
    35:          0          0      27567          0          0          0 \
          0          0  IR-PCI-MSIX-0000:03:00.3  3-edge  xhci_hcd
    36:          0          0          0      33234          0          0 \
          0          0  IR-PCI-MSIX-0000:03:00.3  4-edge  xhci_hcd
    37:          0          0          0          0    1519411          0 \
          0          0  IR-PCI-MSIX-0000:03:00.3  5-edge  xhci_hcd

This demonstrates that transfer completions are no longer handled
exclusively by interrupter 0, but are instead distributed across
multiple MSI-X vectors.

Signed-off-by: Xu Rao <raoxu@uniontech.com>
---
Changelog:
v1 -> v2:
  - Bind interrupters to endpoints at enable time instead of selecting
    per transfer.
  - Store the selected interrupter in struct xhci_virt_ep and program
    TRB_INTR_TARGET() from the bound interrupter.
  - Use a single IRQ handler for both primary and secondary vectors,
    with STS_EINT handling restricted to interrupter 0.
  - Keep a common dev_id for IRQ registration to match the existing
    xhci_cleanup_msix() teardown constraints and avoid dev_id
    lifetime issues.
  - Clarify secondary interrupter teardown to avoid double-free or
    use-after-free during xHCI removal.
v2 -> v3:
  - modify commit information
---
 drivers/usb/host/xhci-mem.c  | 86 +++++++++++++++++++++++++++++++++---
 drivers/usb/host/xhci-pci.c  | 28 ++++++++++++
 drivers/usb/host/xhci-ring.c | 79 ++++++++++++++++++++++++---------
 drivers/usb/host/xhci.c      | 38 ++++++++++++++++
 drivers/usb/host/xhci.h      |  7 +++
 5 files changed, 212 insertions(+), 26 deletions(-)

diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
index c4a6544aa107..277d395c03b8 100644
--- a/drivers/usb/host/xhci-mem.c
+++ b/drivers/usb/host/xhci-mem.c
@@ -1408,6 +1408,36 @@ static u32 xhci_get_max_esit_payload(struct usb_device *udev,
 	return max_packet * max_burst;
 }
 
+/* Pick an interrupter for an endpoint (EP0 always stays on interrupter 0). */
+static struct xhci_interrupter *
+xhci_pick_ep_interrupter(struct xhci_hcd *xhci, unsigned int ep_index)
+{
+	unsigned int idx;
+
+	/* Keep EP0 on primary interrupter */
+	if (ep_index == 0 || !xhci->nr_xfer_interrupters)
+		return xhci->interrupters[0];
+
+	/* round-robin over enabled secondary interrupters */
+	idx = (unsigned int)atomic_inc_return(&xhci->next_xfer_intr);
+	idx = (idx - 1) % xhci->nr_xfer_interrupters;
+	return xhci->xfer_interrupters[idx] ?: xhci->interrupters[0];
+}
+
+/* Bind the endpoint to one interrupter at enable time. */
+static void xhci_bind_ep_interrupter(struct xhci_hcd *xhci,
+		struct xhci_virt_device *virt_dev,
+		unsigned int ep_index)
+{
+	struct xhci_virt_ep *xep;
+	struct xhci_interrupter *ir;
+
+	xep = &virt_dev->eps[ep_index];
+	ir = xhci_pick_ep_interrupter(xhci, ep_index);
+
+	xep->interrupter = ir;
+}
+
 /* Set up an endpoint with one ring segment.  Do not allocate stream rings.
  * Drivers will have to call usb_alloc_streams() to do that.
  */
@@ -1511,6 +1541,9 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
 	ep_ctx->tx_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
 				      EP_AVG_TRB_LENGTH(avg_trb_len));
 
+	/* bind endpoint to an interrupter once at enable time */
+	xhci_bind_ep_interrupter(xhci, virt_dev, ep_index);
+
 	return 0;
 }
 
@@ -1902,17 +1935,31 @@ EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
 void xhci_mem_cleanup(struct xhci_hcd *xhci)
 {
 	struct device	*dev = xhci_to_hcd(xhci)->self.sysdev;
+	struct usb_hcd  *hcd = xhci_to_hcd(xhci);
 	int i, j, num_ports;
 
 	cancel_delayed_work_sync(&xhci->cmd_timer);
 
-	for (i = 0; xhci->interrupters && i < xhci->max_interrupters; i++) {
-		if (xhci->interrupters[i]) {
-			xhci_remove_interrupter(xhci, xhci->interrupters[i]);
-			xhci_free_interrupter(xhci, xhci->interrupters[i]);
-			xhci->interrupters[i] = NULL;
+	if (xhci->interrupters && xhci->interrupters[0]) {
+		xhci_remove_interrupter(xhci, xhci->interrupters[0]);
+		xhci_free_interrupter(xhci, xhci->interrupters[0]);
+		xhci->interrupters[0] = NULL;
+	}
+
+	for (i = 0; xhci->xfer_interrupters && i < xhci->xfer_irq_num; i++) {
+		if (xhci->xfer_interrupters[i]) {
+			xhci_remove_secondary_interrupter(hcd, xhci->xfer_interrupters[i]);
+			xhci->xfer_interrupters[i] = NULL;
 		}
 	}
+
+	if (xhci->xfer_irq_num) {
+		kfree(xhci->xfer_interrupters);
+		xhci->xfer_interrupters = NULL;
+		xhci->xfer_irq_num = 0;
+		atomic_set(&xhci->next_xfer_intr, 0);
+	}
+
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed interrupters");
 
 	if (xhci->cmd_ring)
@@ -2412,6 +2459,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 {
 	struct device	*dev = xhci_to_hcd(xhci)->self.sysdev;
 	dma_addr_t	dma;
+	int		i;
 
 	/*
 	 * xHCI section 5.4.6 - Device Context array must be
@@ -2505,6 +2553,34 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
 	if (!xhci->interrupters[0])
 		goto fail;
 
+	/*
+	 * Allocate secondary interrupters [1..max_interrupters-1].
+	 * Cap by num_online_cpus() to avoid excessive vectors.
+	 */
+	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocating secondary event ring");
+	if (xhci->max_interrupters > 1) {
+		xhci->xfer_irq_num = min(num_online_cpus(),
+					(unsigned int)xhci->max_interrupters - 1);
+		xhci->xfer_interrupters = kcalloc_node(xhci->xfer_irq_num,
+				sizeof(*xhci->xfer_interrupters),
+				flags, dev_to_node(dev));
+
+		if (!xhci->xfer_interrupters)
+			goto fail;
+	} else
+		xhci->xfer_irq_num = 0;
+
+	for (i = 0; i < xhci->xfer_irq_num; i++) {
+		struct xhci_interrupter *ir;
+		/* Create secondary interrupter with intr_num = i + 1. */
+		ir = xhci_create_secondary_interrupter(xhci_to_hcd(xhci),
+				i + 1, xhci->imod_interval, 0);
+		if (!ir)
+			goto fail;
+
+		xhci->xfer_interrupters[i] = ir;
+	}
+
 	if (scratchpad_alloc(xhci, flags))
 		goto fail;
 
diff --git a/drivers/usb/host/xhci-pci.c b/drivers/usb/host/xhci-pci.c
index f67a4d956204..217e6e217f81 100644
--- a/drivers/usb/host/xhci-pci.c
+++ b/drivers/usb/host/xhci-pci.c
@@ -14,6 +14,7 @@
 #include <linux/acpi.h>
 #include <linux/reset.h>
 #include <linux/suspend.h>
+#include <linux/irq.h>
 
 #include "xhci.h"
 #include "xhci-trace.h"
@@ -130,11 +131,20 @@ static void xhci_cleanup_msix(struct xhci_hcd *xhci)
 {
 	struct usb_hcd *hcd = xhci_to_hcd(xhci);
 	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
+	int i;
 
 	if (hcd->irq > 0)
 		return;
 
+	irq_set_handler_data(pci_irq_vector(pdev, 0), NULL);
 	free_irq(pci_irq_vector(pdev, 0), xhci_to_hcd(xhci));
+
+	for (i = 0; i < xhci->nr_xfer_interrupters; i++) {
+		irq_set_handler_data(pci_irq_vector(pdev, i+1), NULL);
+		free_irq(pci_irq_vector(pdev, i+1), hcd);
+	}
+	xhci->nr_xfer_interrupters = 0;
+
 	pci_free_irq_vectors(pdev);
 	hcd->msix_enabled = 0;
 }
@@ -145,6 +155,7 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
 	struct pci_dev *pdev = to_pci_dev(hcd->self.controller);
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 	int ret;
+	int i;
 
 	/*
 	 * Some Fresco Logic host controllers advertise MSI, but fail to
@@ -179,6 +190,23 @@ static int xhci_try_enable_msi(struct usb_hcd *hcd)
 	if (ret)
 		goto free_irq_vectors;
 
+	irq_set_handler_data(pci_irq_vector(pdev, 0), xhci->interrupters[0]);
+
+	/* Secondary transfer interrupters */
+	xhci->nr_xfer_interrupters = 0;
+	for (i = 0; i < xhci->xfer_irq_num; i++) {
+		struct xhci_interrupter *ir;
+
+		ir = xhci->xfer_interrupters[i];
+		ret = request_irq(pci_irq_vector(pdev, ir->intr_num),
+				xhci_msi_irq, 0, "xhci_hcd", xhci_to_hcd(xhci));
+		if (ret)
+			break;
+
+		irq_set_handler_data(pci_irq_vector(pdev, ir->intr_num), ir);
+		xhci->nr_xfer_interrupters++;
+	}
+
 	hcd->msi_enabled = 1;
 	hcd->msix_enabled = pdev->msix_enabled;
 	return 0;
diff --git a/drivers/usb/host/xhci-ring.c b/drivers/usb/host/xhci-ring.c
index 6309200e93dc..a76707055180 100644
--- a/drivers/usb/host/xhci-ring.c
+++ b/drivers/usb/host/xhci-ring.c
@@ -57,6 +57,7 @@
 #include <linux/slab.h>
 #include <linux/string_choices.h>
 #include <linux/dma-mapping.h>
+#include <linux/irq.h>
 #include "xhci.h"
 #include "xhci-trace.h"
 
@@ -3187,14 +3188,8 @@ void xhci_skip_sec_intr_events(struct xhci_hcd *xhci,
 	xhci_handle_events(xhci, ir, true);
 }
 
-/*
- * xHCI spec says we can get an interrupt, and if the HC has an error condition,
- * we might get bad data out of the event ring.  Section 4.10.2.7 has a list of
- * indicators of an event TRB error, but we check the status *first* to be safe.
- */
-irqreturn_t xhci_irq(struct usb_hcd *hcd)
+static irqreturn_t xhci_irq_ir(struct xhci_hcd *xhci, struct xhci_interrupter *ir)
 {
-	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 	irqreturn_t ret = IRQ_HANDLED;
 	u32 status;
 
@@ -3206,7 +3201,11 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
 		goto out;
 	}
 
-	if (!(status & STS_EINT)) {
+	/*
+	 * STS_EINT is only meaningful for the primary interrupter (0).
+	 * Secondary MSI/MSI-X interrupters may fire without STS_EINT set.
+	 */
+	if (ir->intr_num == 0 && !(status & STS_EINT)) {
 		ret = IRQ_NONE;
 		goto out;
 	}
@@ -3222,25 +3221,46 @@ irqreturn_t xhci_irq(struct usb_hcd *hcd)
 		goto out;
 	}
 
-	/*
-	 * Clear the op reg interrupt status first,
-	 * so we can receive interrupts from other MSI-X interrupters.
-	 * Write 1 to clear the interrupt status.
-	 */
-	status |= STS_EINT;
-	writel(status, &xhci->op_regs->status);
+	if (ir->intr_num == 0) {
+		/*
+		 * Clear the op reg interrupt status first,
+		 * so we can receive interrupts from other MSI-X interrupters.
+		 * Write 1 to clear the interrupt status.
+		 */
+		status |= STS_EINT;
+		writel(status, &xhci->op_regs->status);
+	}
 
 	/* This is the handler of the primary interrupter */
-	xhci_handle_events(xhci, xhci->interrupters[0], false);
+	xhci_handle_events(xhci, ir, false);
 out:
 	spin_unlock(&xhci->lock);
 
 	return ret;
 }
 
+/*
+ * xHCI spec says we can get an interrupt, and if the HC has an error condition,
+ * we might get bad data out of the event ring.  Section 4.10.2.7 has a list of
+ * indicators of an event TRB error, but we check the status *first* to be safe.
+ */
+irqreturn_t xhci_irq(struct usb_hcd *hcd)
+{
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+
+	return xhci_irq_ir(xhci, xhci->interrupters[0]);
+}
+
 irqreturn_t xhci_msi_irq(int irq, void *hcd)
 {
-	return xhci_irq(hcd);
+	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
+	struct xhci_interrupter *ir;
+
+	ir = irq_get_handler_data(irq);
+	if (!ir)
+		ir = xhci->interrupters[0];
+
+	return xhci_irq_ir(xhci, ir);
 }
 EXPORT_SYMBOL_GPL(xhci_msi_irq);
 
@@ -3624,6 +3644,21 @@ static int xhci_align_td(struct xhci_hcd *xhci, struct urb *urb, u32 enqd_len,
 	return 1;
 }
 
+static inline struct xhci_interrupter *
+xhci_ep_interrupter(struct xhci_hcd *xhci, int slot_id, unsigned int ep_index)
+{
+	struct xhci_virt_device *vdev;
+
+	if (slot_id <= 0 || slot_id >= MAX_HC_SLOTS)
+		return xhci->interrupters[0];
+	vdev = xhci->devs[slot_id];
+	if (!vdev)
+		return xhci->interrupters[0];
+	if (ep_index >= ARRAY_SIZE(vdev->eps))
+		return xhci->interrupters[0];
+	return vdev->eps[ep_index].interrupter ?: xhci->interrupters[0];
+}
+
 /* This is very similar to what ehci-q.c qtd_fill() does */
 int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 		struct urb *urb, int slot_id, unsigned int ep_index)
@@ -3642,6 +3677,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 	int sent_len, ret;
 	u32 field, length_field, remainder;
 	u64 addr, send_addr;
+	struct xhci_interrupter *ir;
 
 	ring = xhci_urb_to_transfer_ring(xhci, urb);
 	if (!ring)
@@ -3682,6 +3718,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 	start_trb = &ring->enqueue->generic;
 	start_cycle = ring->cycle_state;
 	send_addr = addr;
+	ir = xhci_ep_interrupter(xhci, slot_id, ep_index);
 
 	/* Queue the TRBs, even if they are zero-length */
 	for (enqd_len = 0; first_trb || enqd_len < full_len;
@@ -3742,7 +3779,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
 		length_field = TRB_LEN(trb_buff_len) |
 			TRB_TD_SIZE(remainder) |
-			TRB_INTR_TARGET(0);
+			TRB_INTR_TARGET(ir->intr_num);
 
 		queue_trb(xhci, ring, more_trbs_coming | need_zero_pkt,
 				lower_32_bits(send_addr),
@@ -3774,7 +3811,7 @@ int xhci_queue_bulk_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 		urb_priv->td[1].end_trb = ring->enqueue;
 		urb_priv->td[1].end_seg = ring->enq_seg;
 		field = TRB_TYPE(TRB_NORMAL) | ring->cycle_state | TRB_IOC;
-		queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(0), field);
+		queue_trb(xhci, ring, 0, 0, 0, TRB_INTR_TARGET(ir->intr_num), field);
 	}
 
 	check_trb_math(urb, enqd_len);
@@ -4112,7 +4149,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 
 	xep = &xhci->devs[slot_id]->eps[ep_index];
 	ep_ring = xhci->devs[slot_id]->eps[ep_index].ring;
-	ir = xhci->interrupters[0];
+	ir = xep->interrupter ?: xhci->interrupters[0];
 
 	num_tds = urb->number_of_packets;
 	if (num_tds < 1) {
@@ -4213,7 +4250,7 @@ static int xhci_queue_isoc_tx(struct xhci_hcd *xhci, gfp_t mem_flags,
 						   urb, more_trbs_coming);
 
 			length_field = TRB_LEN(trb_buff_len) |
-				TRB_INTR_TARGET(0);
+				TRB_INTR_TARGET(ir->intr_num);
 
 			/* xhci 1.1 with ETE uses TD Size field for TBC */
 			if (first_trb && xep->use_extended_tbc)
diff --git a/drivers/usb/host/xhci.c b/drivers/usb/host/xhci.c
index 742c23826e17..c6836b254d9d 100644
--- a/drivers/usb/host/xhci.c
+++ b/drivers/usb/host/xhci.c
@@ -590,6 +590,7 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
 	struct xhci_interrupter *ir = xhci->interrupters[0];
 	unsigned long	flags;
 	u32		temp;
+	int		i;
 
 	/*
 	 * Enable interrupts before starting the host (xhci 4.2 and 5.5.2).
@@ -605,6 +606,12 @@ static int xhci_run_finished(struct xhci_hcd *xhci)
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Enable primary interrupter");
 	xhci_enable_interrupter(ir);
 
+	/* Enable secondary interrupters (if any were successfully requested) */
+	for (i = 0; i < xhci->nr_xfer_interrupters; i++) {
+		if (xhci->xfer_interrupters && xhci->xfer_interrupters[i])
+			xhci_enable_interrupter(xhci->xfer_interrupters[i]);
+	}
+
 	if (xhci_start(xhci)) {
 		xhci_halt(xhci);
 		spin_unlock_irqrestore(&xhci->lock, flags);
@@ -701,6 +708,7 @@ void xhci_stop(struct usb_hcd *hcd)
 	u32 temp;
 	struct xhci_hcd *xhci = hcd_to_xhci(hcd);
 	struct xhci_interrupter *ir = xhci->interrupters[0];
+	int i;
 
 	mutex_lock(&xhci->mutex);
 
@@ -737,6 +745,12 @@ void xhci_stop(struct usb_hcd *hcd)
 	writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
 	xhci_disable_interrupter(xhci, ir);
 
+	/* Disable secondary interrupters */
+	for (i = 0; i < xhci->nr_xfer_interrupters; i++) {
+		if (xhci->xfer_interrupters && xhci->xfer_interrupters[i])
+			xhci_disable_interrupter(xhci, xhci->xfer_interrupters[i]);
+	}
+
 	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "cleaning up memory");
 	xhci_mem_cleanup(xhci);
 	xhci_debugfs_exit(xhci);
@@ -1080,6 +1094,7 @@ int xhci_resume(struct xhci_hcd *xhci, bool power_lost, bool is_auto_resume)
 	bool			comp_timer_running = false;
 	bool			pending_portevent = false;
 	bool			suspended_usb3_devs = false;
+	int			i;
 
 	if (!hcd->state)
 		return 0;
@@ -1175,6 +1190,12 @@ int xhci_resume(struct xhci_hcd *xhci, bool power_lost, bool is_auto_resume)
 		writel((temp & ~0x1fff) | STS_EINT, &xhci->op_regs->status);
 		xhci_disable_interrupter(xhci, xhci->interrupters[0]);
 
+		/* Disable secondary interrupters as well */
+		for (i = 0; i < xhci->nr_xfer_interrupters; i++) {
+			if (xhci->xfer_interrupters && xhci->xfer_interrupters[i])
+				xhci_disable_interrupter(xhci, xhci->xfer_interrupters[i]);
+		}
+
 		xhci_dbg(xhci, "cleaning up memory\n");
 		xhci_mem_cleanup(xhci);
 		xhci_debugfs_exit(xhci);
@@ -1879,6 +1900,16 @@ static int xhci_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
 	return ret;
 }
 
+static void xhci_unbind_ep_interrupter(struct xhci_hcd *xhci,
+		struct xhci_virt_device *virt_dev,
+		unsigned int ep_index)
+{
+	struct xhci_virt_ep *xep;
+
+	xep = &virt_dev->eps[ep_index];
+	xep->interrupter = NULL;
+}
+
 /* Drop an endpoint from a new bandwidth configuration for this device.
  * Only one call to this function is allowed per endpoint before
  * check_bandwidth() or reset_bandwidth() must be called.
@@ -1902,6 +1933,7 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
 	struct xhci_ep_ctx *ep_ctx;
 	u32 drop_flag;
 	u32 new_add_flags, new_drop_flags;
+	struct xhci_virt_device *virt_dev;
 	int ret;
 
 	ret = xhci_check_args(hcd, udev, ep, 1, true, __func__);
@@ -1953,6 +1985,12 @@ int xhci_drop_endpoint(struct usb_hcd *hcd, struct usb_device *udev,
 
 	xhci_endpoint_zero(xhci, xhci->devs[udev->slot_id], ep);
 
+	virt_dev = xhci->devs[udev->slot_id];
+	if (virt_dev) {
+		ep_index = xhci_get_endpoint_index(&ep->desc);
+		xhci_unbind_ep_interrupter(xhci, virt_dev, ep_index);
+	}
+
 	xhci_dbg(xhci, "drop ep 0x%x, slot id %d, new drop flags = %#x, new add flags = %#x\n",
 			(unsigned int) ep->desc.bEndpointAddress,
 			udev->slot_id,
diff --git a/drivers/usb/host/xhci.h b/drivers/usb/host/xhci.h
index 85d5b964bf1e..23caedfebdb9 100644
--- a/drivers/usb/host/xhci.h
+++ b/drivers/usb/host/xhci.h
@@ -700,6 +700,8 @@ struct xhci_virt_ep {
 	bool			use_extended_tbc;
 	/* set if this endpoint is controlled via sideband access*/
 	struct xhci_sideband	*sideband;
+	/* interrupter bound to this endpoint */
+	struct xhci_interrupter *interrupter;
 };
 
 enum xhci_overhead_type {
@@ -1533,6 +1535,11 @@ struct xhci_hcd {
 	/* data structures */
 	struct xhci_device_context_array *dcbaa;
 	struct xhci_interrupter **interrupters;
+	struct xhci_interrupter **xfer_interrupters;
+	/* secondary interrupters for transfer events */
+	unsigned int            nr_xfer_interrupters;
+	atomic_t	        next_xfer_intr;
+	unsigned int		xfer_irq_num;
 	struct xhci_ring	*cmd_ring;
 	unsigned int            cmd_ring_state;
 #define CMD_RING_STATE_RUNNING         (1 << 0)
-- 
2.50.1


^ permalink raw reply related	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] usb: xhci: route endpoints to secondary interrupters
  2025-12-17  9:46 [PATCH v3] usb: xhci: route endpoints to secondary interrupters raoxu
@ 2025-12-18  7:57 ` Michal Pecio
  2025-12-18 15:49 ` Mathias Nyman
  1 sibling, 0 replies; 6+ messages in thread
From: Michal Pecio @ 2025-12-18  7:57 UTC (permalink / raw)
  To: raoxu; +Cc: mathias.nyman, gregkh, linux-usb, niklas.neronin, zhanjun

On Wed, 17 Dec 2025 17:46:08 +0800, raoxu wrote:
> From: Xu Rao <raoxu@uniontech.com>
> 
> Some xHCI hosts expose multiple MSI/MSI-X vectors, but the driver
> currently routes all transfer completions through interrupter 0.
> This can lead to unnecessary contention on the primary event ring
> and IRQ vector.
> 
> If the host reports more than one interrupter, allocate secondary
> interrupters [1..max_interrupters-1] and cap the number of created
> interrupters by num_online_cpus(). Each secondary interrupter has
> its own event ring and can be requested as a separate IRQ vector.
> 
> An interrupter is bound to each endpoint once at endpoint enable
> time. EP0 is always kept on interrupter 0, while all other endpoints
> are assigned in a round-robin fashion over the enabled secondary
> interrupters. Multiple endpoints may therefore share the same
> interrupter.
> 
> Interrupt routing is performed by programming TRB_INTR_TARGET()
> from the endpoint's bound interrupter number when queueing TRBs.
> As a result, transfer completions are delivered to the event ring
> (and IRQ vector) of the selected interrupter instead of always
> landing on interrupter 0.
> 
> All interrupters share a common IRQ handler. STS_EINT is only
> checked and cleared for interrupter 0, as it is only meaningful
> for the primary interrupter. Secondary MSI/MSI-X vectors may fire
> independently and simply process their associated event rings.
> 
> When requesting IRQs, the usb_hcd pointer is used as the dev_id
> for both primary and secondary vectors. Although each secondary
> interrupter has its own event ring, using per-interrupter dev_id
> objects complicates teardown ordering in xhci_cleanup_msix().
> In particular, IRQs must be freed before the corresponding
> interrupter structures are removed, and the existing cleanup
> sequence imposes constraints on dev_id lifetime. Using a common
> dev_id avoids dev_id mismatches during free_irq() and keeps the
> IRQ teardown consistent with the current xHCI removal flow.
> 
> Testing on an MSI-X capable host controller shows that interrupts
> are effectively distributed across secondary vectors. For example,
> after sustained USB transfers:
> 
>   /proc/interrupts (filtered):
>     32:          0          0          0          0          0          0 \
>           0        522  IR-PCI-MSIX-0000:03:00.3  0-edge  xhci_hcd
>     33:      12297          0          0          0          0          0 \
>           0          0  IR-PCI-MSIX-0000:03:00.3  1-edge  xhci_hcd
>     34:          0      17082          0          0          0          0 \
>           0          0  IR-PCI-MSIX-0000:03:00.3  2-edge  xhci_hcd
>     35:          0          0      27567          0          0          0 \
>           0          0  IR-PCI-MSIX-0000:03:00.3  3-edge  xhci_hcd
>     36:          0          0          0      33234          0          0 \
>           0          0  IR-PCI-MSIX-0000:03:00.3  4-edge  xhci_hcd
>     37:          0          0          0          0    1519411          0 \
>           0          0  IR-PCI-MSIX-0000:03:00.3  5-edge  xhci_hcd
> 
> This demonstrates that transfer completions are no longer handled
> exclusively by interrupter 0, but are instead distributed across
> multiple MSI-X vectors.

What's the practical outcome and does it justify all this complexity?

The patch isn't even complete, because it opens a can of worms which
has never been dealt with before: completion events could be handled
in different order than they actually happened.

Most transfer events will go to secondary rings, yes. But some events
don't refer to any TRB and there is no TRB_INTR_TARGET applicable, so
they go to the slot's default interrupter. Command completion events
can only be delivered to the primary interrupter.

All event handling code relies on the assumption that transfer events
that happened earlier on the same endpoint have already been handled,
which won't be true if they are waiting in a different event ring.

It doesn't sound like fun to go through *all* of that code and come up
with workarounds. I guess it would be necessary to scan the other ring
for relevant events before doing anything. Figuring out ordering may
be further complicated by not all events having TRB pointers.


Also, I think there is no debugfs support for secondary event rings?

Regards,
Michal

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] usb: xhci: route endpoints to secondary interrupters
  2025-12-17  9:46 [PATCH v3] usb: xhci: route endpoints to secondary interrupters raoxu
  2025-12-18  7:57 ` Michal Pecio
@ 2025-12-18 15:49 ` Mathias Nyman
  2025-12-18 17:01   ` Kenneth Crudup
  1 sibling, 1 reply; 6+ messages in thread
From: Mathias Nyman @ 2025-12-18 15:49 UTC (permalink / raw)
  To: raoxu; +Cc: gregkh, linux-usb, michal.pecio, niklas.neronin, zhanjun

Hi Xu Rao

Thanks for the updated version

On 12/17/25 11:46, raoxu wrote:
> From: Xu Rao <raoxu@uniontech.com>
> 
> Some xHCI hosts expose multiple MSI/MSI-X vectors, but the driver
> currently routes all transfer completions through interrupter 0.
> This can lead to unnecessary contention on the primary event ring
> and IRQ vector.
> 
> If the host reports more than one interrupter, allocate secondary
> interrupters [1..max_interrupters-1] and cap the number of created
> interrupters by num_online_cpus(). Each secondary interrupter has
> its own event ring and can be requested as a separate IRQ vector.

This can lead to excessive amounts of interrupters on systems that
usually don't really use usb that much.

96 core systems would have 96 interrupters, each with an 8k event ring
to serve maybe one usb keyboard.

Lets start with something simple like 2 or 4 interrupters.

> 
> An interrupter is bound to each endpoint once at endpoint enable
> time. EP0 is always kept on interrupter 0, while all other endpoints
> are assigned in a round-robin fashion over the enabled secondary
> interrupters. Multiple endpoints may therefore share the same
> interrupter.

I think it would be better to assign a whole USB device to the same
interrupter, and set the "Interrupter Target" field in the slot
context to that interrupter.

This way special transfer events such as 'ring overrun' and 'ring underrun'
will end up on the same event ring as the rest of the transfer events for
that endpoint, and avoid some of the issues Michal pointed out.

> 
> Interrupt routing is performed by programming TRB_INTR_TARGET()
> from the endpoint's bound interrupter number when queueing TRBs.
> As a result, transfer completions are delivered to the event ring
> (and IRQ vector) of the selected interrupter instead of always
> landing on interrupter 0.
> 
> All interrupters share a common IRQ handler. STS_EINT is only
> checked and cleared for interrupter 0, as it is only meaningful
> for the primary interrupter. Secondary MSI/MSI-X vectors may fire
> independently and simply process their associated event rings.
> 
> When requesting IRQs, the usb_hcd pointer is used as the dev_id
> for both primary and secondary vectors. Although each secondary
> interrupter has its own event ring, using per-interrupter dev_id
> objects complicates teardown ordering in xhci_cleanup_msix().
> In particular, IRQs must be freed before the corresponding
> interrupter structures are removed, and the existing cleanup
> sequence imposes constraints on dev_id lifetime. Using a common
> dev_id avoids dev_id mismatches during free_irq() and keeps the
> IRQ teardown consistent with the current xHCI removal flow.
> 
> Testing on an MSI-X capable host controller shows that interrupts
> are effectively distributed across secondary vectors. For example,
> after sustained USB transfers:
> 
>    /proc/interrupts (filtered):
>      32:          0          0          0          0          0          0 \
>            0        522  IR-PCI-MSIX-0000:03:00.3  0-edge  xhci_hcd
>      33:      12297          0          0          0          0          0 \
>            0          0  IR-PCI-MSIX-0000:03:00.3  1-edge  xhci_hcd
>      34:          0      17082          0          0          0          0 \
>            0          0  IR-PCI-MSIX-0000:03:00.3  2-edge  xhci_hcd
>      35:          0          0      27567          0          0          0 \
>            0          0  IR-PCI-MSIX-0000:03:00.3  3-edge  xhci_hcd
>      36:          0          0          0      33234          0          0 \
>            0          0  IR-PCI-MSIX-0000:03:00.3  4-edge  xhci_hcd
>      37:          0          0          0          0    1519411          0 \
>            0          0  IR-PCI-MSIX-0000:03:00.3  5-edge  xhci_hcd
> 
> This demonstrates that transfer completions are no longer handled
> exclusively by interrupter 0, but are instead distributed across
> multiple MSI-X vectors.
> 
> Signed-off-by: Xu Rao <raoxu@uniontech.com>
> ---
> Changelog:
> v1 -> v2:
>    - Bind interrupters to endpoints at enable time instead of selecting
>      per transfer.
>    - Store the selected interrupter in struct xhci_virt_ep and program
>      TRB_INTR_TARGET() from the bound interrupter.
>    - Use a single IRQ handler for both primary and secondary vectors,
>      with STS_EINT handling restricted to interrupter 0.
>    - Keep a common dev_id for IRQ registration to match the existing
>      xhci_cleanup_msix() teardown constraints and avoid dev_id
>      lifetime issues.
>    - Clarify secondary interrupter teardown to avoid double-free or
>      use-after-free during xHCI removal.
> v2 -> v3:
>    - modify commit information
> ---
>   drivers/usb/host/xhci-mem.c  | 86 +++++++++++++++++++++++++++++++++---
>   drivers/usb/host/xhci-pci.c  | 28 ++++++++++++
>   drivers/usb/host/xhci-ring.c | 79 ++++++++++++++++++++++++---------
>   drivers/usb/host/xhci.c      | 38 ++++++++++++++++
>   drivers/usb/host/xhci.h      |  7 +++
>   5 files changed, 212 insertions(+), 26 deletions(-)
> 
> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
> index c4a6544aa107..277d395c03b8 100644
> --- a/drivers/usb/host/xhci-mem.c
> +++ b/drivers/usb/host/xhci-mem.c
> @@ -1408,6 +1408,36 @@ static u32 xhci_get_max_esit_payload(struct usb_device *udev,
>   	return max_packet * max_burst;
>   }
>   
> +/* Pick an interrupter for an endpoint (EP0 always stays on interrupter 0). */
> +static struct xhci_interrupter *
> +xhci_pick_ep_interrupter(struct xhci_hcd *xhci, unsigned int ep_index)
> +{
> +	unsigned int idx;
> +
> +	/* Keep EP0 on primary interrupter */
> +	if (ep_index == 0 || !xhci->nr_xfer_interrupters)
> +		return xhci->interrupters[0];
> +
> +	/* round-robin over enabled secondary interrupters */
> +	idx = (unsigned int)atomic_inc_return(&xhci->next_xfer_intr);
> +	idx = (idx - 1) % xhci->nr_xfer_interrupters;
> +	return xhci->xfer_interrupters[idx] ?: xhci->interrupters[0];
> +}

Set same interrupter for a whole device instead of round-robin for endpoints.
Skip the atomic_inc_return and whole atomic variable and do something like:
idx = slot_id % number_of_interrupters;

> +
> +/* Bind the endpoint to one interrupter at enable time. */
> +static void xhci_bind_ep_interrupter(struct xhci_hcd *xhci,
> +		struct xhci_virt_device *virt_dev,
> +		unsigned int ep_index)
> +{
> +	struct xhci_virt_ep *xep;
> +	struct xhci_interrupter *ir;
> +
> +	xep = &virt_dev->eps[ep_index];
> +	ir = xhci_pick_ep_interrupter(xhci, ep_index);
> +
> +	xep->interrupter = ir;
> +}

This helper doesn't do much.
Can be skipped.

> +
>   /* Set up an endpoint with one ring segment.  Do not allocate stream rings.
>    * Drivers will have to call usb_alloc_streams() to do that.
>    */
> @@ -1511,6 +1541,9 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
>   	ep_ctx->tx_info = cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
>   				      EP_AVG_TRB_LENGTH(avg_trb_len));
>   
> +	/* bind endpoint to an interrupter once at enable time */
> +	xhci_bind_ep_interrupter(xhci, virt_dev, ep_index);
> +
>   	return 0;
>   }
>   
> @@ -1902,17 +1935,31 @@ EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
>   void xhci_mem_cleanup(struct xhci_hcd *xhci)
>   {
>   	struct device	*dev = xhci_to_hcd(xhci)->self.sysdev;
> +	struct usb_hcd  *hcd = xhci_to_hcd(xhci);
>   	int i, j, num_ports;
>   
>   	cancel_delayed_work_sync(&xhci->cmd_timer);
>   
> -	for (i = 0; xhci->interrupters && i < xhci->max_interrupters; i++) {
> -		if (xhci->interrupters[i]) {
> -			xhci_remove_interrupter(xhci, xhci->interrupters[i]);
> -			xhci_free_interrupter(xhci, xhci->interrupters[i]);
> -			xhci->interrupters[i] = NULL;
> +	if (xhci->interrupters && xhci->interrupters[0]) {
> +		xhci_remove_interrupter(xhci, xhci->interrupters[0]);
> +		xhci_free_interrupter(xhci, xhci->interrupters[0]);
> +		xhci->interrupters[0] = NULL;
> +	}
> +
> +	for (i = 0; xhci->xfer_interrupters && i < xhci->xfer_irq_num; i++) {
> +		if (xhci->xfer_interrupters[i]) {
> +			xhci_remove_secondary_interrupter(hcd, xhci->xfer_interrupters[i]);
> +			xhci->xfer_interrupters[i] = NULL;
>   		}
>   	}
> +
> +	if (xhci->xfer_irq_num) {
> +		kfree(xhci->xfer_interrupters);
> +		xhci->xfer_interrupters = NULL;
> +		xhci->xfer_irq_num = 0;
> +		atomic_set(&xhci->next_xfer_intr, 0);

Hmm, so we now have two arrays of interrupters
   xhci->interrupters[]
   xhci->xfer_interripters[]

And some variables to keep track how many xhci interrupters are allocated,
and others to show how man actual interrupt vectors are in use.

I don't have a better way out of the box but it seems like
like there probably is a neater way to do this.


> +	}
> +
>   	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed interrupters");
>   
>   	if (xhci->cmd_ring)
> @@ -2412,6 +2459,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
>   {
>   	struct device	*dev = xhci_to_hcd(xhci)->self.sysdev;
>   	dma_addr_t	dma;
> +	int		i;
>   
>   	/*
>   	 * xHCI section 5.4.6 - Device Context array must be
> @@ -2505,6 +2553,34 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t flags)
>   	if (!xhci->interrupters[0])
>   		goto fail;
>   
> +	/*
> +	 * Allocate secondary interrupters [1..max_interrupters-1].
> +	 * Cap by num_online_cpus() to avoid excessive vectors.
> +	 */
> +	xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocating secondary event ring");
> +	if (xhci->max_interrupters > 1) {
> +		xhci->xfer_irq_num = min(num_online_cpus(),
> +					(unsigned int)xhci->max_interrupters - 1);
> +		xhci->xfer_interrupters = kcalloc_node(xhci->xfer_irq_num,
> +				sizeof(*xhci->xfer_interrupters),
> +				flags, dev_to_node(dev));
> +
> +		if (!xhci->xfer_interrupters)
> +			goto fail;
> +	} else
> +		xhci->xfer_irq_num = 0;
> +
> +	for (i = 0; i < xhci->xfer_irq_num; i++) {
> +		struct xhci_interrupter *ir;
> +		/* Create secondary interrupter with intr_num = i + 1. */
> +		ir = xhci_create_secondary_interrupter(xhci_to_hcd(xhci),
> +				i + 1, xhci->imod_interval, 0);
> +		if (!ir)
> +			goto fail;

Don't fail completely just because we can't get a secondary interrupter.
Roll back to only using primary, or use fewer secondary interrupters

At this stage we don't yet know if hardware really can provide the actual
interrupt vectors, and if request_irq() will be successful.

xhci->nvecs could be useful here, but it is not yet set.

Could allocating the xhci secondary interrupters and call request_irq()
be done in the same loop in xhci_pci_run()?

That would simpify things.

Note, Niklas was looking at this idea recently, and pointed out is
would need changes to xhci_resume() power_lost path

Thanks
Mathias

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] usb: xhci: route endpoints to secondary interrupters
  2025-12-18 15:49 ` Mathias Nyman
@ 2025-12-18 17:01   ` Kenneth Crudup
  2025-12-22 16:33     ` Kenneth Crudup
  0 siblings, 1 reply; 6+ messages in thread
From: Kenneth Crudup @ 2025-12-18 17:01 UTC (permalink / raw)
  To: Mathias Nyman, raoxu
  Cc: gregkh, linux-usb, michal.pecio, niklas.neronin, zhanjun,
	Kenneth C


FWIW, I rebased this (perhaps the previous spin?) for v.19-rc1 (see 
attached) and tried it out, before I saw you guys' objections ... whoops 
... but FWIW, it seems to be working here OK (that being said, I haven't 
had any USB errors so not sure what'll happen then, based on the 
followup comments).

If nothing else, I'll run it 'till my next reboot at least and see if 
there's any anomalies, but I guess you can put a "Tested-By" here?

Before, e.g.,:

----
  178:     675913          0          0          0          0          0 
   12944781          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:0d.0    0-edge      xhci_hcd
  186:    3286163          0          0          0          0          0 
          0          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:14.0    0-edge      xhci_hcd
----

... after (and after a couple of "Bonnie" runs):

----
  178:          0          0          0          0          0          0 
       1470          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:0d.0    0-edge      xhci_hcd
  179:          0          0          0          0          0          0 
          0     369210          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:0d.0    1-edge      xhci_hcd
  180:          0          0          0          0          0          0 
          0          0     264964          0          0          0    0 
         0 IR-PCI-MSI-0000:00:0d.0    2-edge      xhci_hcd
  181:          0          0          0          0          0          0 
          0          0          0     632289          0          0    0 
         0 IR-PCI-MSI-0000:00:0d.0    3-edge      xhci_hcd
  182:          0          0          0          0          0          0 
          0          0          0          0     557895          0    0 
         0 IR-PCI-MSI-0000:00:0d.0    4-edge      xhci_hcd
  183:          0          0          0          0          0          0 
          0          0          0          0          0      75643    0 
         0 IR-PCI-MSI-0000:00:0d.0    5-edge      xhci_hcd
  184:          0          0          0          0          0          0 
          0          0          0          0          0          0 9806 
         0 IR-PCI-MSI-0000:00:0d.0    6-edge      xhci_hcd
  185:          0          0          0          0          0          0 
          0          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:0d.0    7-edge      xhci_hcd
  186:        935          0          0          0          0          0 
          0          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:14.0    0-edge      xhci_hcd
  187:          0      48742          0          0          0          0 
          0          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:14.0    1-edge      xhci_hcd
  188:          0          0      30631          0          0          0 
          0          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:14.0    2-edge      xhci_hcd
  189:          0          0          0          0          0          0 
          0          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:14.0    3-edge      xhci_hcd
  190:          0          0          0          0          0          0 
          0          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:14.0    4-edge      xhci_hcd
  191:          0          0          0          0          0        157 
          0          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:14.0    5-edge      xhci_hcd
  192:          0          0          0          0          0          0 
       4820          0          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:14.0    6-edge      xhci_hcd
  193:          0          0          0          0          0          0 
          0       2915          0          0          0          0    0 
         0 IR-PCI-MSI-0000:00:14.0    7-edge      xhci_hcd
----

-K

On 12/18/25 07:49, Mathias Nyman wrote:
> Hi Xu Rao
> 
> Thanks for the updated version
> 
> On 12/17/25 11:46, raoxu wrote:
>> From: Xu Rao <raoxu@uniontech.com>
>>
>> Some xHCI hosts expose multiple MSI/MSI-X vectors, but the driver
>> currently routes all transfer completions through interrupter 0.
>> This can lead to unnecessary contention on the primary event ring
>> and IRQ vector.
>>
>> If the host reports more than one interrupter, allocate secondary
>> interrupters [1..max_interrupters-1] and cap the number of created
>> interrupters by num_online_cpus(). Each secondary interrupter has
>> its own event ring and can be requested as a separate IRQ vector.
> 
> This can lead to excessive amounts of interrupters on systems that
> usually don't really use usb that much.
> 
> 96 core systems would have 96 interrupters, each with an 8k event ring
> to serve maybe one usb keyboard.
> 
> Lets start with something simple like 2 or 4 interrupters.
> 
>>
>> An interrupter is bound to each endpoint once at endpoint enable
>> time. EP0 is always kept on interrupter 0, while all other endpoints
>> are assigned in a round-robin fashion over the enabled secondary
>> interrupters. Multiple endpoints may therefore share the same
>> interrupter.
> 
> I think it would be better to assign a whole USB device to the same
> interrupter, and set the "Interrupter Target" field in the slot
> context to that interrupter.
> 
> This way special transfer events such as 'ring overrun' and 'ring underrun'
> will end up on the same event ring as the rest of the transfer events for
> that endpoint, and avoid some of the issues Michal pointed out.
> 
>>
>> Interrupt routing is performed by programming TRB_INTR_TARGET()
>> from the endpoint's bound interrupter number when queueing TRBs.
>> As a result, transfer completions are delivered to the event ring
>> (and IRQ vector) of the selected interrupter instead of always
>> landing on interrupter 0.
>>
>> All interrupters share a common IRQ handler. STS_EINT is only
>> checked and cleared for interrupter 0, as it is only meaningful
>> for the primary interrupter. Secondary MSI/MSI-X vectors may fire
>> independently and simply process their associated event rings.
>>
>> When requesting IRQs, the usb_hcd pointer is used as the dev_id
>> for both primary and secondary vectors. Although each secondary
>> interrupter has its own event ring, using per-interrupter dev_id
>> objects complicates teardown ordering in xhci_cleanup_msix().
>> In particular, IRQs must be freed before the corresponding
>> interrupter structures are removed, and the existing cleanup
>> sequence imposes constraints on dev_id lifetime. Using a common
>> dev_id avoids dev_id mismatches during free_irq() and keeps the
>> IRQ teardown consistent with the current xHCI removal flow.
>>
>> Testing on an MSI-X capable host controller shows that interrupts
>> are effectively distributed across secondary vectors. For example,
>> after sustained USB transfers:
>>
>>    /proc/interrupts (filtered):
>>      32:          0          0          0          0          
>> 0          0 \
>>            0        522  IR-PCI-MSIX-0000:03:00.3  0-edge  xhci_hcd
>>      33:      12297          0          0          0          
>> 0          0 \
>>            0          0  IR-PCI-MSIX-0000:03:00.3  1-edge  xhci_hcd
>>      34:          0      17082          0          0          
>> 0          0 \
>>            0          0  IR-PCI-MSIX-0000:03:00.3  2-edge  xhci_hcd
>>      35:          0          0      27567          0          
>> 0          0 \
>>            0          0  IR-PCI-MSIX-0000:03:00.3  3-edge  xhci_hcd
>>      36:          0          0          0      33234          
>> 0          0 \
>>            0          0  IR-PCI-MSIX-0000:03:00.3  4-edge  xhci_hcd
>>      37:          0          0          0          0    
>> 1519411          0 \
>>            0          0  IR-PCI-MSIX-0000:03:00.3  5-edge  xhci_hcd
>>
>> This demonstrates that transfer completions are no longer handled
>> exclusively by interrupter 0, but are instead distributed across
>> multiple MSI-X vectors.
>>
>> Signed-off-by: Xu Rao <raoxu@uniontech.com>
>> ---
>> Changelog:
>> v1 -> v2:
>>    - Bind interrupters to endpoints at enable time instead of selecting
>>      per transfer.
>>    - Store the selected interrupter in struct xhci_virt_ep and program
>>      TRB_INTR_TARGET() from the bound interrupter.
>>    - Use a single IRQ handler for both primary and secondary vectors,
>>      with STS_EINT handling restricted to interrupter 0.
>>    - Keep a common dev_id for IRQ registration to match the existing
>>      xhci_cleanup_msix() teardown constraints and avoid dev_id
>>      lifetime issues.
>>    - Clarify secondary interrupter teardown to avoid double-free or
>>      use-after-free during xHCI removal.
>> v2 -> v3:
>>    - modify commit information
>> ---
>>   drivers/usb/host/xhci-mem.c  | 86 +++++++++++++++++++++++++++++++++---
>>   drivers/usb/host/xhci-pci.c  | 28 ++++++++++++
>>   drivers/usb/host/xhci-ring.c | 79 ++++++++++++++++++++++++---------
>>   drivers/usb/host/xhci.c      | 38 ++++++++++++++++
>>   drivers/usb/host/xhci.h      |  7 +++
>>   5 files changed, 212 insertions(+), 26 deletions(-)
>>
>> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
>> index c4a6544aa107..277d395c03b8 100644
>> --- a/drivers/usb/host/xhci-mem.c
>> +++ b/drivers/usb/host/xhci-mem.c
>> @@ -1408,6 +1408,36 @@ static u32 xhci_get_max_esit_payload(struct 
>> usb_device *udev,
>>       return max_packet * max_burst;
>>   }
>> +/* Pick an interrupter for an endpoint (EP0 always stays on 
>> interrupter 0). */
>> +static struct xhci_interrupter *
>> +xhci_pick_ep_interrupter(struct xhci_hcd *xhci, unsigned int ep_index)
>> +{
>> +    unsigned int idx;
>> +
>> +    /* Keep EP0 on primary interrupter */
>> +    if (ep_index == 0 || !xhci->nr_xfer_interrupters)
>> +        return xhci->interrupters[0];
>> +
>> +    /* round-robin over enabled secondary interrupters */
>> +    idx = (unsigned int)atomic_inc_return(&xhci->next_xfer_intr);
>> +    idx = (idx - 1) % xhci->nr_xfer_interrupters;
>> +    return xhci->xfer_interrupters[idx] ?: xhci->interrupters[0];
>> +}
> 
> Set same interrupter for a whole device instead of round-robin for 
> endpoints.
> Skip the atomic_inc_return and whole atomic variable and do something like:
> idx = slot_id % number_of_interrupters;
> 
>> +
>> +/* Bind the endpoint to one interrupter at enable time. */
>> +static void xhci_bind_ep_interrupter(struct xhci_hcd *xhci,
>> +        struct xhci_virt_device *virt_dev,
>> +        unsigned int ep_index)
>> +{
>> +    struct xhci_virt_ep *xep;
>> +    struct xhci_interrupter *ir;
>> +
>> +    xep = &virt_dev->eps[ep_index];
>> +    ir = xhci_pick_ep_interrupter(xhci, ep_index);
>> +
>> +    xep->interrupter = ir;
>> +}
> 
> This helper doesn't do much.
> Can be skipped.
> 
>> +
>>   /* Set up an endpoint with one ring segment.  Do not allocate stream 
>> rings.
>>    * Drivers will have to call usb_alloc_streams() to do that.
>>    */
>> @@ -1511,6 +1541,9 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
>>       ep_ctx->tx_info = 
>> cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
>>                         EP_AVG_TRB_LENGTH(avg_trb_len));
>> +    /* bind endpoint to an interrupter once at enable time */
>> +    xhci_bind_ep_interrupter(xhci, virt_dev, ep_index);
>> +
>>       return 0;
>>   }
>> @@ -1902,17 +1935,31 @@ 
>> EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
>>   void xhci_mem_cleanup(struct xhci_hcd *xhci)
>>   {
>>       struct device    *dev = xhci_to_hcd(xhci)->self.sysdev;
>> +    struct usb_hcd  *hcd = xhci_to_hcd(xhci);
>>       int i, j, num_ports;
>>       cancel_delayed_work_sync(&xhci->cmd_timer);
>> -    for (i = 0; xhci->interrupters && i < xhci->max_interrupters; i++) {
>> -        if (xhci->interrupters[i]) {
>> -            xhci_remove_interrupter(xhci, xhci->interrupters[i]);
>> -            xhci_free_interrupter(xhci, xhci->interrupters[i]);
>> -            xhci->interrupters[i] = NULL;
>> +    if (xhci->interrupters && xhci->interrupters[0]) {
>> +        xhci_remove_interrupter(xhci, xhci->interrupters[0]);
>> +        xhci_free_interrupter(xhci, xhci->interrupters[0]);
>> +        xhci->interrupters[0] = NULL;
>> +    }
>> +
>> +    for (i = 0; xhci->xfer_interrupters && i < xhci->xfer_irq_num; i+ 
>> +) {
>> +        if (xhci->xfer_interrupters[i]) {
>> +            xhci_remove_secondary_interrupter(hcd, xhci- 
>> >xfer_interrupters[i]);
>> +            xhci->xfer_interrupters[i] = NULL;
>>           }
>>       }
>> +
>> +    if (xhci->xfer_irq_num) {
>> +        kfree(xhci->xfer_interrupters);
>> +        xhci->xfer_interrupters = NULL;
>> +        xhci->xfer_irq_num = 0;
>> +        atomic_set(&xhci->next_xfer_intr, 0);
> 
> Hmm, so we now have two arrays of interrupters
>    xhci->interrupters[]
>    xhci->xfer_interripters[]
> 
> And some variables to keep track how many xhci interrupters are allocated,
> and others to show how man actual interrupt vectors are in use.
> 
> I don't have a better way out of the box but it seems like
> like there probably is a neater way to do this.
> 
> 
>> +    }
>> +
>>       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed interrupters");
>>       if (xhci->cmd_ring)
>> @@ -2412,6 +2459,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t 
>> flags)
>>   {
>>       struct device    *dev = xhci_to_hcd(xhci)->self.sysdev;
>>       dma_addr_t    dma;
>> +    int        i;
>>       /*
>>        * xHCI section 5.4.6 - Device Context array must be
>> @@ -2505,6 +2553,34 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t 
>> flags)
>>       if (!xhci->interrupters[0])
>>           goto fail;
>> +    /*
>> +     * Allocate secondary interrupters [1..max_interrupters-1].
>> +     * Cap by num_online_cpus() to avoid excessive vectors.
>> +     */
>> +    xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocating secondary 
>> event ring");
>> +    if (xhci->max_interrupters > 1) {
>> +        xhci->xfer_irq_num = min(num_online_cpus(),
>> +                    (unsigned int)xhci->max_interrupters - 1);
>> +        xhci->xfer_interrupters = kcalloc_node(xhci->xfer_irq_num,
>> +                sizeof(*xhci->xfer_interrupters),
>> +                flags, dev_to_node(dev));
>> +
>> +        if (!xhci->xfer_interrupters)
>> +            goto fail;
>> +    } else
>> +        xhci->xfer_irq_num = 0;
>> +
>> +    for (i = 0; i < xhci->xfer_irq_num; i++) {
>> +        struct xhci_interrupter *ir;
>> +        /* Create secondary interrupter with intr_num = i + 1. */
>> +        ir = xhci_create_secondary_interrupter(xhci_to_hcd(xhci),
>> +                i + 1, xhci->imod_interval, 0);
>> +        if (!ir)
>> +            goto fail;
> 
> Don't fail completely just because we can't get a secondary interrupter.
> Roll back to only using primary, or use fewer secondary interrupters
> 
> At this stage we don't yet know if hardware really can provide the actual
> interrupt vectors, and if request_irq() will be successful.
> 
> xhci->nvecs could be useful here, but it is not yet set.
> 
> Could allocating the xhci secondary interrupters and call request_irq()
> be done in the same loop in xhci_pci_run()?
> 
> That would simpify things.
> 
> Note, Niklas was looking at this idea recently, and pointed out is
> would need changes to xhci_resume() power_lost path
> 
> Thanks
> Mathias
> 

-- 
Kenneth R. Crudup / Sr. SW Engineer, Scott County Consulting, Orange 
County CA


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] usb: xhci: route endpoints to secondary interrupters
  2025-12-18 17:01   ` Kenneth Crudup
@ 2025-12-22 16:33     ` Kenneth Crudup
  2025-12-22 17:54       ` Kenneth Crudup
  0 siblings, 1 reply; 6+ messages in thread
From: Kenneth Crudup @ 2025-12-22 16:33 UTC (permalink / raw)
  To: Mathias Nyman, raoxu
  Cc: gregkh, linux-usb, michal.pecio, niklas.neronin, zhanjun


I'm gonna have to jump in with a "NAK" as well; it breaks resuming from 
hibernation (and in a big way, system is totally frozen once the resume 
finishes, can't even force a core-dump via SysRq-C).

(My (totally-random) guess is that upon resume (and therefore, a 
power-cycle) the boot IRQs and the resumed-image IRQs are different, but 
I'd think this would also affect other blocks' IRQs, though.)

-K

On 12/18/25 09:01, Kenneth Crudup wrote:
> 
> FWIW, I rebased this (perhaps the previous spin?) for v.19-rc1 (see 
> attached) and tried it out, before I saw you guys' objections ... 
> whoops ... but FWIW, it seems to be working here OK (that being said, I 
> haven't had any USB errors so not sure what'll happen then, based on the 
> followup comments).
> 
> If nothing else, I'll run it 'till my next reboot at least and see if 
> there's any anomalies, but I guess you can put a "Tested-By" here?
> 
> Before, e.g.,:
> 
> ----
>   178:     675913          0          0          0          0          0 
>    12944781          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:0d.0    0-edge      xhci_hcd
>   186:    3286163          0          0          0          0          0 
>           0          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:14.0    0-edge      xhci_hcd
> ----
> 
> ... after (and after a couple of "Bonnie" runs):
> 
> ----
>   178:          0          0          0          0          0          0 
>        1470          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:0d.0    0-edge      xhci_hcd
>   179:          0          0          0          0          0          0 
>           0     369210          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:0d.0    1-edge      xhci_hcd
>   180:          0          0          0          0          0          0 
>           0          0     264964          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:0d.0    2-edge      xhci_hcd
>   181:          0          0          0          0          0          0 
>           0          0          0     632289          0          0    0 
>          0 IR-PCI-MSI-0000:00:0d.0    3-edge      xhci_hcd
>   182:          0          0          0          0          0          0 
>           0          0          0          0     557895          0    0 
>          0 IR-PCI-MSI-0000:00:0d.0    4-edge      xhci_hcd
>   183:          0          0          0          0          0          0 
>           0          0          0          0          0      75643    0 
>          0 IR-PCI-MSI-0000:00:0d.0    5-edge      xhci_hcd
>   184:          0          0          0          0          0          0 
>           0          0          0          0          0          0 9806 
>          0 IR-PCI-MSI-0000:00:0d.0    6-edge      xhci_hcd
>   185:          0          0          0          0          0          0 
>           0          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:0d.0    7-edge      xhci_hcd
>   186:        935          0          0          0          0          0 
>           0          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:14.0    0-edge      xhci_hcd
>   187:          0      48742          0          0          0          0 
>           0          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:14.0    1-edge      xhci_hcd
>   188:          0          0      30631          0          0          0 
>           0          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:14.0    2-edge      xhci_hcd
>   189:          0          0          0          0          0          0 
>           0          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:14.0    3-edge      xhci_hcd
>   190:          0          0          0          0          0          0 
>           0          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:14.0    4-edge      xhci_hcd
>   191:          0          0          0          0          0        157 
>           0          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:14.0    5-edge      xhci_hcd
>   192:          0          0          0          0          0          0 
>        4820          0          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:14.0    6-edge      xhci_hcd
>   193:          0          0          0          0          0          0 
>           0       2915          0          0          0          0    0 
>          0 IR-PCI-MSI-0000:00:14.0    7-edge      xhci_hcd
> ----
> 
> -K
> 
> On 12/18/25 07:49, Mathias Nyman wrote:
>> Hi Xu Rao
>>
>> Thanks for the updated version
>>
>> On 12/17/25 11:46, raoxu wrote:
>>> From: Xu Rao <raoxu@uniontech.com>
>>>
>>> Some xHCI hosts expose multiple MSI/MSI-X vectors, but the driver
>>> currently routes all transfer completions through interrupter 0.
>>> This can lead to unnecessary contention on the primary event ring
>>> and IRQ vector.
>>>
>>> If the host reports more than one interrupter, allocate secondary
>>> interrupters [1..max_interrupters-1] and cap the number of created
>>> interrupters by num_online_cpus(). Each secondary interrupter has
>>> its own event ring and can be requested as a separate IRQ vector.
>>
>> This can lead to excessive amounts of interrupters on systems that
>> usually don't really use usb that much.
>>
>> 96 core systems would have 96 interrupters, each with an 8k event ring
>> to serve maybe one usb keyboard.
>>
>> Lets start with something simple like 2 or 4 interrupters.
>>
>>>
>>> An interrupter is bound to each endpoint once at endpoint enable
>>> time. EP0 is always kept on interrupter 0, while all other endpoints
>>> are assigned in a round-robin fashion over the enabled secondary
>>> interrupters. Multiple endpoints may therefore share the same
>>> interrupter.
>>
>> I think it would be better to assign a whole USB device to the same
>> interrupter, and set the "Interrupter Target" field in the slot
>> context to that interrupter.
>>
>> This way special transfer events such as 'ring overrun' and 'ring 
>> underrun'
>> will end up on the same event ring as the rest of the transfer events for
>> that endpoint, and avoid some of the issues Michal pointed out.
>>
>>>
>>> Interrupt routing is performed by programming TRB_INTR_TARGET()
>>> from the endpoint's bound interrupter number when queueing TRBs.
>>> As a result, transfer completions are delivered to the event ring
>>> (and IRQ vector) of the selected interrupter instead of always
>>> landing on interrupter 0.
>>>
>>> All interrupters share a common IRQ handler. STS_EINT is only
>>> checked and cleared for interrupter 0, as it is only meaningful
>>> for the primary interrupter. Secondary MSI/MSI-X vectors may fire
>>> independently and simply process their associated event rings.
>>>
>>> When requesting IRQs, the usb_hcd pointer is used as the dev_id
>>> for both primary and secondary vectors. Although each secondary
>>> interrupter has its own event ring, using per-interrupter dev_id
>>> objects complicates teardown ordering in xhci_cleanup_msix().
>>> In particular, IRQs must be freed before the corresponding
>>> interrupter structures are removed, and the existing cleanup
>>> sequence imposes constraints on dev_id lifetime. Using a common
>>> dev_id avoids dev_id mismatches during free_irq() and keeps the
>>> IRQ teardown consistent with the current xHCI removal flow.
>>>
>>> Testing on an MSI-X capable host controller shows that interrupts
>>> are effectively distributed across secondary vectors. For example,
>>> after sustained USB transfers:
>>>
>>>    /proc/interrupts (filtered):
>>>      32:          0          0          0          0 0          0 \
>>>            0        522  IR-PCI-MSIX-0000:03:00.3  0-edge  xhci_hcd
>>>      33:      12297          0          0          0 0          0 \
>>>            0          0  IR-PCI-MSIX-0000:03:00.3  1-edge  xhci_hcd
>>>      34:          0      17082          0          0 0          0 \
>>>            0          0  IR-PCI-MSIX-0000:03:00.3  2-edge  xhci_hcd
>>>      35:          0          0      27567          0 0          0 \
>>>            0          0  IR-PCI-MSIX-0000:03:00.3  3-edge  xhci_hcd
>>>      36:          0          0          0      33234 0          0 \
>>>            0          0  IR-PCI-MSIX-0000:03:00.3  4-edge  xhci_hcd
>>>      37:          0          0          0          0 1519411          
>>> 0 \
>>>            0          0  IR-PCI-MSIX-0000:03:00.3  5-edge  xhci_hcd
>>>
>>> This demonstrates that transfer completions are no longer handled
>>> exclusively by interrupter 0, but are instead distributed across
>>> multiple MSI-X vectors.
>>>
>>> Signed-off-by: Xu Rao <raoxu@uniontech.com>
>>> ---
>>> Changelog:
>>> v1 -> v2:
>>>    - Bind interrupters to endpoints at enable time instead of selecting
>>>      per transfer.
>>>    - Store the selected interrupter in struct xhci_virt_ep and program
>>>      TRB_INTR_TARGET() from the bound interrupter.
>>>    - Use a single IRQ handler for both primary and secondary vectors,
>>>      with STS_EINT handling restricted to interrupter 0.
>>>    - Keep a common dev_id for IRQ registration to match the existing
>>>      xhci_cleanup_msix() teardown constraints and avoid dev_id
>>>      lifetime issues.
>>>    - Clarify secondary interrupter teardown to avoid double-free or
>>>      use-after-free during xHCI removal.
>>> v2 -> v3:
>>>    - modify commit information
>>> ---
>>>   drivers/usb/host/xhci-mem.c  | 86 +++++++++++++++++++++++++++++++++---
>>>   drivers/usb/host/xhci-pci.c  | 28 ++++++++++++
>>>   drivers/usb/host/xhci-ring.c | 79 ++++++++++++++++++++++++---------
>>>   drivers/usb/host/xhci.c      | 38 ++++++++++++++++
>>>   drivers/usb/host/xhci.h      |  7 +++
>>>   5 files changed, 212 insertions(+), 26 deletions(-)
>>>
>>> diff --git a/drivers/usb/host/xhci-mem.c b/drivers/usb/host/xhci-mem.c
>>> index c4a6544aa107..277d395c03b8 100644
>>> --- a/drivers/usb/host/xhci-mem.c
>>> +++ b/drivers/usb/host/xhci-mem.c
>>> @@ -1408,6 +1408,36 @@ static u32 xhci_get_max_esit_payload(struct 
>>> usb_device *udev,
>>>       return max_packet * max_burst;
>>>   }
>>> +/* Pick an interrupter for an endpoint (EP0 always stays on 
>>> interrupter 0). */
>>> +static struct xhci_interrupter *
>>> +xhci_pick_ep_interrupter(struct xhci_hcd *xhci, unsigned int ep_index)
>>> +{
>>> +    unsigned int idx;
>>> +
>>> +    /* Keep EP0 on primary interrupter */
>>> +    if (ep_index == 0 || !xhci->nr_xfer_interrupters)
>>> +        return xhci->interrupters[0];
>>> +
>>> +    /* round-robin over enabled secondary interrupters */
>>> +    idx = (unsigned int)atomic_inc_return(&xhci->next_xfer_intr);
>>> +    idx = (idx - 1) % xhci->nr_xfer_interrupters;
>>> +    return xhci->xfer_interrupters[idx] ?: xhci->interrupters[0];
>>> +}
>>
>> Set same interrupter for a whole device instead of round-robin for 
>> endpoints.
>> Skip the atomic_inc_return and whole atomic variable and do something 
>> like:
>> idx = slot_id % number_of_interrupters;
>>
>>> +
>>> +/* Bind the endpoint to one interrupter at enable time. */
>>> +static void xhci_bind_ep_interrupter(struct xhci_hcd *xhci,
>>> +        struct xhci_virt_device *virt_dev,
>>> +        unsigned int ep_index)
>>> +{
>>> +    struct xhci_virt_ep *xep;
>>> +    struct xhci_interrupter *ir;
>>> +
>>> +    xep = &virt_dev->eps[ep_index];
>>> +    ir = xhci_pick_ep_interrupter(xhci, ep_index);
>>> +
>>> +    xep->interrupter = ir;
>>> +}
>>
>> This helper doesn't do much.
>> Can be skipped.
>>
>>> +
>>>   /* Set up an endpoint with one ring segment.  Do not allocate 
>>> stream rings.
>>>    * Drivers will have to call usb_alloc_streams() to do that.
>>>    */
>>> @@ -1511,6 +1541,9 @@ int xhci_endpoint_init(struct xhci_hcd *xhci,
>>>       ep_ctx->tx_info = 
>>> cpu_to_le32(EP_MAX_ESIT_PAYLOAD_LO(max_esit_payload) |
>>>                         EP_AVG_TRB_LENGTH(avg_trb_len));
>>> +    /* bind endpoint to an interrupter once at enable time */
>>> +    xhci_bind_ep_interrupter(xhci, virt_dev, ep_index);
>>> +
>>>       return 0;
>>>   }
>>> @@ -1902,17 +1935,31 @@ 
>>> EXPORT_SYMBOL_GPL(xhci_remove_secondary_interrupter);
>>>   void xhci_mem_cleanup(struct xhci_hcd *xhci)
>>>   {
>>>       struct device    *dev = xhci_to_hcd(xhci)->self.sysdev;
>>> +    struct usb_hcd  *hcd = xhci_to_hcd(xhci);
>>>       int i, j, num_ports;
>>>       cancel_delayed_work_sync(&xhci->cmd_timer);
>>> -    for (i = 0; xhci->interrupters && i < xhci->max_interrupters; i+ 
>>> +) {
>>> -        if (xhci->interrupters[i]) {
>>> -            xhci_remove_interrupter(xhci, xhci->interrupters[i]);
>>> -            xhci_free_interrupter(xhci, xhci->interrupters[i]);
>>> -            xhci->interrupters[i] = NULL;
>>> +    if (xhci->interrupters && xhci->interrupters[0]) {
>>> +        xhci_remove_interrupter(xhci, xhci->interrupters[0]);
>>> +        xhci_free_interrupter(xhci, xhci->interrupters[0]);
>>> +        xhci->interrupters[0] = NULL;
>>> +    }
>>> +
>>> +    for (i = 0; xhci->xfer_interrupters && i < xhci->xfer_irq_num; 
>>> i+ +) {
>>> +        if (xhci->xfer_interrupters[i]) {
>>> +            xhci_remove_secondary_interrupter(hcd, xhci- 
>>> >xfer_interrupters[i]);
>>> +            xhci->xfer_interrupters[i] = NULL;
>>>           }
>>>       }
>>> +
>>> +    if (xhci->xfer_irq_num) {
>>> +        kfree(xhci->xfer_interrupters);
>>> +        xhci->xfer_interrupters = NULL;
>>> +        xhci->xfer_irq_num = 0;
>>> +        atomic_set(&xhci->next_xfer_intr, 0);
>>
>> Hmm, so we now have two arrays of interrupters
>>    xhci->interrupters[]
>>    xhci->xfer_interripters[]
>>
>> And some variables to keep track how many xhci interrupters are 
>> allocated,
>> and others to show how man actual interrupt vectors are in use.
>>
>> I don't have a better way out of the box but it seems like
>> like there probably is a neater way to do this.
>>
>>
>>> +    }
>>> +
>>>       xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Freed interrupters");
>>>       if (xhci->cmd_ring)
>>> @@ -2412,6 +2459,7 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t 
>>> flags)
>>>   {
>>>       struct device    *dev = xhci_to_hcd(xhci)->self.sysdev;
>>>       dma_addr_t    dma;
>>> +    int        i;
>>>       /*
>>>        * xHCI section 5.4.6 - Device Context array must be
>>> @@ -2505,6 +2553,34 @@ int xhci_mem_init(struct xhci_hcd *xhci, gfp_t 
>>> flags)
>>>       if (!xhci->interrupters[0])
>>>           goto fail;
>>> +    /*
>>> +     * Allocate secondary interrupters [1..max_interrupters-1].
>>> +     * Cap by num_online_cpus() to avoid excessive vectors.
>>> +     */
>>> +    xhci_dbg_trace(xhci, trace_xhci_dbg_init, "Allocating secondary 
>>> event ring");
>>> +    if (xhci->max_interrupters > 1) {
>>> +        xhci->xfer_irq_num = min(num_online_cpus(),
>>> +                    (unsigned int)xhci->max_interrupters - 1);
>>> +        xhci->xfer_interrupters = kcalloc_node(xhci->xfer_irq_num,
>>> +                sizeof(*xhci->xfer_interrupters),
>>> +                flags, dev_to_node(dev));
>>> +
>>> +        if (!xhci->xfer_interrupters)
>>> +            goto fail;
>>> +    } else
>>> +        xhci->xfer_irq_num = 0;
>>> +
>>> +    for (i = 0; i < xhci->xfer_irq_num; i++) {
>>> +        struct xhci_interrupter *ir;
>>> +        /* Create secondary interrupter with intr_num = i + 1. */
>>> +        ir = xhci_create_secondary_interrupter(xhci_to_hcd(xhci),
>>> +                i + 1, xhci->imod_interval, 0);
>>> +        if (!ir)
>>> +            goto fail;
>>
>> Don't fail completely just because we can't get a secondary interrupter.
>> Roll back to only using primary, or use fewer secondary interrupters
>>
>> At this stage we don't yet know if hardware really can provide the actual
>> interrupt vectors, and if request_irq() will be successful.
>>
>> xhci->nvecs could be useful here, but it is not yet set.
>>
>> Could allocating the xhci secondary interrupters and call request_irq()
>> be done in the same loop in xhci_pci_run()?
>>
>> That would simpify things.
>>
>> Note, Niklas was looking at this idea recently, and pointed out is
>> would need changes to xhci_resume() power_lost path
>>
>> Thanks
>> Mathias
>>
> 

-- 
Kenneth R. Crudup / Sr. SW Engineer, Scott County Consulting, Orange 
County CA


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH v3] usb: xhci: route endpoints to secondary interrupters
  2025-12-22 16:33     ` Kenneth Crudup
@ 2025-12-22 17:54       ` Kenneth Crudup
  0 siblings, 0 replies; 6+ messages in thread
From: Kenneth Crudup @ 2025-12-22 17:54 UTC (permalink / raw)
  To: Mathias Nyman, raoxu
  Cc: gregkh, linux-usb, michal.pecio, niklas.neronin, zhanjun

[-- Attachment #1: Type: text/plain, Size: 3188 bytes --]


> I'm gonna have to jump in with a "NAK" as well; it breaks resuming from 
> hibernation (and in a big way, system is totally frozen once the resume 
> finishes, can't even force a core-dump via SysRq-C).

I'd forgotten that I'd switched to SystemD's pstore dumper from my 
custom one, so the good news is I do have crash dumps. I've attached one 
of them but here's a snippet of what happened after resume:

----
...
<6>[  652.406001][ T3671] ACPI: EC: event unblocked
<5>[  652.406137][ T3715] usb usb1: root hub lost power or was reset
Panic#1 Part8
<5>[  652.406140][ T3715] usb usb2: root hub lost power or was reset
<5>[  652.406301][ T3717] usb usb3: root hub lost power or was reset
<5>[  652.406303][ T3717] usb usb4: root hub lost power or was reset
<3>[  652.407181][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not 
required
<3>[  652.407191][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not 
required
<3>[  652.407200][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not 
required
<3>[  652.407208][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not 
required
<3>[  652.407218][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not 
required
<3>[  652.407225][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not 
required
<3>[  652.407233][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not 
required
<3>[  652.407453][ T3717] xhci_hcd 0000:00:14.0: event ring handling not 
required
<3>[  652.407469][ T3717] xhci_hcd 0000:00:14.0: event ring handling not 
required
<3>[  652.407481][ T3717] xhci_hcd 0000:00:14.0: event ring handling not 
required
<3>[  652.407495][ T3717] xhci_hcd 0000:00:14.0: event ring handling not 
required
<3>[  652.407509][ T3717] xhci_hcd 0000:00:14.0: event ring handling not 
required
<3>[  652.407521][ T3717] xhci_hcd 0000:00:14.0: event ring handling not 
required
<3>[  652.407533][ T3717] xhci_hcd 0000:00:14.0: event ring handling not 
required
<3>[  652.427396][    C0] xhci_hcd 0000:00:14.0: ERROR interrupter event 
ring not ready
<4>[  652.479668][ T3721] pcieport 10000:e0:06.0: can't derive routing 
for PCI INT A
<4>[  652.479670][ T3721] nvme 10000:e1:00.0: PCI INT A: no GSI
<6>[  652.492540][ T3721] nvme nvme0: 20/0/0 default/read/poll queues
Panic#1 Part7
<3>[  652.516347][    C0] xhci_hcd 0000:00:0d.0: ERROR interrupter event 
ring not ready
<6>[  652.964456][ T3740] ish-hid 
{33AECD58-B679-4E54-9BD9-A04D34F0C226}: [hid-ish]: enum_devices_done OK, 
num_hid_devic
es=2
<3>[  660.081555][ T3719] xhci_hcd 0000:00:0d.0: Error while assigning 
device slot ID: Command Aborted
<3>[  660.081562][ T3719] xhci_hcd 0000:00:0d.0: Max number of devices 
this xHCI host supports is 64.
<3>[  660.081580][ T3717] xhci_hcd 0000:00:14.0: Error while assigning 
device slot ID: Command Aborted
<3>[  660.081583][ T3729] xhci_hcd 0000:00:14.0: Error while assigning 
device slot ID: Command Aborted
<3>[  660.081586][ T3717] xhci_hcd 0000:00:14.0: Max number of devices 
this xHCI host supports is 64.
<3>[  660.081590][ T3729] xhci_hcd 0000:00:14.0: Max number of devices 
this xHCI host supports is 64.
...
----

-Kenny



-- 
Kenneth R. Crudup / Sr. SW Engineer, Scott County Consulting, Orange 
County CA

[-- Attachment #2: dmesg.txt --]
[-- Type: text/plain, Size: 39868 bytes --]

Panic#1 Part24
<6>[   12.095868][  T191] pci 0000:41:04.0: supports D1 D2
<6>[   12.095869][  T191] pci 0000:41:04.0: PME# supported from D0 D1 D2 D3hot D3cold
<6>[   12.096122][  T191] pci 0000:41:04.0: Adding to iommu group 22
<6>[   12.096199][  T191] pci 0000:40:00.0: PCI bridge to [bus 41-7e]
<6>[   12.096218][  T191] pci 0000:41:00.0: bridge configuration invalid ([bus 00-00]), reconfiguring
<6>[   12.096229][  T191] pci 0000:41:01.0: bridge configuration invalid ([bus 00-00]), reconfiguring
<6>[   12.096239][  T191] pci 0000:41:02.0: bridge configuration invalid ([bus 00-00]), reconfiguring
<6>[   12.096250][  T191] pci 0000:41:03.0: bridge configuration invalid ([bus 00-00]), reconfiguring
<6>[   12.096260][  T191] pci 0000:41:04.0: bridge configuration invalid ([bus 00-00]), reconfiguring
<6>[   12.097213][  T191] pci 0000:41:00.0: PCI bridge to [bus 42-7e]
<6>[   12.097231][  T191] pci_bus 0000:42: busn_res: [bus 42-7e] end is updated to 42
<6>[   12.097323][  T191] pci 0000:41:01.0: PCI bridge to [bus 43-7e]
<6>[   12.097340][  T191] pci_bus 0000:43: busn_res: [bus 43-7e] end is updated to 56
<6>[   12.097445][  T191] pci 0000:41:02.0: PCI bridge to [bus 57-7e]
<6>[   12.097461][  T191] pci_bus 0000:57: busn_res: [bus 57-7e] end is updated to 6a
<6>[   12.097662][  T191] pci 0000:41:03.0: PCI bridge to [bus 6b-7e]
<6>[   12.097680][  T191] pci_bus 0000:6b: busn_res: [bus 6b-7e] end is updated to 7d
<6>[   12.097821][  T191] pci 0000:41:04.0: PCI bridge to [bus 7e]
<6>[   12.097839][  T191] pci_bus 0000:7e: busn_res: [bus 7e] end is updated to 7e
<6>[   12.097845][  T191] pci_bus 0000:41: busn_res: [bus 41-7e] end is updated to 7e
Panic#1 Part23
<6>[   12.097855][  T191] pci 0000:41:01.0: bridge window [mem 0x00100000-0x001fffff 64bit pref] to [bus 43-56] add_size 100000 add_align 100000
<6>[   12.097857][  T191] pci 0000:41:01.0: bridge window [mem 0x00100000-0x001fffff] to [bus 43-56] add_size 100000 add_align 100000
<6>[   12.097859][  T191] pci 0000:41:02.0: bridge window [mem 0x00100000-0x001fffff 64bit pref] to [bus 57-6a] add_size 100000 add_align 100000
<6>[   12.097860][  T191] pci 0000:41:02.0: bridge window [mem 0x00100000-0x001fffff] to [bus 57-6a] add_size 100000 add_align 100000
<6>[   12.097862][  T191] pci 0000:41:03.0: bridge window [mem 0x00100000-0x001fffff 64bit pref] to [bus 6b-7d] add_size 100000 add_align 100000
<6>[   12.097863][  T191] pci 0000:41:03.0: bridge window [mem 0x00100000-0x001fffff] to [bus 6b-7d] add_size 100000 add_align 100000
<6>[   12.097866][  T191] pci 0000:40:00.0: bridge window [mem 0x00100000-0x005fffff 64bit pref] to [bus 41-7e] add_size 300000 add_align 100000
<6>[   12.097868][  T191] pci 0000:40:00.0: bridge window [mem 0x00100000-0x005fffff] to [bus 41-7e] add_size 300000 add_align 100000
<6>[   12.097873][  T191] pci 0000:40:00.0: bridge window [mem 0x74000000-0x801fffff]: assigned
<6>[   12.097875][  T191] pci 0000:40:00.0: bridge window [mem 0x6020000000-0x603bffffff 64bit pref]: assigned
<6>[   12.097876][  T191] pci 0000:40:00.0: bridge window [io  size 0x5000]: can't assign; no space
<6>[   12.097878][  T191] pci 0000:40:00.0: bridge window [io  size 0x5000]: failed to assign
<6>[   12.097879][  T191] pci 0000:40:00.0: bridge window [io  size 0x5000]: can't assign; no space
Panic#1 Part22
<6>[   12.097879][  T191] pci 0000:40:00.0: bridge window [io  size 0x5000]: failed to assign
<6>[   12.097883][  T191] pci 0000:41:00.0: bridge window [mem 0x74000000-0x740fffff]: assigned
<6>[   12.097885][  T191] pci 0000:41:00.0: bridge window [mem 0x6020000000-0x60200fffff 64bit pref]: assigned
<6>[   12.097886][  T191] pci 0000:41:01.0: bridge window [mem 0x74100000-0x780fffff]: assigned
<6>[   12.097887][  T191] pci 0000:41:01.0: bridge window [mem 0x6020100000-0x60294fffff 64bit pref]: assigned
<6>[   12.097888][  T191] pci 0000:41:02.0: bridge window [mem 0x78100000-0x7c0fffff]: assigned
<6>[   12.097889][  T191] pci 0000:41:02.0: bridge window [mem 0x6029500000-0x60328fffff 64bit pref]: assigned
<6>[   12.097890][  T191] pci 0000:41:03.0: bridge window [mem 0x7c100000-0x800fffff]: assigned
<6>[   12.097891][  T191] pci 0000:41:03.0: bridge window [mem 0x6032900000-0x603bcfffff 64bit pref]: assigned
<6>[   12.097892][  T191] pci 0000:41:04.0: bridge window [mem 0x80100000-0x801fffff]: assigned
<6>[   12.097893][  T191] pci 0000:41:04.0: bridge window [mem 0x603bd00000-0x603bdfffff 64bit pref]: assigned
<6>[   12.097894][  T191] pci 0000:41:00.0: bridge window [io  size 0x1000]: can't assign; no space
<6>[   12.097894][  T191] pci 0000:41:00.0: bridge window [io  size 0x1000]: failed to assign
<6>[   12.097895][  T191] pci 0000:41:01.0: bridge window [io  size 0x1000]: can't assign; no space
<6>[   12.097896][  T191] pci 0000:41:01.0: bridge window [io  size 0x1000]: failed to assign
<6>[   12.097897][  T191] pci 0000:41:02.0: bridge window [io  size 0x1000]: can't assign; no space
Panic#1 Part21
<6>[   12.097898][  T191] pci 0000:41:02.0: bridge window [io  size 0x1000]: failed to assign
<6>[   12.097898][  T191] pci 0000:41:03.0: bridge window [io  size 0x1000]: can't assign; no space
<6>[   12.097899][  T191] pci 0000:41:03.0: bridge window [io  size 0x1000]: failed to assign
<6>[   12.097900][  T191] pci 0000:41:04.0: bridge window [io  size 0x1000]: can't assign; no space
<6>[   12.097901][  T191] pci 0000:41:04.0: bridge window [io  size 0x1000]: failed to assign
<6>[   12.097902][  T191] pci 0000:41:00.0: bridge window [io  size 0x1000]: can't assign; no space
<6>[   12.097903][  T191] pci 0000:41:00.0: bridge window [io  size 0x1000]: failed to assign
<6>[   12.097904][  T191] pci 0000:41:01.0: bridge window [io  size 0x1000]: can't assign; no space
<6>[   12.097904][  T191] pci 0000:41:01.0: bridge window [io  size 0x1000]: failed to assign
<6>[   12.097905][  T191] pci 0000:41:02.0: bridge window [io  size 0x1000]: can't assign; no space
<6>[   12.097906][  T191] pci 0000:41:02.0: bridge window [io  size 0x1000]: failed to assign
<6>[   12.097907][  T191] pci 0000:41:03.0: bridge window [io  size 0x1000]: can't assign; no space
<6>[   12.097907][  T191] pci 0000:41:03.0: bridge window [io  size 0x1000]: failed to assign
<6>[   12.097908][  T191] pci 0000:41:04.0: bridge window [io  size 0x1000]: can't assign; no space
<6>[   12.097909][  T191] pci 0000:41:04.0: bridge window [io  size 0x1000]: failed to assign
<6>[   12.097910][  T191] pci 0000:41:00.0: PCI bridge to [bus 42]
<6>[   12.097916][  T191] pci 0000:41:00.0:   bridge window [mem 0x74000000-0x740fffff]
Panic#1 Part20
<6>[   12.097920][  T191] pci 0000:41:00.0:   bridge window [mem 0x6020000000-0x60200fffff 64bit pref]
<6>[   12.097928][  T191] pci 0000:41:01.0: PCI bridge to [bus 43-56]
<6>[   12.097934][  T191] pci 0000:41:01.0:   bridge window [mem 0x74100000-0x780fffff]
<6>[   12.097938][  T191] pci 0000:41:01.0:   bridge window [mem 0x6020100000-0x60294fffff 64bit pref]
<6>[   12.097945][  T191] pci 0000:41:02.0: PCI bridge to [bus 57-6a]
<6>[   12.097951][  T191] pci 0000:41:02.0:   bridge window [mem 0x78100000-0x7c0fffff]
<6>[   12.097955][  T191] pci 0000:41:02.0:   bridge window [mem 0x6029500000-0x60328fffff 64bit pref]
<6>[   12.097962][  T191] pci 0000:41:03.0: PCI bridge to [bus 6b-7d]
<6>[   12.097968][  T191] pci 0000:41:03.0:   bridge window [mem 0x7c100000-0x800fffff]
<6>[   12.097972][  T191] pci 0000:41:03.0:   bridge window [mem 0x6032900000-0x603bcfffff 64bit pref]
<6>[   12.097979][  T191] pci 0000:41:04.0: PCI bridge to [bus 7e]
<6>[   12.097984][  T191] pci 0000:41:04.0:   bridge window [mem 0x80100000-0x801fffff]
<6>[   12.097988][  T191] pci 0000:41:04.0:   bridge window [mem 0x603bd00000-0x603bdfffff 64bit pref]
<6>[   12.097996][  T191] pci 0000:40:00.0: PCI bridge to [bus 41-7e]
<6>[   12.098001][  T191] pci 0000:40:00.0:   bridge window [mem 0x74000000-0x801fffff]
<6>[   12.098005][  T191] pci 0000:40:00.0:   bridge window [mem 0x6020000000-0x603bffffff 64bit pref]
<6>[   12.098013][  T191] pcieport 0000:00:07.2: PCI bridge to [bus 40-7e]
<6>[   12.098014][  T191] pcieport 0000:00:07.2:   bridge window [io  0x5000-0x8fff]
<6>[   12.098016][  T191] pcieport 0000:00:07.2:   bridge window [mem 0x74000000-0x801fffff]
Panic#1 Part19
<6>[   12.098018][  T191] pcieport 0000:00:07.2:   bridge window [mem 0x6020000000-0x603bffffff 64bit pref]
<6>[   12.098021][  T191] PCI: No. 2 try to assign unassigned res
<6>[   12.098023][  T191] pcieport 0000:00:07.2: bridge window [io  0x5000-0x8fff]: releasing
<6>[   12.098031][  T191] pcieport 0000:00:07.2: bridge window [io  0x5000-0x9fff]: assigned
<6>[   12.098032][  T191] pci 0000:40:00.0: bridge window [io  0x5000-0x9fff]: assigned
<6>[   12.098034][  T191] pci 0000:41:00.0: bridge window [io  0x5000-0x5fff]: assigned
<6>[   12.098035][  T191] pci 0000:41:01.0: bridge window [io  0x6000-0x6fff]: assigned
<6>[   12.098036][  T191] pci 0000:41:02.0: bridge window [io  0x7000-0x7fff]: assigned
<6>[   12.098037][  T191] pci 0000:41:03.0: bridge window [io  0x8000-0x8fff]: assigned
<6>[   12.098038][  T191] pci 0000:41:04.0: bridge window [io  0x9000-0x9fff]: assigned
<6>[   12.098039][  T191] pci 0000:41:00.0: PCI bridge to [bus 42]
<6>[   12.098041][  T191] pci 0000:41:00.0:   bridge window [io  0x5000-0x5fff]
<6>[   12.098047][  T191] pci 0000:41:00.0:   bridge window [mem 0x74000000-0x740fffff]
<6>[   12.098051][  T191] pci 0000:41:00.0:   bridge window [mem 0x6020000000-0x60200fffff 64bit pref]
<6>[   12.098058][  T191] pci 0000:41:01.0: PCI bridge to [bus 43-56]
<6>[   12.098060][  T191] pci 0000:41:01.0:   bridge window [io  0x6000-0x6fff]
<6>[   12.098066][  T191] pci 0000:41:01.0:   bridge window [mem 0x74100000-0x780fffff]
<6>[   12.098070][  T191] pci 0000:41:01.0:   bridge window [mem 0x6020100000-0x60294fffff 64bit pref]
<6>[   12.098077][  T191] pci 0000:41:02.0: PCI bridge to [bus 57-6a]
Panic#1 Part18
<6>[   12.098080][  T191] pci 0000:41:02.0:   bridge window [io  0x7000-0x7fff]
<6>[   12.098085][  T191] pci 0000:41:02.0:   bridge window [mem 0x78100000-0x7c0fffff]
<6>[   12.098089][  T191] pci 0000:41:02.0:   bridge window [mem 0x6029500000-0x60328fffff 64bit pref]
<6>[   12.098096][  T191] pci 0000:41:03.0: PCI bridge to [bus 6b-7d]
<6>[   12.098099][  T191] pci 0000:41:03.0:   bridge window [io  0x8000-0x8fff]
<6>[   12.098104][  T191] pci 0000:41:03.0:   bridge window [mem 0x7c100000-0x800fffff]
<6>[   12.098108][  T191] pci 0000:41:03.0:   bridge window [mem 0x6032900000-0x603bcfffff 64bit pref]
<6>[   12.098116][  T191] pci 0000:41:04.0: PCI bridge to [bus 7e]
<6>[   12.098118][  T191] pci 0000:41:04.0:   bridge window [io  0x9000-0x9fff]
<6>[   12.098123][  T191] pci 0000:41:04.0:   bridge window [mem 0x80100000-0x801fffff]
<6>[   12.098127][  T191] pci 0000:41:04.0:   bridge window [mem 0x603bd00000-0x603bdfffff 64bit pref]
<6>[   12.098135][  T191] pci 0000:40:00.0: PCI bridge to [bus 41-7e]
<6>[   12.098137][  T191] pci 0000:40:00.0:   bridge window [io  0x5000-0x9fff]
<6>[   12.098143][  T191] pci 0000:40:00.0:   bridge window [mem 0x74000000-0x801fffff]
<6>[   12.098147][  T191] pci 0000:40:00.0:   bridge window [mem 0x6020000000-0x603bffffff 64bit pref]
<6>[   12.098154][  T191] pcieport 0000:00:07.2: PCI bridge to [bus 40-7e]
<6>[   12.098155][  T191] pcieport 0000:00:07.2:   bridge window [io  0x5000-0x9fff]
<6>[   12.098157][  T191] pcieport 0000:00:07.2:   bridge window [mem 0x74000000-0x801fffff]
<6>[   12.098159][  T191] pcieport 0000:00:07.2:   bridge window [mem 0x6020000000-0x603bffffff 64bit pref]
Panic#1 Part17
<6>[   12.098378][  T191] pcieport 0000:40:00.0: enabling device (0000 -> 0003)
<6>[   12.098705][  T191] pcieport 0000:41:00.0: enabling device (0000 -> 0003)
<6>[   12.099020][  T191] pcieport 0000:41:01.0: enabling device (0000 -> 0003)
<6>[   12.099197][  T191] pcieport 0000:41:01.0: pciehp: Slot #1 AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+ Interlock- NoCompl+ IbPresDis- LLActRep+
<6>[   12.099498][  T191] pcieport 0000:41:02.0: enabling device (0000 -> 0003)
<6>[   12.099732][  T191] pcieport 0000:41:02.0: pciehp: Slot #2 AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+ Interlock- NoCompl+ IbPresDis- LLActRep+
<6>[   12.100016][  T191] pcieport 0000:41:03.0: enabling device (0000 -> 0003)
<6>[   12.100191][  T191] pcieport 0000:41:03.0: pciehp: Slot #3 AttnBtn- PwrCtrl- MRL- AttnInd- PwrInd- HotPlug+ Surprise+ Interlock- NoCompl+ IbPresDis- LLActRep+
<6>[   12.100471][  T191] pcieport 0000:41:04.0: enabling device (0000 -> 0003)
<6>[   12.140211][  T186] Bluetooth: hci0: Waiting for firmware download to complete
<6>[   12.140960][  T186] Bluetooth: hci0: Firmware loaded in 1507294 usecs
<6>[   12.140986][  T186] Bluetooth: hci0: Waiting for device to boot
<6>[   12.156999][  T186] Bluetooth: hci0: Device booted in 15651 usecs
<6>[   12.160195][  T186] Bluetooth: hci0: Found Intel DDC parameters: intel/ibt-0040-0041.ddc
<6>[   12.161938][  T186] Bluetooth: hci0: Applying Intel DDC parameters completed
<6>[   12.164962][  T186] Bluetooth: hci0: Firmware timestamp 2025.20 buildtype 1 build 82053
<6>[   12.164965][  T186] Bluetooth: hci0: Firmware SHA1: 0x937bca4a
Panic#1 Part16
<6>[   12.168926][  T186] Bluetooth: hci0: Fseq status: Success (0x00)
<6>[   12.168931][  T186] Bluetooth: hci0: Fseq executed: 00.00.02.41
<6>[   12.168934][  T186] Bluetooth: hci0: Fseq BT Top: 00.00.02.41
<6>[   12.237967][  T982] Bluetooth: MGMT ver 1.23
<6>[   21.386342][ T1551] ish-hid {33AECD58-B679-4E54-9BD9-A04D34F0C226}: [hid-ish]: enum_devices_done OK, num_hid_devices=2
<6>[   21.393808][ T1551] hid-sensor-hub 001F:8087:0AC2.0008: hidraw7: SENSOR HUB HID v2.00 Device [hid-ishtp 8087:0AC2] on 
<6>[   21.395044][ T1554] pci 0000:00:05.0: Found supported sensor OVTI01A0:00
<6>[   21.395192][ T1554] pci 0000:00:05.0: Connected 1 cameras
<6>[   21.398220][  T219] intel-ipu6 0000:00:05.0: IPU6-v3[465d] hardware version 5
<6>[   21.420306][ T1551] hid-sensor-hub 001F:8087:0AC2.0009: hidraw8: SENSOR HUB HID v2.00 Device [hid-ishtp 8087:0AC2] on 
<6>[   21.533701][  T793] iwlwifi 0000:00:14.3: WFPM_UMAC_PD_NOTIFICATION: 0x20
<6>[   21.533758][  T793] iwlwifi 0000:00:14.3: WFPM_LMAC2_PD_NOTIFICATION: 0x1f
<6>[   21.533767][  T793] iwlwifi 0000:00:14.3: WFPM_AUTH_KEY_0: 0x90
<6>[   21.533829][  T793] iwlwifi 0000:00:14.3: CNVI_SCU_SEQ_DATA_DW9: 0x0
<6>[   21.533979][  T793] iwlwifi 0000:00:14.3: Detected RF GF, rfid=0x2010d000
<6>[   21.535151][   T25] iwlwifi 0000:00:14.3: RFIm is deactivated, reason = 4
<6>[   21.620461][  T793] iwlwifi 0000:00:14.3: base HW address: 54:6c:eb:db:9d:a4
<6>[   21.833009][ T1149] iwlwifi 0000:00:14.3: WFPM_UMAC_PD_NOTIFICATION: 0x20
<6>[   21.833068][ T1149] iwlwifi 0000:00:14.3: WFPM_LMAC2_PD_NOTIFICATION: 0x1f
<6>[   21.833077][ T1149] iwlwifi 0000:00:14.3: WFPM_AUTH_KEY_0: 0x90
Panic#1 Part15
<6>[   21.833087][ T1149] iwlwifi 0000:00:14.3: CNVI_SCU_SEQ_DATA_DW9: 0x0
<6>[   21.834551][   T25] iwlwifi 0000:00:14.3: RFIm is deactivated, reason = 4
<6>[   22.108500][   T92] r8152 2-3.4.1:1.0 eth0: carrier on
<6>[   22.364095][   T92] r8152 2-3.4.1:1.0 eth0: carrier off
<6>[   25.947713][   T92] r8152 2-3.4.1:1.0 eth0: carrier on
<6>[   33.869245][ T1801] xe 0000:00:02.0: [drm] Selective fetch area calculation failed in pipe A
<6>[  244.585252][ T2010] usb 3-9: reset full-speed USB device number 3 using xhci_hcd
<6>[  244.851269][ T2010] usb 3-9: reset full-speed USB device number 3 using xhci_hcd
<6>[  261.856085][  T222] xe 0000:00:02.0: [drm] Tile0: GT0: Engine reset: engine_class=rcs, logical_mask: 0x1, guc_id=16
<5>[  261.856122][  T222] xe 0000:00:02.0: [drm] Tile0: GT0: Timedout job: seqno=4294967169, lrc_seqno=4294967169, guc_id=16, flags=0x0 in Xorg [1801]
<6>[  261.856479][  T222] xe 0000:00:02.0: [drm] Xe device coredump has been created
<6>[  261.856481][  T222] xe 0000:00:02.0: [drm] Check your /sys/class/drm/card0/device/devcoredump/data
<6>[  262.194823][  T219] xe 0000:00:02.0: [drm] Tile0: GT0: Engine reset: engine_class=rcs, logical_mask: 0x1, guc_id=31
<5>[  262.194865][  T219] xe 0000:00:02.0: [drm] Tile0: GT0: Timedout job: seqno=4294967169, lrc_seqno=4294967169, guc_id=31, flags=0x0 in Xorg [1801]
<6>[  262.195209][  T219] xe 0000:00:02.0: [drm] Tile0: GT0: Engine reset: engine_class=rcs, logical_mask: 0x1, guc_id=34
<5>[  262.195257][  T219] xe 0000:00:02.0: [drm] Tile0: GT0: Timedout job: seqno=4294967169, lrc_seqno=4294967169, guc_id=34, flags=0x0 in Xorg [1801]
Panic#1 Part14
<4>[  264.828416][ T2762] warning: `xosview' uses wireless extensions which will stop working for Wi-Fi 7 hardware; use nl80211
<6>[  264.910873][  T165] xe 0000:00:02.0: [drm] Tile0: GT0: Engine reset: engine_class=rcs, logical_mask: 0x1, guc_id=8
<5>[  264.910915][  T165] xe 0000:00:02.0: [drm] Tile0: GT0: Timedout job: seqno=4294967169, lrc_seqno=4294967169, guc_id=8, flags=0x0 in Xorg [1801]
<6>[  264.918923][  T165] xe 0000:00:02.0: [drm] Tile0: GT0: Engine reset: engine_class=rcs, logical_mask: 0x1, guc_id=9
<5>[  264.918967][  T165] xe 0000:00:02.0: [drm] Tile0: GT0: Timedout job: seqno=4294967169, lrc_seqno=4294967169, guc_id=9, flags=0x0 in Xorg [1801]
<6>[  264.924334][  T222] xe 0000:00:02.0: [drm] Tile0: GT0: Engine reset: engine_class=rcs, logical_mask: 0x1, guc_id=9
<5>[  264.924379][  T222] xe 0000:00:02.0: [drm] Tile0: GT0: Timedout job: seqno=4294967169, lrc_seqno=4294967169, guc_id=9, flags=0x0 in Xorg [1801]
<6>[  264.932065][  T901] xe 0000:00:02.0: [drm] Tile0: GT0: Engine reset: engine_class=rcs, logical_mask: 0x1, guc_id=9
<5>[  264.932121][  T901] xe 0000:00:02.0: [drm] Tile0: GT0: Timedout job: seqno=4294967169, lrc_seqno=4294967169, guc_id=9, flags=0x0 in Xorg [1801]
<6>[  264.947061][  T901] xe 0000:00:02.0: [drm] Tile0: GT0: Engine reset: engine_class=rcs, logical_mask: 0x1, guc_id=10
<5>[  264.947105][  T901] xe 0000:00:02.0: [drm] Tile0: GT0: Timedout job: seqno=4294967169, lrc_seqno=4294967169, guc_id=10, flags=0x0 in Xorg [1801]
<6>[  264.955407][  T165] xe 0000:00:02.0: [drm] Tile0: GT0: Engine reset: engine_class=rcs, logical_mask: 0x1, guc_id=10
Panic#1 Part13
<5>[  264.955566][  T165] xe 0000:00:02.0: [drm] Tile0: GT0: Timedout job: seqno=4294967169, lrc_seqno=4294967169, guc_id=10, flags=0x0 in Xorg [1801]
<6>[  265.066913][  T222] xe 0000:00:02.0: [drm] Tile0: GT0: Engine reset: engine_class=rcs, logical_mask: 0x1, guc_id=11
<5>[  265.066973][  T222] xe 0000:00:02.0: [drm] Tile0: GT0: Timedout job: seqno=4294967169, lrc_seqno=4294967169, guc_id=11, flags=0x0 in Xorg [1801]
<4>[  408.380207][   C18] hrtimer: interrupt took 27803 ns
<12>[  649.828860][ T3682] Suspended at Mon, 22 Dec 2025 06:53:59 -0800
<6>[  649.912832][ T3671] PM: hibernation: hibernation entry
<6>[  649.937254][  T205] Filesystems sync: 0.004 seconds
<6>[  649.937422][ T3671] Freezing user space processes
<6>[  649.938703][ T3671] Freezing user space processes completed (elapsed 0.001 seconds)
<6>[  649.938706][ T3671] OOM killer disabled.
<7>[  649.938950][ T3671] PM: hibernation: Marking nosave pages: [mem 0x00000000-0x00000fff]
<7>[  649.938953][ T3671] PM: hibernation: Marking nosave pages: [mem 0x0009f000-0x000fffff]
<7>[  649.938955][ T3671] PM: hibernation: Marking nosave pages: [mem 0x523e6000-0x52426fff]
<7>[  649.938956][ T3671] PM: hibernation: Marking nosave pages: [mem 0x57cb6000-0x5d7fefff]
<7>[  649.939145][ T3671] PM: hibernation: Marking nosave pages: [mem 0x5d800000-0xffffffff]
<7>[  649.939232][ T3671] PM: hibernation: Basic memory bitmaps created
<6>[  649.939465][ T3671] PM: hibernation: Preallocating image memory
<6>[  650.429565][ T3671] PM: hibernation: Allocated 1249716 pages for snapshot
<6>[  650.429569][ T3671] PM: hibernation: Allocated 4998864 kbytes in 0.49 seconds (10201.76 MB/s)
Panic#1 Part12
<6>[  650.429571][ T3671] Freezing remaining freezable tasks
<6>[  650.431049][ T3671] Freezing remaining freezable tasks completed (elapsed 0.001 seconds)
<6>[  650.542251][ T3671] printk: Suspending console(s) (use no_console_suspend to debug)
<6>[  651.219641][ T3671] ACPI: EC: interrupt blocked
<6>[  651.219662][ T3671] ACPI: PM: Preparing to enter system sleep state S4
<6>[  651.263946][ T3671] ACPI: EC: event blocked
<6>[  651.263948][ T3671] ACPI: EC: EC stopped
<6>[  651.263949][ T3671] ACPI: PM: Saving platform NVS memory
<6>[  651.266975][ T3671] Disabling non-boot CPUs ...
<6>[  651.269024][ T3671] smpboot: CPU 19 is now offline
<6>[  651.271894][ T3671] smpboot: CPU 18 is now offline
<6>[  651.274888][ T3671] smpboot: CPU 17 is now offline
<6>[  651.277804][ T3671] smpboot: CPU 16 is now offline
<6>[  651.280666][ T3671] smpboot: CPU 15 is now offline
<6>[  651.283254][ T3671] smpboot: CPU 14 is now offline
<6>[  651.285974][ T3671] smpboot: CPU 13 is now offline
<6>[  651.288531][ T3671] smpboot: CPU 12 is now offline
<6>[  651.290900][ T3671] smpboot: CPU 10 is now offline
<6>[  651.293365][ T3671] smpboot: CPU 8 is now offline
<6>[  651.295494][ T3671] smpboot: CPU 6 is now offline
<6>[  651.297630][ T3671] smpboot: CPU 4 is now offline
<6>[  651.299701][ T3671] smpboot: CPU 2 is now offline
<7>[  651.556367][ T3671] PM: hibernation: Normal pages needed: 1204144 + 1024, available pages: 7082251
<6>[  651.308964][ T3671] ACPI: PM: Restoring platform NVS memory
<6>[  651.309826][ T3671] ACPI: EC: EC started
<6>[  651.311544][ T3671] Enabling non-boot CPUs ...
<6>[  651.311571][ T3671] smpboot: Booting Node 0 Processor 2 APIC 0x8
Panic#1 Part11
<6>[  651.315723][ T3671] CPU2 is up
<6>[  651.315745][ T3671] smpboot: Booting Node 0 Processor 4 APIC 0x10
<6>[  651.319351][ T3671] CPU4 is up
<6>[  651.319365][ T3671] smpboot: Booting Node 0 Processor 6 APIC 0x18
<6>[  651.323673][ T3671] CPU6 is up
<6>[  651.323694][ T3671] smpboot: Booting Node 0 Processor 8 APIC 0x20
<6>[  651.327735][ T3671] CPU8 is up
<6>[  651.327749][ T3671] smpboot: Booting Node 0 Processor 10 APIC 0x28
<6>[  651.331413][ T3671] CPU10 is up
<6>[  651.331428][ T3671] smpboot: Booting Node 0 Processor 12 APIC 0x30
<6>[  651.334453][    T0] core: cpu_atom PMU driver: 
<6>[  651.334458][    T0] ... version:                   5
<6>[  651.334459][    T0] ... bit width:                 48
<6>[  651.334459][    T0] ... generic counters:          6
<6>[  651.334460][    T0] ... generic bitmap:            000000000000003f
<6>[  651.334461][    T0] ... fixed-purpose counters:    3
<6>[  651.334461][    T0] ... fixed-purpose bitmap:      0000000000000007
<6>[  651.334462][    T0] ... value mask:                0000ffffffffffff
<6>[  651.334462][    T0] ... max period:                00007fffffffffff
<6>[  651.334463][    T0] ... global_ctrl mask:          000000070000003f
<6>[  651.335650][ T3671] CPU12 is up
<6>[  651.335664][ T3671] smpboot: Booting Node 0 Processor 13 APIC 0x32
<6>[  651.339921][ T3671] CPU13 is up
<6>[  651.339936][ T3671] smpboot: Booting Node 0 Processor 14 APIC 0x34
<6>[  651.346490][ T3671] CPU14 is up
<6>[  651.346510][ T3671] smpboot: Booting Node 0 Processor 15 APIC 0x36
<6>[  651.353746][ T3671] CPU15 is up
<6>[  651.353761][ T3671] smpboot: Booting Node 0 Processor 16 APIC 0x38
Panic#1 Part10
<6>[  651.361048][ T3671] CPU16 is up
<6>[  651.361072][ T3671] smpboot: Booting Node 0 Processor 17 APIC 0x3a
<6>[  651.368088][ T3671] CPU17 is up
<6>[  651.368113][ T3671] smpboot: Booting Node 0 Processor 18 APIC 0x3c
<6>[  651.375123][ T3671] CPU18 is up
<6>[  651.375180][ T3671] smpboot: Booting Node 0 Processor 19 APIC 0x3e
<6>[  651.382216][ T3671] CPU19 is up
<6>[  651.384953][ T3671] smpboot: Booting Node 0 Processor 1 APIC 0x1
<4>[  651.405078][  T100] processor cpu1: EM: No online CPU for CPUFreq policy
<6>[  651.405183][  T100] processor cpu1: EM: created perf domain
<6>[  651.409253][ T3671] smpboot: Booting Node 0 Processor 3 APIC 0x9
<4>[  651.429661][  T106] processor cpu3: EM: No online CPU for CPUFreq policy
<6>[  651.429761][  T106] processor cpu3: EM: created perf domain
<6>[  651.433343][ T3671] smpboot: Booting Node 0 Processor 5 APIC 0x11
<4>[  651.453705][  T112] processor cpu5: EM: No online CPU for CPUFreq policy
<6>[  651.453807][  T112] processor cpu5: EM: created perf domain
<6>[  651.457654][ T3671] smpboot: Booting Node 0 Processor 7 APIC 0x19
<4>[  651.468466][  T118] processor cpu7: EM: No online CPU for CPUFreq policy
<6>[  651.468556][  T118] processor cpu7: EM: created perf domain
<6>[  651.472440][ T3671] smpboot: Booting Node 0 Processor 9 APIC 0x21
<4>[  651.492711][  T124] processor cpu9: EM: No online CPU for CPUFreq policy
<6>[  651.492815][  T124] processor cpu9: EM: created perf domain
<6>[  651.496866][ T3671] smpboot: Booting Node 0 Processor 11 APIC 0x29
<4>[  651.516761][  T130] processor cpu11: EM: No online CPU for CPUFreq policy
<6>[  651.516880][  T130] processor cpu11: EM: created perf domain
Panic#1 Part9
<6>[  651.534820][  T809] smpboot: CPU 1 is now offline
<6>[  651.541873][  T809] smpboot: CPU 3 is now offline
<6>[  651.554287][  T809] smpboot: CPU 5 is now offline
<6>[  651.567829][  T809] smpboot: CPU 7 is now offline
<6>[  651.586834][  T809] smpboot: CPU 9 is now offline
<6>[  651.596744][  T809] smpboot: CPU 11 is now offline
<6>[  651.605640][ T3671] ACPI: PM: Waking up from system sleep state S4
<4>[  651.619132][ T3604] ACPI: button: The lid device is not compliant to SW_LID.
<6>[  651.635210][ T3671] ACPI: EC: interrupt unblocked
<6>[  652.308682][ T3671] intel_pmc_core INT33A1:00: CPU did not enter Package C10!!! (Package C10 cnt=0x0)
<6>[  652.308691][ T3671] intel_pmc_core INT33A1:00: Prev Package C2 cnt = 0x44bd2c62fc, Current Package C2 cnt = 0x5b7725dc
<6>[  652.308696][ T3671] intel_pmc_core INT33A1:00: Prev Package C3 cnt = 0x183eddbe5c, Current Package C3 cnt = 0xd6c304c
<6>[  652.308699][ T3671] intel_pmc_core INT33A1:00: Prev Package C6 cnt = 0xa17c0, Current Package C6 cnt = 0x0
<6>[  652.308702][ T3671] intel_pmc_core INT33A1:00: Prev Package C7 cnt = 0x0, Current Package C7 cnt = 0x0
<6>[  652.308704][ T3671] intel_pmc_core INT33A1:00: Prev Package C8 cnt = 0x0, Current Package C8 cnt = 0x0
<6>[  652.308707][ T3671] intel_pmc_core INT33A1:00: Prev Package C9 cnt = 0x0, Current Package C9 cnt = 0x0
<6>[  652.308709][ T3671] intel_pmc_core INT33A1:00: Prev Package C10 cnt = 0x0, Current Package C10 cnt = 0x0
<6>[  652.405932][ T3719] intel-ipu6 0000:00:05.0: IPU6 in non-secure mode
<6>[  652.406001][ T3671] ACPI: EC: event unblocked
<5>[  652.406137][ T3715] usb usb1: root hub lost power or was reset
Panic#1 Part8
<5>[  652.406140][ T3715] usb usb2: root hub lost power or was reset
<5>[  652.406301][ T3717] usb usb3: root hub lost power or was reset
<5>[  652.406303][ T3717] usb usb4: root hub lost power or was reset
<3>[  652.407181][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not required
<3>[  652.407191][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not required
<3>[  652.407200][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not required
<3>[  652.407208][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not required
<3>[  652.407218][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not required
<3>[  652.407225][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not required
<3>[  652.407233][ T3715] xhci_hcd 0000:00:0d.0: event ring handling not required
<3>[  652.407453][ T3717] xhci_hcd 0000:00:14.0: event ring handling not required
<3>[  652.407469][ T3717] xhci_hcd 0000:00:14.0: event ring handling not required
<3>[  652.407481][ T3717] xhci_hcd 0000:00:14.0: event ring handling not required
<3>[  652.407495][ T3717] xhci_hcd 0000:00:14.0: event ring handling not required
<3>[  652.407509][ T3717] xhci_hcd 0000:00:14.0: event ring handling not required
<3>[  652.407521][ T3717] xhci_hcd 0000:00:14.0: event ring handling not required
<3>[  652.407533][ T3717] xhci_hcd 0000:00:14.0: event ring handling not required
<3>[  652.427396][    C0] xhci_hcd 0000:00:14.0: ERROR interrupter event ring not ready
<4>[  652.479668][ T3721] pcieport 10000:e0:06.0: can't derive routing for PCI INT A
<4>[  652.479670][ T3721] nvme 10000:e1:00.0: PCI INT A: no GSI
<6>[  652.492540][ T3721] nvme nvme0: 20/0/0 default/read/poll queues
Panic#1 Part7
<3>[  652.516347][    C0] xhci_hcd 0000:00:0d.0: ERROR interrupter event ring not ready
<6>[  652.964456][ T3740] ish-hid {33AECD58-B679-4E54-9BD9-A04D34F0C226}: [hid-ish]: enum_devices_done OK, num_hid_devices=2
<3>[  660.081555][ T3719] xhci_hcd 0000:00:0d.0: Error while assigning device slot ID: Command Aborted
<3>[  660.081562][ T3719] xhci_hcd 0000:00:0d.0: Max number of devices this xHCI host supports is 64.
<3>[  660.081580][ T3717] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  660.081583][ T3729] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  660.081586][ T3717] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  660.081590][ T3729] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  660.081594][ T3720] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  660.081600][ T3720] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  660.081632][ T3707] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  660.081635][ T3707] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  672.369518][ T3719] xhci_hcd 0000:00:0d.0: Error while assigning device slot ID: Command Aborted
<3>[  672.369527][ T3719] xhci_hcd 0000:00:0d.0: Max number of devices this xHCI host supports is 64.
<3>[  672.369532][ T3729] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  672.369540][ T3729] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
Panic#1 Part6
<3>[  672.369557][ T3717] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  672.369564][ T3717] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<6>[  672.369675][ T3717] usb 3-9: reset full-speed USB device number 3 using xhci_hcd
<3>[  672.369682][ T3717] usb 3-9: hub failed to enable device, error -22
<3>[  684.657538][ T3729] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  684.657538][ T3717] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  684.657546][ T3729] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  684.657546][ T3717] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<6>[  684.657578][ T3717] usb 3-9: reset full-speed USB device number 3 using xhci_hcd
<3>[  684.657585][ T3717] usb 3-9: hub failed to enable device, error -22
<3>[  684.657669][ T3719] xhci_hcd 0000:00:0d.0: Error while assigning device slot ID: Command Aborted
<3>[  684.657675][ T3719] xhci_hcd 0000:00:0d.0: Max number of devices this xHCI host supports is 64.
<3>[  696.945425][ T3719] xhci_hcd 0000:00:0d.0: Error while assigning device slot ID: Command Aborted
<3>[  696.945432][ T3719] xhci_hcd 0000:00:0d.0: Max number of devices this xHCI host supports is 64.
<3>[  696.945433][ T3729] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  696.945440][ T3729] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  696.945514][ T3717] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
Panic#1 Part5
<3>[  696.945520][ T3717] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<6>[  696.945546][ T3717] usb 3-9: reset full-speed USB device number 3 using xhci_hcd
<3>[  697.361392][ T3717] usb 3-9: device not accepting address 3, error -22
<3>[  709.233410][ T3719] xhci_hcd 0000:00:0d.0: Error while assigning device slot ID: Command Aborted
<3>[  709.233419][ T3719] xhci_hcd 0000:00:0d.0: Max number of devices this xHCI host supports is 64.
<3>[  709.233421][ T3717] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  709.233429][ T3717] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<6>[  709.233443][ T3717] usb 3-9: reset full-speed USB device number 3 using xhci_hcd
<3>[  709.233493][ T3729] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  709.233499][ T3729] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  709.649393][ T3717] usb 3-9: device not accepting address 3, error -22
<3>[  721.521555][ T3720] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  721.521555][ T3729] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  721.521563][ T3729] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  721.521563][ T3720] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  721.521566][ T3719] xhci_hcd 0000:00:0d.0: Error while assigning device slot ID: Command Aborted
<3>[  721.521573][ T3719] xhci_hcd 0000:00:0d.0: Max number of devices this xHCI host supports is 64.
Panic#1 Part4
<6>[  721.521762][ T3720] usb 3-10: reset full-speed USB device number 4 using xhci_hcd
<3>[  721.521771][ T3720] usb 3-10: hub failed to enable device, error -22
<3>[  721.937366][ T3719] usb 2-3: device not accepting address 2, error -22
<3>[  733.809349][ T3720] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  733.809357][ T3720] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  733.809380][ T3729] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  733.809387][ T3729] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<6>[  733.809386][ T3720] usb 3-10: reset full-speed USB device number 4 using xhci_hcd
<3>[  733.809395][ T3720] usb 3-10: hub failed to enable device, error -22
<3>[  734.321394][ T3719] xhci_hcd 0000:00:0d.0: Error while assigning device slot ID: Command Aborted
<3>[  734.321402][ T3719] xhci_hcd 0000:00:0d.0: Max number of devices this xHCI host supports is 64.
<3>[  734.737347][ T3719] usb 2-3: device not accepting address 2, error -22
<3>[  746.097493][ T3729] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  746.097494][ T3720] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  746.097502][ T3720] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<3>[  746.097502][ T3729] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<6>[  746.097533][ T3720] usb 3-10: reset full-speed USB device number 4 using xhci_hcd
<3>[  746.513324][ T3720] usb 3-10: device not accepting address 4, error -22
Panic#1 Part3
<3>[  747.121436][ T3719] xhci_hcd 0000:00:0d.0: Error while assigning device slot ID: Command Aborted
<3>[  747.121448][ T3719] xhci_hcd 0000:00:0d.0: Max number of devices this xHCI host supports is 64.
<3>[  747.537343][ T3719] usb 2-3: device not accepting address 2, error -22
<3>[  758.897464][ T3720] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  758.897471][ T3720] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<6>[  758.897503][ T3720] usb 3-10: reset full-speed USB device number 4 using xhci_hcd
<3>[  759.313293][ T3720] usb 3-10: device not accepting address 4, error -22
<3>[  759.921378][ T3719] xhci_hcd 0000:00:0d.0: Error while assigning device slot ID: Command Aborted
<3>[  759.921387][ T3719] xhci_hcd 0000:00:0d.0: Max number of devices this xHCI host supports is 64.
<3>[  760.337304][ T3719] usb 2-3: device not accepting address 2, error -22
<6>[  768.964758][    C0] sysrq: Emergency Sync
<4>[  768.974270][  T809] Emergency Sync complete
<6>[  769.401430][    C0] sysrq: Emergency Remount R/O
<6>[  769.466021][  T809] EXT4-fs (nvme0n1p4): re-mounted 17354762-b6e0-4196-8528-2db4de1025f6 ro.
<4>[  769.482250][  T809] Emergency Remount complete
<3>[  771.697468][ T3707] xhci_hcd 0000:00:14.0: Error while assigning device slot ID: Command Aborted
<3>[  771.697480][ T3707] xhci_hcd 0000:00:14.0: Max number of devices this xHCI host supports is 64.
<6>[  771.697664][ T3707] usb 3-8: reset full-speed USB device number 2 using xhci_hcd
<3>[  771.697676][ T3707] usb 3-8: hub failed to enable device, error -22
<6>[  772.311804][    C0] sysrq: Trigger a crash
Panic#1 Part2
<0>[  772.311814][    C0] Kernel panic - not syncing: sysrq triggered crash
<4>[  772.311821][    C0] CPU: 0 UID: 0 PID: 0 Comm: swapper/0 Tainted: G S   U              6.19.0-rc2-kenny+ #10 PREEMPT 
<4>[  772.311831][    C0] Tainted: [S]=CPU_OUT_OF_SPEC, [U]=USER
<4>[  772.311833][    C0] Hardware name: Dell Inc. XPS 9320/0KNXGD, BIOS 2.26.0 10/27/2025
<4>[  772.311836][    C0] Call Trace:
<4>[  772.311840][    C0]  <IRQ>
<4>[  772.311847][    C0]  __dump_stack+0x19/0x20
<4>[  772.311861][    C0]  dump_stack_lvl+0x1b/0x60
<4>[  772.311867][    C0]  dump_stack+0x10/0x12
<4>[  772.311873][    C0]  vpanic+0xda/0x2d0
<4>[  772.311879][    C0]  panic+0x46/0x50
<4>[  772.311884][    C0]  ? rcu_read_unlock+0x9/0x10
<4>[  772.311889][    C0]  sysrq_handle_crash+0x15/0x20
<4>[  772.311893][    C0]  __handle_sysrq+0x10f/0x120
<4>[  772.311897][    C0]  sysrq_filter+0x18b/0x380
<4>[  772.311902][    C0]  input_handle_events_filter+0x4f/0x80
<4>[  772.311911][    C0]  input_pass_values+0x134/0x150
<4>[  772.311917][    C0]  input_event_dispose+0x112/0x140
<4>[  772.311923][    C0]  input_handle_event+0x3cc/0x3e0
<4>[  772.311928][    C0]  input_event+0x4c/0x80
<4>[  772.311933][    C0]  atkbd_receive_byte+0x444/0x5d0
<4>[  772.311939][    C0]  ps2_interrupt+0x5c/0x220
<4>[  772.311945][    C0]  serio_interrupt+0x3f/0x90
<4>[  772.311949][    C0]  i8042_handle_data+0x280/0x380
<4>[  772.311955][    C0]  i8042_interrupt+0xc/0x50
<4>[  772.311960][    C0]  __handle_irq_event_percpu+0x67/0x190
<4>[  772.311965][    C0]  handle_irq_event+0x31/0x70
<4>[  772.311969][    C0]  handle_edge_irq+0x98/0x180
<4>[  772.311974][    C0]  __common_interrupt+0x35/0x80
Panic#1 Part1
<4>[  772.311981][    C0]  common_interrupt+0x81/0xa0
<4>[  772.311987][    C0]  </IRQ>
<4>[  772.311988][    C0]  <TASK>
<4>[  772.311991][    C0]  asm_common_interrupt+0x27/0x40
<4>[  772.311995][    C0] RIP: 0010:cpuidle_enter_state+0xf5/0x1f0
<4>[  772.312004][    C0] Code: 75 05 e8 be fd ff ff e8 b9 0e d5 fe e8 d4 f5 ff ff 49 89 c5 31 ff e8 3a 47 d4 fe 80 7d d4 00 74 05 e8 6f 08 a3 ff fb 45 85 ff <78> 58 44 89 f9 48 6b f9 68 4c 8b 45 c8 49 8b 54 38 30 4c 2b 6d c0
<4>[  772.312008][    C0] RSP: 0018:ffffffffad203e18 EFLAGS: 00000202
<4>[  772.312015][    C0] RAX: ffff9545c1078000 RBX: ffff953e02c56000 RCX: 000000000000001f
<4>[  772.312019][    C0] RDX: 0000000000000012 RSI: 00000025cf680bb6 RDI: 0000000000000000
<4>[  772.312022][    C0] RBP: ffffffffad203e58 R08: 0000000000000000 R09: 0000000000000000
<4>[  772.312025][    C0] R10: 0000000028290000 R11: 0000000028290100 R12: 0000000000000002
<4>[  772.312027][    C0] R13: 000000b3d15d7573 R14: ffffffffae0e3ff8 R15: 0000000000000002
<4>[  772.312034][    C0]  ? cpuidle_enter_state+0xe6/0x1f0
<4>[  772.312040][    C0]  cpuidle_enter+0x27/0x40
<4>[  772.312048][    C0]  do_idle+0x198/0x220
<4>[  772.312055][    C0]  cpu_startup_entry+0x25/0x30
<4>[  772.312061][    C0]  rest_init+0xbd/0xc0
<4>[  772.312067][    C0]  start_kernel+0x352/0x380
<4>[  772.312072][    C0]  x86_64_start_reservations+0x24/0x30
<4>[  772.312079][    C0]  x86_64_start_kernel+0xfc/0x100
<4>[  772.312084][    C0]  common_startup_64+0x13e/0x147
<4>[  772.312090][    C0]  </TASK>
<0>[  772.313102][    C0] Kernel Offset: 0x29c00000 from 0xffffffff81000000 (relocation range: 0xffffffff80000000-0xffffffffbfffffff)

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2025-12-22 17:54 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-12-17  9:46 [PATCH v3] usb: xhci: route endpoints to secondary interrupters raoxu
2025-12-18  7:57 ` Michal Pecio
2025-12-18 15:49 ` Mathias Nyman
2025-12-18 17:01   ` Kenneth Crudup
2025-12-22 16:33     ` Kenneth Crudup
2025-12-22 17:54       ` Kenneth Crudup

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox