mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
* [PATCH] usb: pci-quirks: abort xHCI handoff if MMIO is inaccessible
@ 2026-09-06 16:26 Haowen Bai
  2026-09-10 13:35 ` Mathias Nyman
  0 siblings, 1 reply; 2+ messages in thread
From: Haowen Bai @ 2026-09-06 16:26 UTC (permalink / raw)
  To: mathias.nyman; +Cc: gregkh, linux-usb, linux-kernel, Haowen Bai, stable

The xHCI early handoff quirk polls the BIOS ownership, CNR, and HALT bits
with readl_poll_timeout_atomic(). Unlike xhci_handshake(), handshake()
does not treat an all-ones read as an inaccessible controller.

If the controller becomes inaccessible, readl() can return U32_MAX. The CNR
bit then never clears, and the atomic poll keeps retrying. The atomic poll
budget is decremented using the requested delay and loop iterations, but
not the time spent in readl(). Slow failed MMIO reads can therefore keep
the PCI hotplug thread spinning far beyond the nominal timeout and trigger
a soft lockup. The 26-second value in the first warning is the watchdog
threshold, not the handshake timeout; repeated warnings showed the thread
still stuck up to 260 seconds before a controlled reboot, leaving the
system unavailable to normal management. Comparing the watchdog timestamps
with the RBP loop counter in the dumps (about 1,372 iterations in 26 s and
15,638 in 260 s) implies roughly 16-19 ms per polling iteration, despite
configured 10 us delay; these values are inferred, not direct measurements
of an individual readl().

Return -ENODEV when the polled register reads U32_MAX and stop the handoff
before issuing further accesses. This prevents an inaccessible xHCI from
keeping the PCI hotplug thread busy and making the system unavailable. An
eGPU may still fail to enumerate, but that failure must remain controlled
rather than causing a kernel Soft Lockup and taking down SSH or desktop
management. The existing timeout behavior for non-all-ones reads is
preserved, matching xhci_handshake().

A Thunderbolt-attached AMD Radeon Pro W5700 in a Razer Core X enclosure
reproduced this on an x86_64 UGREEN DXP8800 Plus with an Intel Core
i5-1235U. The GPU's xHCI function 0000:06:00.2 (1002:7316) triggered
the soft lockup in irq/123-pciehp; the register dump contained
RAX=U32_MAX:

  watchdog: BUG: soft lockup - CPU#6 stuck for 26s! [irq/123-pciehp:139]
  RIP: 0010:quirk_usb_early_handoff+0x552/0x7e0
  register state: RAX=00000000ffffffff

The call trace was:

  pci_do_fixups
  pci_bus_add_device
  pci_bus_add_devices
  pciehp_configure_device
  pciehp_handle_presence_or_link_change
  pciehp_ist
  irq_thread_fn

The failure reproduced on two hot-plug attempts and did not occur when the
enclosure was connected before boot.

Fixes: 66d4eadd8d06 ("USB: xhci: BIOS handoff and HW initialization.")
Cc: stable@vger.kernel.org
Signed-off-by: Haowen Bai <calvin.bai@ugreen.com>
---
 drivers/usb/host/pci-quirks.c | 22 +++++++++++++++++++---
 1 file changed, 19 insertions(+), 3 deletions(-)

diff --git a/drivers/usb/host/pci-quirks.c b/drivers/usb/host/pci-quirks.c
index 0404489c2f6a..e5ddd33c734d 100644
--- a/drivers/usb/host/pci-quirks.c
+++ b/drivers/usb/host/pci-quirks.c
@@ -1026,15 +1026,22 @@ static void quirk_usb_disable_ehci(struct pci_dev *pdev)
  * Returns 0 when the mask bits have the value done.
  * Returns -ETIMEDOUT if this condition is not true after
  * wait_usec microseconds have passed.
+ * Returns -ENODEV if the register reads as all-ones (hardware removed).
  */
 static int handshake(void __iomem *ptr, u32 mask, u32 done,
 		int wait_usec, int delay_usec)
 {
 	u32	result;
+	int	ret;
 
-	return readl_poll_timeout_atomic(ptr, result,
-					 ((result & mask) == done),
-					 delay_usec, wait_usec);
+	ret = readl_poll_timeout_atomic(ptr, result,
+					(result & mask) == done ||
+					result == U32_MAX,
+					delay_usec, wait_usec);
+	if (result == U32_MAX)
+		return -ENODEV;
+
+	return ret;
 }
 
 /*
@@ -1203,6 +1210,9 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
 		timeout = handshake(base + ext_cap_offset, XHCI_HC_BIOS_OWNED,
 				0, 1000000, 10);
 
+		if (timeout == -ENODEV)
+			goto iounmap;
+
 		/* Assume a buggy BIOS and take HC ownership anyway */
 		if (timeout) {
 			dev_warn(&pdev->dev,
@@ -1231,6 +1241,9 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
 	 */
 	timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_CNR, 0,
 			5000000, 10);
+	if (timeout == -ENODEV)
+		goto iounmap;
+
 	/* Assume a buggy HC and start HC initialization anyway */
 	if (timeout) {
 		val = readl(op_reg_base + XHCI_STS_OFFSET);
@@ -1247,6 +1260,9 @@ static void quirk_usb_handoff_xhci(struct pci_dev *pdev)
 	/* Wait for the HC to halt - poll every 125 usec (one microframe). */
 	timeout = handshake(op_reg_base + XHCI_STS_OFFSET, XHCI_STS_HALT, 1,
 			XHCI_MAX_HALT_USEC, 125);
+	if (timeout == -ENODEV)
+		goto iounmap;
+
 	if (timeout) {
 		val = readl(op_reg_base + XHCI_STS_OFFSET);
 		dev_warn(&pdev->dev,
-- 
2.47.3


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

* Re: [PATCH] usb: pci-quirks: abort xHCI handoff if MMIO is inaccessible
  2026-09-06 16:26 [PATCH] usb: pci-quirks: abort xHCI handoff if MMIO is inaccessible Haowen Bai
@ 2026-09-10 13:35 ` Mathias Nyman
  0 siblings, 0 replies; 2+ messages in thread
