Linux USB
 help / color / mirror / Atom feed
From: Michal Pecio <michal.pecio@gmail.com>
To: Desnes Nunes <desnesn@redhat.com>
Cc: linux-kernel@vger.kernel.org, linux-usb@vger.kernel.org,
	gregkh@linuxfoundation.org, mathias.nyman@intel.com,
	stable@vger.kernel.org
Subject: Re: [PATCH RFT RFC] usb: xhci: Kill hosts with HCE or HSE on command timeout
Date: Fri, 22 May 2026 11:03:28 +0200	[thread overview]
Message-ID: <20260522110328.0d3eecd8.michal.pecio@gmail.com> (raw)
In-Reply-To: <CACaw+ewSWTo72fSk2Q7ZzCM8pNuyrX5ua+qA=SZOQuNNMKSA5Q@mail.gmail.com>

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

On Wed, 20 May 2026 01:59:41 -0300, Desnes Nunes wrote:
> On Mon, May 18, 2026 at 3:33 AM Michal Pecio <michal.pecio@gmail.com> wrote:
> > > The chip IOMMU faults shortly after setting USBCMD.RUN = 1.
> > > Such fault is expected to cause HSE assertion and usually it does.
> > > You will probably find that HSE is already set while Enable Slot
> > > is being queued, even if it was clear in xhci_gen_setup().  
> 
> I've just read HSE at these places and confirmed that HSE was already
> set even before queuing the enable slot trb, even though it was
> previously clear in xhci_gen_setup().

Makes sense, thanks for checking.

> The fault addresses do not appear in the main log, nor anywhere other
> than the DMAR fault addr messages in the crashkernel's log.
> 
> However, by comparing the previous log messages from the past kernel,
> to the ones I saw with the new kernel I built today, I noticed the
> same 8K displacement from the fault addr. Maybe an iommu driver bug
> clue?

