Thread (5 messages) 5 messages, 3 authors, 11d ago

[PATCH 2/2] usb: xhci-mtk: power down u3 ports skipped by u3p-dis-msk

COOLING11d

From: Frank Wunderlich <hidden>
Date: 2026-09-19 11:48:14
Also in: linux-clk, linux-mediatek, linux-usb, lkml
Subsystem: mediatek usb3 drd ip driver, the rest, usb subsystem, usb xhci driver · Maintainers: Chunfeng Yun, Linus Torvalds, Greg Kroah-Hartman, Mathias Nyman

From: Mihai Ordean <redacted>

xhci_mtk_host_enable() skips ports flagged in "mediatek,u3p-dis-msk"
entirely: it neither powers them up nor powers them down, leaving them
in their power-on/bootloader default state, which on MediaTek IPPC is
powered up and host-selected. The mask exists precisely for ports whose
USB3 PHY is not usable - on BPI-R4 Pro (MT7988A) ssusb0's U3 SerDes
lane is shared with (and muxed to) PCIe2, so the board DT masks U3 port
0 and omits the xphy U3 port from "phys".

The result on that board is a U3 port that is powered and host-selected
but has no initialized PHY and a MAC clock domain that is never
released from reset (the driver deliberately excludes STS1_U3_MAC_RST
from its stability poll for masked ports). This holds the controller's
level interrupt permanently asserted with a status the xHCI interrupt
handler cannot acknowledge:

  [    2.455798] xhci-mtk 11190000.usb: irq 120, io mem 0x11190000
  [    2.861314] irq 120: nobody cared (try booting with the "irqpoll" option)
  [    3.242105] [<0000000014dcb6ae>] usb_hcd_irq
  [    3.246371] Disabling IRQ #120

Once the spurious-IRQ detector disables the line, the fully functional
USB2 bus on the same controller dies with it: xHC commands are queued
but their completions never interrupt, the first hub_event needing a
command parks in D state holding the hub lock

  [  126.053644] Workqueue: usb_hub_wq hub_event
  [  126.053742]  xhci_disable_slot+0xb4/0x188
  [  126.053757]  xhci_free_dev+0xfc/0x2a4
  [  126.053771]  hub_event+0x1364/0x1a0c

and device_shutdown() blocks behind it on reboot, hanging the system.

Explicitly park masked ports by setting CTRL_U3_PORT_PDN and
CTRL_U3_PORT_DIS, mirroring what host_enable() does in reverse for
active ports. xhci_mtk_host_disable() already skips masked ports, which
remains correct as they are now already down.

Signed-off-by: Mihai Ordean <redacted>
Signed-off-by: Frank Wunderlich <redacted>
---
 drivers/usb/host/xhci-mtk.c | 13 +++++++++++++
 1 file changed, 13 insertions(+)
diff --git a/drivers/usb/host/xhci-mtk.c b/drivers/usb/host/xhci-mtk.c
index 60af5fe29bd4..016a4902fc4c 100644
--- a/drivers/usb/host/xhci-mtk.c
+++ b/drivers/usb/host/xhci-mtk.c
@@ -219,6 +219,19 @@ static int xhci_mtk_host_enable(struct xhci_hcd_mtk *mtk)
 	/* power on and enable u3 ports except skipped ones */
 	for (i = 0; i < mtk->num_u3_ports; i++) {
 		if ((0x1 << i) & mtk->u3p_dis_msk) {
+			/*
+			 * Park skipped ports instead of leaving them in
+			 * their power-on default state: the port's PHY may
+			 * be uninitialized or its SerDes lane owned by
+			 * another controller (e.g. PCIe), in which case a
+			 * powered-up port whose MAC clock domain is never
+			 * released from reset can hold the interrupt line
+			 * asserted, getting it disabled by the spurious
+			 * IRQ detector and killing the whole host.
+			 */
+			value = readl(&ippc->u3_ctrl_p[i]);
+			value |= CTRL_U3_PORT_PDN | CTRL_U3_PORT_DIS;
+			writel(value, &ippc->u3_ctrl_p[i]);
 			u3_ports_disabled++;
 			continue;
 		}
-- 
2.53.0

Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help