USB3 port events are dropped whenever the controller has only one roothub.
The check that guards them treats a missing shared hcd as proof the hcd was
removed, which stopped being true with upstream commit
4736ebd7fcaf ("usb:
host: xhci-plat: omit shared hcd if either root hub has no ports"). A
controller whose USB2 root hub has no ports gets a single roothub and never
has a shared one, so every SuperSpeed event is thrown away and nothing
enumerates even though the port reports the device:
0x006a1203 Powered Connected Enabled Link:U0 PortSpeed:4
Broadcom Northstar is such a controller. USB3 works there up to 5.15 and
stops from 5.19 onwards.
Tested on an Asus RT-N18U with kernel 6.18, seven SuperSpeed enumerations,
USB2 unaffected on both ports.
Link: https://github.com/openwrt/openwrt/issues/19592
Signed-off-by: Semih Baskan <strst.gs@gmail.com>
Link: https://github.com/openwrt/openwrt/pull/24547
Signed-off-by: Hauke Mehrtens <hauke@hauke-m.de>
--- /dev/null
+From eb8cfe27aef67b30299aaf2a1ac538cf905135f2 Mon Sep 17 00:00:00 2001
+From: Semih Baskan <strst.gs@gmail.com>
+Date: Mon, 3 Aug 2026 07:08:11 +0300
+Subject: [PATCH] usb: xhci: Handle USB3 port events when there is one roothub
+
+handle_port_status() drops every USB3 port event when xhci->shared_hcd is
+NULL. The check dates from a time when xhci-plat always created a shared
+hcd, so a NULL one could only mean the hcd had been removed.
+
+Since commit 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if
+either root hub has no ports") that is no longer true. A controller whose
+USB2 root hub has no ports gets a single roothub, the USB3 rhub is served
+by the main hcd, and shared_hcd stays NULL for the lifetime of the device.
+Every SuperSpeed port event is then thrown away as bogus behind a debug
+message, so devices never enumerate even though the port reports them:
+
+ 0x006a1203 Powered Connected Enabled Link:U0 PortSpeed:4
+
+Broadcom Northstar is such a controller. USB3 works there up to 5.15 and
+stops working from 5.19 onwards.
+
+Ask xhci_get_usb3_hcd() instead. It returns the shared hcd when there is
+one, the main hcd when the USB2 root hub has no ports, and NULL once the
+shared hcd is gone, which keeps the original meaning of the check.
+
+Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports")
+Signed-off-by: Semih Baskan <strst.gs@gmail.com>
+---
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -1986,7 +1986,7 @@ static void handle_port_status(struct xh
+ vdev = xhci->devs[port->slot_id];
+
+ /* We might get interrupts after shared_hcd is removed */
+- if (port->rhub == &xhci->usb3_rhub && xhci->shared_hcd == NULL) {
++ if (port->rhub == &xhci->usb3_rhub && xhci_get_usb3_hcd(xhci) == NULL) {
+ xhci_dbg(xhci, "ignore port event for removed USB3 hcd\n");
+ bogus_port_status = true;
+ goto cleanup;
--- /dev/null
+From eb8cfe27aef67b30299aaf2a1ac538cf905135f2 Mon Sep 17 00:00:00 2001
+From: Semih Baskan <strst.gs@gmail.com>
+Date: Mon, 3 Aug 2026 07:08:11 +0300
+Subject: [PATCH] usb: xhci: Handle USB3 port events when there is one roothub
+
+handle_port_status() drops every USB3 port event when xhci->shared_hcd is
+NULL. The check dates from a time when xhci-plat always created a shared
+hcd, so a NULL one could only mean the hcd had been removed.
+
+Since commit 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if
+either root hub has no ports") that is no longer true. A controller whose
+USB2 root hub has no ports gets a single roothub, the USB3 rhub is served
+by the main hcd, and shared_hcd stays NULL for the lifetime of the device.
+Every SuperSpeed port event is then thrown away as bogus behind a debug
+message, so devices never enumerate even though the port reports them:
+
+ 0x006a1203 Powered Connected Enabled Link:U0 PortSpeed:4
+
+Broadcom Northstar is such a controller. USB3 works there up to 5.15 and
+stops working from 5.19 onwards.
+
+Ask xhci_get_usb3_hcd() instead. It returns the shared hcd when there is
+one, the main hcd when the USB2 root hub has no ports, and NULL once the
+shared hcd is gone, which keeps the original meaning of the check.
+
+Fixes: 4736ebd7fcaf ("usb: host: xhci-plat: omit shared hcd if either root hub has no ports")
+Signed-off-by: Semih Baskan <strst.gs@gmail.com>
+---
+--- a/drivers/usb/host/xhci-ring.c
++++ b/drivers/usb/host/xhci-ring.c
+@@ -2026,7 +2026,7 @@ static void handle_port_status(struct xh
+ vdev = xhci->devs[port->slot_id];
+
+ /* We might get interrupts after shared_hcd is removed */
+- if (port->rhub == &xhci->usb3_rhub && xhci->shared_hcd == NULL) {
++ if (port->rhub == &xhci->usb3_rhub && xhci_get_usb3_hcd(xhci) == NULL) {
+ xhci_dbg(xhci, "ignore port event for removed USB3 hcd\n");
+ bogus_port_status = true;
+ goto cleanup;