If the bug is deterministic it should be fairly easy to nail it down.
Attached xhci debugfs patch adds a list of almost all memory the xHC
is allowed to access, including (if I havevn't missed something) all
mappings it is allowed to access before any slots are enabled.

Please apply, reboot and then:

zip -r before.zip /sys/kernel/debug/usb/xhci/0000:80:14.0
# trigger crash kexec and the bug
zip -r after.zip /sys/kernel/debug/usb/xhci/0000:80:14.0

Note: if you need to use tar instead, copy the directory and then
archive the copy, because tar doesn't work on debugfs directly.

And since the bug may be an out of bounds access by the HW, if you
don't mind running slightly experimental patch to a critical subsystem,
please also apply the DMA guard pages patch. I've been using it for a
few months without issues, but YMMV. It helps determine which mapping
is accessed OOB.

Note: DMA guard pages may casue USB to stop working before kexec if
it's a HW bug masked by memory layout, or begin to work after kexec in
case of some IOMMU subsystem issues.

> PS: there was a big iommu PR a few days ago - all the results from on
> this email were performed with a recent 7.1.0-rc3 kernel checked out
> at 30e0ff6d6a83.

Well, so those IOMMU changes neither broke it nor fixed it.
Knowing xHCI I frankly suspect that the problem is here.

Regards,
Michal



[-- Attachment #2: xhci-debugfs-memory.patch --]
[-- Type: text/x-patch, Size: 2872 bytes --]

diff --git a/drivers/usb/host/xhci-debugfs.c b/drivers/usb/host/xhci-debugfs.c
index da528d07b815..b4f12013d487 100644
--- a/drivers/usb/host/xhci-debugfs.c
+++ b/drivers/usb/host/xhci-debugfs.c
@@ -779,6 +779,78 @@ static void xhci_debugfs_create_bandwidth(struct xhci_hcd *xhci,
 			  parent, &bw_fops);
 }
 
+static void list_ring_segments(struct seq_file *s, struct xhci_ring *ring)
+{
+	struct xhci_segment *seg;
+
+	xhci_for_each_ring_seg(ring->first_seg, seg)
+		seq_printf(s, "%.3x: %pad\n", seg->num, &seg->dma);
+}
+
+static void list_event_ring_segments(struct seq_file *s, struct xhci_interrupter *ir)
+{
+	struct xhci_segment *seg;
+
+	seq_printf(s, "IR%d ERST: %pad\n", ir->intr_num, &ir->erst.erst_dma_addr);
+	xhci_for_each_ring_seg(ir->event_ring->first_seg, seg)
+		seq_printf(s, "%.3x: %pad %c= %.16llx %.8x\n", seg->num, &seg->dma,
+				ir->erst.entries[seg->num].seg_addr == seg->dma ? '=' : '!',
+				ir->erst.entries[seg->num].seg_addr,
+				ir->erst.entries[seg->num].seg_size);
+	seq_putc(s, '\n');
+}
+
+static int xhci_memory_show(struct seq_file *s, void *unused)
+{
+	struct xhci_hcd		*xhci = (struct xhci_hcd *)s->private;
+	int			num_sp = HCS_MAX_SCRATCHPAD(xhci->hcs_params2);
+
+	if (!xhci)
+		return -EFAULT;
+
+	seq_puts(s, "CR:\n");
+	list_ring_segments(s, xhci->cmd_ring);
+	seq_putc(s, '\n');
+
+	for (int i = 0; i < 1; i++)
+		if (xhci->interrupters[i])
+			list_event_ring_segments(s, xhci->interrupters[i]);
+
+	seq_printf(s, "DCBAA: %pad\n", &xhci->dcbaa->dma);
+	for (int i = 0; i < MAX_HC_SLOTS; i++)
+		seq_printf(s, "%.3x: %pad\n", i, xhci->dcbaa->dev_context_ptrs + i);
+	seq_putc(s, '\n');
+
+	if (xhci->scratchpad) {
+		seq_printf(s, "SBA: %pad\n", &xhci->scratchpad->sp_dma);
+		for (int i = 0; i < num_sp; i++)
+			seq_printf(s, "%.3x: %pad\n", i, xhci->scratchpad->sp_array + i);
+		seq_putc(s, '\n');
+	}
+
+	for (int d = 1; d < MAX_HC_SLOTS; d++)
+		for (int e = 0; e < EP_CTX_PER_DEV; e++)
+			if (xhci->devs[d] && xhci->devs[d]->eps[e].ring) {
+				seq_printf(s, "DEV %d EP %d:\n", d, e);
+				list_ring_segments(s, xhci->devs[d]->eps[e].ring);
+				seq_putc(s, '\n');
+			}
+
+	return 0;
+}
+
+static int memory_open(struct inode *inode, struct file *file)
+{
+	return single_open(file, xhci_memory_show, inode->i_private);
+}
+
+static const struct file_operations memory_fops = {
+	.open			= memory_open,
+	.read			= seq_read,
+	.llseek			= seq_lseek,
+	.release		= single_release,
+};
+
 void xhci_debugfs_init(struct xhci_hcd *xhci)
 {
 	struct device		*dev = xhci_to_hcd(xhci)->self.controller;
@@ -831,6 +903,8 @@ void xhci_debugfs_init(struct xhci_hcd *xhci)
 	xhci_debugfs_create_ports(xhci, xhci->debugfs_root);
 
 	xhci_debugfs_create_bandwidth(xhci, xhci->debugfs_root);
+
+	debugfs_create_file("memory", 0444, xhci->debugfs_root, xhci, &memory_fops);
 }
 
 void xhci_debugfs_exit(struct xhci_hcd *xhci)

[-- Attachment #3: dma-guard-pages.patch --]
[-- Type: text/x-patch, Size: 1910 bytes --]

diff --git a/drivers/iommu/dma-iommu.c b/drivers/iommu/dma-iommu.c
index 54d96e847f16..41ff22748276 100644
--- a/drivers/iommu/dma-iommu.c
+++ b/drivers/iommu/dma-iommu.c
@@ -757,6 +757,17 @@ static int dma_info_to_prot(enum dma_data_direction dir, bool coherent,
 	}
 }
 
+static unsigned long size_to_iova_len(struct iova_domain *iovad, size_t size)
+{
+	size_t guard_size = 0;
+
+	/* allocate optional guard pages after the requested mapping */
+	if (1)
+		guard_size = iova_align(iovad, 1024 << 10);
+
+	return (size + guard_size) >> iova_shift(iovad);
+}
+
 static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
 		size_t size, u64 dma_limit, struct device *dev)
 {
@@ -770,7 +781,7 @@ static dma_addr_t iommu_dma_alloc_iova(struct iommu_domain *domain,
 	}
 
 	shift = iova_shift(iovad);
-	iova_len = size >> shift;
+	iova_len = size_to_iova_len(iovad, size);
 
 	dma_limit = min_not_zero(dma_limit, dev->bus_dma_limit);
 
@@ -807,17 +818,21 @@ static void iommu_dma_free_iova(struct iommu_domain *domain, dma_addr_t iova,
 				size_t size, struct iommu_iotlb_gather *gather)
 {
 	struct iova_domain *iovad = &domain->iova_cookie->iovad;
+	unsigned long iova_len;
 
 	/* The MSI case is only ever cleaning up its most recent allocation */
-	if (domain->cookie_type == IOMMU_COOKIE_DMA_MSI)
+	if (domain->cookie_type == IOMMU_COOKIE_DMA_MSI) {
 		domain->msi_cookie->msi_iova -= size;
-	else if (gather && gather->queued)
+		return;
+	}
+
+	iova_len = size_to_iova_len(iovad, size);
+
+	if (gather && gather->queued)
 		queue_iova(domain->iova_cookie, iova_pfn(iovad, iova),
-				size >> iova_shift(iovad),
-				&gather->freelist);
+				iova_len, &gather->freelist);
 	else
-		free_iova_fast(iovad, iova_pfn(iovad, iova),
-				size >> iova_shift(iovad));
+		free_iova_fast(iovad, iova_pfn(iovad, iova), iova_len);
 }
 
 static void __iommu_dma_unmap(struct device *dev, dma_addr_t dma_addr,

  reply	other threads:[~2026-05-22  9:03 UTC|newest]

Thread overview: 18+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2026-04-30  1:48 [PATCH] usb: xhci: bound wait command completion to avoid kdump deadlock Desnes Nunes
2026-04-30  8:48 ` Michal Pecio
2026-04-30 17:27   ` Desnes Nunes
2026-04-30 21:54     ` Michal Pecio
2026-05-01 14:09       ` Desnes Nunes
2026-05-02  9:46         ` [PATCH RFT RFC] usb: xhci: Kill hosts with HCE or HSE on command timeout Michal Pecio
2026-05-02 11:38           ` Desnes Nunes
2026-05-02 21:55             ` Michal Pecio
2026-05-03  3:36               ` Desnes Nunes
2026-05-03  5:17                 ` Michal Pecio
2026-05-03 16:20                   ` Desnes Nunes
2026-05-03 19:31                     ` Michal Pecio
2026-05-04  7:31                       ` Michal Pecio
2026-05-18  6:33                         ` Michal Pecio
2026-05-20  4:59                           ` Desnes Nunes
2026-05-22  9:03                             ` Michal Pecio [this message]
2026-05-22 20:45                               ` Desnes Nunes
2026-05-23  0:29                                 ` Michal Pecio

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20260522110328.0d3eecd8.michal.pecio@gmail.com \
    --to=michal.pecio@gmail.com \
    --cc=desnesn@redhat.com \
    --cc=gregkh@linuxfoundation.org \
    --cc=linux-kernel@vger.kernel.org \
    --cc=linux-usb@vger.kernel.org \
    --cc=mathias.nyman@intel.com \
    --cc=stable@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox