[SRU][R][PATCH 1/1] UBUNTU: SAUCE: thunderbolt: Fix PCIe device enumeration with delayed rescan
AceLan Kao
acelan.kao at canonical.com
Wed Apr 8 00:39:17 UTC 2026
From: "Chia-Lin Kao (AceLan)" <acelan.kao at canonical.com>
BugLink: https://bugs.launchpad.net/bugs/2139572
PCIe devices behind Thunderbolt tunnels may fail to enumerate when
spurious hotplug events prevent pciehp from detecting link-up.
Root cause:
Spurious unplug events occur immediately after tunnel activation:
[ 932.438] thunderbolt: acking hot unplug event on 702:2
[ 932.852] thunderbolt: PCIe Up path activation complete
[ 932.855] thunderbolt: hotplug event for upstream port 702:2
(unplug: 0)
[ 932.855] thunderbolt: hotplug event for upstream port 702:2
(unplug: 1)
These events disrupt pciehp timing, causing device enumeration to fail
~70% of the time on affected hardware. Manual PCI rescan succeeds,
proving devices are present and functional on the bus.
Solution:
Schedule a delayed pci_rescan_bus() (300ms) after tunnel activation.
Since pci_rescan_bus() is idempotent and won't re-add already-enumerated
devices, we unconditionally rescan rather than comparing device counts.
This is non-blocking and avoids overhead on systems where pciehp works
correctly, as the rescan is a no-op when devices are already present.
Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao at canonical.com>
(cherry picked from commit https://lore.kernel.org/lkml/20260121060857.237777-1-acelan.kao@canonical.com/T/#u)
Signed-off-by: Chia-Lin Kao (AceLan) <acelan.kao at canonical.com>
---
drivers/thunderbolt/tb.c | 35 +++++++++++++++++++++++++++++++++++
1 file changed, 35 insertions(+)
diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c
index c69c323e6952a..4967ceab83109 100644
--- a/drivers/thunderbolt/tb.c
+++ b/drivers/thunderbolt/tb.c
@@ -11,6 +11,7 @@
#include <linux/delay.h>
#include <linux/pm_runtime.h>
#include <linux/platform_data/x86/apple.h>
+#include <linux/pci.h>
#include "tb.h"
#include "tb_regs.h"
@@ -18,6 +19,7 @@
#define TB_TIMEOUT 100 /* ms */
#define TB_RELEASE_BW_TIMEOUT 10000 /* ms */
+#define TB_PCIEHP_ENUMERATION_DELAY 300 /* ms */
/*
* How many time bandwidth allocation request from graphics driver is
@@ -83,6 +85,12 @@ struct tb_hotplug_event {
int retry;
};
+/* Delayed work to rescan PCIe bus after tunnel activation */
+struct tb_pci_rescan_work {
+ struct delayed_work work;
+ struct pci_bus *bus;
+};
+
static void tb_scan_port(struct tb_port *port);
static void tb_handle_hotplug(struct work_struct *work);
static void tb_dp_resource_unavailable(struct tb *tb, struct tb_port *port,
@@ -90,6 +98,17 @@ static void tb_dp_resource_unavailable(struct tb *tb, struct tb_port *port,
static void tb_queue_dp_bandwidth_request(struct tb *tb, u64 route, u8 port,
int retry, unsigned long delay);
+static void tb_pci_rescan_work_fn(struct work_struct *work)
+{
+ struct tb_pci_rescan_work *rescan_work =
+ container_of(work, typeof(*rescan_work), work.work);
+
+ pci_lock_rescan_remove();
+ pci_rescan_bus(rescan_work->bus);
+ pci_unlock_rescan_remove();
+ kfree(rescan_work);
+}
+
static void tb_queue_hotplug(struct tb *tb, u64 route, u8 port, bool unplug)
{
struct tb_hotplug_event *ev;
@@ -2313,6 +2332,22 @@ static int tb_tunnel_pci(struct tb *tb, struct tb_switch *sw)
tb_sw_warn(sw, "failed to connect xHCI\n");
list_add_tail(&tunnel->list, &tcm->tunnel_list);
+
+ /* Schedule a delayed PCIe bus rescan in case pciehp misses devices */
+ if (tb->nhi && tb->nhi->pdev && tb->nhi->pdev->bus) {
+ struct pci_bus *bus = tb->nhi->pdev->bus;
+ struct tb_pci_rescan_work *rescan_work;
+
+ rescan_work = kmalloc(sizeof(*rescan_work), GFP_KERNEL);
+ if (!rescan_work)
+ return 0;
+
+ rescan_work->bus = bus->parent ? bus->parent : bus;
+ INIT_DELAYED_WORK(&rescan_work->work, tb_pci_rescan_work_fn);
+ queue_delayed_work(tb->wq, &rescan_work->work,
+ msecs_to_jiffies(TB_PCIEHP_ENUMERATION_DELAY));
+ }
+
return 0;
}
--
2.53.0
More information about the kernel-team
mailing list