From: Mathias Nyman @ 2026-09-10 13:35 UTC (permalink / raw)
  To: Haowen Bai, mathias.nyman; +Cc: gregkh, linux-usb, linux-kernel, stable

On 9/6/26 19:26, Haowen Bai wrote:
> The xHCI early handoff quirk polls the BIOS ownership, CNR, and HALT bits
> with readl_poll_timeout_atomic(). Unlike xhci_handshake(), handshake()
> does not treat an all-ones read as an inaccessible controller.
> 
> If the controller becomes inaccessible, readl() can return U32_MAX. The CNR
> bit then never clears, and the atomic poll keeps retrying. The atomic poll
> budget is decremented using the requested delay and loop iterations, but
> not the time spent in readl(). Slow failed MMIO reads can therefore keep
> the PCI hotplug thread spinning far beyond the nominal timeout and trigger
> a soft lockup. The 26-second value in the first warning is the watchdog
> threshold, not the handshake timeout; repeated warnings showed the thread
> still stuck up to 260 seconds before a controlled reboot, leaving the
> system unavailable to normal management. Comparing the watchdog timestamps
> with the RBP loop counter in the dumps (about 1,372 iterations in 26 s and
> 15,638 in 260 s) implies roughly 16-19 ms per polling iteration, despite
> configured 10 us delay; these values are inferred, not direct measurements
> of an individual readl().
> 
> Return -ENODEV when the polled register reads U32_MAX and stop the handoff
> before issuing further accesses. This prevents an inaccessible xHCI from
> keeping the PCI hotplug thread busy and making the system unavailable. An
> eGPU may still fail to enumerate, but that failure must remain controlled
> rather than causing a kernel Soft Lockup and taking down SSH or desktop
> management. The existing timeout behavior for non-all-ones reads is
> preserved, matching xhci_handshake().
> 
> A Thunderbolt-attached AMD Radeon Pro W5700 in a Razer Core X enclosure
> reproduced this on an x86_64 UGREEN DXP8800 Plus with an Intel Core
> i5-1235U. The GPU's xHCI function 0000:06:00.2 (1002:7316) triggered
> the soft lockup in irq/123-pciehp; the register dump contained
> RAX=U32_MAX:
> 
>    watchdog: BUG: soft lockup - CPU#6 stuck for 26s! [irq/123-pciehp:139]
>    RIP: 0010:quirk_usb_early_handoff+0x552/0x7e0
>    register state: RAX=00000000ffffffff
> 
> The call trace was:
> 
>    pci_do_fixups
>    pci_bus_add_device
>    pci_bus_add_devices
>    pciehp_configure_device
>    pciehp_handle_presence_or_link_change
>    pciehp_ist
>    irq_thread_fn
> 
> The failure reproduced on two hot-plug attempts and did not occur when the
> enclosure was connected before boot.
> 
> Fixes: 66d4eadd8d06 ("USB: xhci: BIOS handoff and HW initialization.")
> Cc: stable@vger.kernel.org
> Signed-off-by: Haowen Bai <calvin.bai@ugreen.com>
Acked-by: Mathias Nyman <mathias.nyman@linux.intel.com>

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

end of thread, other threads:[~2026-09-10 13:36 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-09-06 16:26 [PATCH] usb: pci-quirks: abort xHCI handoff if MMIO is inaccessible Haowen Bai
2026-09-10 13:35 ` Mathias Nyman

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

all inboxes | Powered by JetHome®