|
| 1 | +From c9a88b70e1157e75b7de963bf7d2144c127a5037 Mon Sep 17 00:00:00 2001 |
| 2 | +From: deqrocks <andre@negmaster.com> |
| 3 | +Date: Sun, 5 Apr 2026 13:36:54 +0200 |
| 4 | +Subject: [PATCH] thunderbolt: add device links for integrated Apple T2 NHI |
| 5 | + |
| 6 | +--- |
| 7 | + drivers/thunderbolt/tb.c | 115 +++++++++++++++++++++++++++------------ |
| 8 | + 1 file changed, 80 insertions(+), 35 deletions(-) |
| 9 | + |
| 10 | +diff --git a/drivers/thunderbolt/tb.c b/drivers/thunderbolt/tb.c |
| 11 | +index 4f5f1dfc0..1b4ff0d9e 100644 |
| 12 | +--- a/drivers/thunderbolt/tb.c |
| 13 | ++++ b/drivers/thunderbolt/tb.c |
| 14 | +@@ -9,6 +9,7 @@ |
| 15 | + #include <linux/slab.h> |
| 16 | + #include <linux/errno.h> |
| 17 | + #include <linux/delay.h> |
| 18 | ++#include <linux/acpi.h> |
| 19 | + #include <linux/pm_runtime.h> |
| 20 | + #include <linux/platform_data/x86/apple.h> |
| 21 | + |
| 22 | +@@ -3305,21 +3306,12 @@ static const struct tb_cm_ops tb_cm_ops = { |
| 23 | + static bool tb_apple_add_links(struct tb_nhi *nhi) |
| 24 | + { |
| 25 | + struct pci_dev *upstream, *pdev; |
| 26 | ++ struct acpi_device *adev; |
| 27 | + bool ret; |
| 28 | + |
| 29 | + if (!x86_apple_machine) |
| 30 | + return false; |
| 31 | + |
| 32 | +- switch (nhi->pdev->device) { |
| 33 | +- case PCI_DEVICE_ID_INTEL_LIGHT_RIDGE: |
| 34 | +- case PCI_DEVICE_ID_INTEL_CACTUS_RIDGE_4C: |
| 35 | +- case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_2C_NHI: |
| 36 | +- case PCI_DEVICE_ID_INTEL_FALCON_RIDGE_4C_NHI: |
| 37 | +- break; |
| 38 | +- default: |
| 39 | +- return false; |
| 40 | +- } |
| 41 | +- |
| 42 | + upstream = pci_upstream_bridge(nhi->pdev); |
| 43 | + while (upstream) { |
| 44 | + if (!pci_is_pcie(upstream)) |
| 45 | +@@ -3329,34 +3321,87 @@ static bool tb_apple_add_links(struct tb_nhi *nhi) |
| 46 | + upstream = pci_upstream_bridge(upstream); |
| 47 | + } |
| 48 | + |
| 49 | +- if (!upstream) |
| 50 | +- return false; |
| 51 | +- |
| 52 | +- /* |
| 53 | +- * For each hotplug downstream port, create add device link |
| 54 | +- * back to NHI so that PCIe tunnels can be re-established after |
| 55 | +- * sleep. |
| 56 | +- */ |
| 57 | + ret = false; |
| 58 | +- for_each_pci_bridge(pdev, upstream->subordinate) { |
| 59 | +- const struct device_link *link; |
| 60 | + |
| 61 | +- if (!pci_is_pcie(pdev)) |
| 62 | +- continue; |
| 63 | +- if (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM || |
| 64 | +- !pdev->is_pciehp) |
| 65 | +- continue; |
| 66 | ++ if (upstream) { |
| 67 | ++ /* |
| 68 | ++ * Discrete Thunderbolt controller (e.g. Light Ridge, Falcon |
| 69 | ++ * Ridge) behind a PCIe switch. Create device links for each |
| 70 | ++ * hotplug-capable downstream port under that switch. |
| 71 | ++ */ |
| 72 | ++ for_each_pci_bridge(pdev, upstream->subordinate) { |
| 73 | ++ const struct device_link *link; |
| 74 | + |
| 75 | +- link = device_link_add(&pdev->dev, &nhi->pdev->dev, |
| 76 | +- DL_FLAG_AUTOREMOVE_SUPPLIER | |
| 77 | +- DL_FLAG_PM_RUNTIME); |
| 78 | +- if (link) { |
| 79 | +- dev_dbg(&nhi->pdev->dev, "created link from %s\n", |
| 80 | +- dev_name(&pdev->dev)); |
| 81 | +- ret = true; |
| 82 | +- } else { |
| 83 | +- dev_warn(&nhi->pdev->dev, "device link creation from %s failed\n", |
| 84 | +- dev_name(&pdev->dev)); |
| 85 | ++ if (!pci_is_pcie(pdev)) |
| 86 | ++ continue; |
| 87 | ++ if (pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM || |
| 88 | ++ !pdev->is_pciehp) |
| 89 | ++ continue; |
| 90 | ++ |
| 91 | ++ link = device_link_add(&pdev->dev, &nhi->pdev->dev, |
| 92 | ++ DL_FLAG_AUTOREMOVE_SUPPLIER | |
| 93 | ++ DL_FLAG_PM_RUNTIME); |
| 94 | ++ if (link) { |
| 95 | ++ dev_dbg(&nhi->pdev->dev, "created link from %s\n", |
| 96 | ++ dev_name(&pdev->dev)); |
| 97 | ++ ret = true; |
| 98 | ++ } else { |
| 99 | ++ dev_warn(&nhi->pdev->dev, |
| 100 | ++ "device link creation from %s failed\n", |
| 101 | ++ dev_name(&pdev->dev)); |
| 102 | ++ } |
| 103 | ++ } |
| 104 | ++ } else { |
| 105 | ++ unsigned int slot, func; |
| 106 | ++ |
| 107 | ++ /* |
| 108 | ++ * Integrated Thunderbolt NHI on T2 Macs (2018-2020). The |
| 109 | ++ * NHI and its associated PCIe root ports all sit directly |
| 110 | ++ * on the root complex with no upstream port. Apple's ACPI |
| 111 | ++ * tables name Thunderbolt root ports as TRP0, TRP1, etc. |
| 112 | ++ * Find them and create device links back to the NHI so |
| 113 | ++ * that PCIe tunnels can be re-established after sleep. |
| 114 | ++ */ |
| 115 | ++ for (slot = 0; slot < 32; slot++) { |
| 116 | ++ for (func = 0; func < 8; func++) { |
| 117 | ++ const struct device_link *link; |
| 118 | ++ const char *bid; |
| 119 | ++ |
| 120 | ++ pdev = pci_get_slot(nhi->pdev->bus, |
| 121 | ++ PCI_DEVFN(slot, func)); |
| 122 | ++ if (!pdev) |
| 123 | ++ continue; |
| 124 | ++ |
| 125 | ++ if (!pci_is_pcie(pdev)) |
| 126 | ++ goto put_pdev; |
| 127 | ++ if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT) |
| 128 | ++ goto put_pdev; |
| 129 | ++ |
| 130 | ++ adev = ACPI_COMPANION(&pdev->dev); |
| 131 | ++ if (!adev) |
| 132 | ++ goto put_pdev; |
| 133 | ++ |
| 134 | ++ bid = acpi_device_bid(adev); |
| 135 | ++ if (!bid || strncmp(bid, "TRP", 3) != 0) |
| 136 | ++ goto put_pdev; |
| 137 | ++ |
| 138 | ++ link = device_link_add(&pdev->dev, &nhi->pdev->dev, |
| 139 | ++ DL_FLAG_AUTOREMOVE_SUPPLIER | |
| 140 | ++ DL_FLAG_PM_RUNTIME); |
| 141 | ++ if (link) { |
| 142 | ++ dev_dbg(&nhi->pdev->dev, |
| 143 | ++ "created link from %s\n", |
| 144 | ++ dev_name(&pdev->dev)); |
| 145 | ++ ret = true; |
| 146 | ++ } else { |
| 147 | ++ dev_warn(&nhi->pdev->dev, |
| 148 | ++ "device link creation from %s failed\n", |
| 149 | ++ dev_name(&pdev->dev)); |
| 150 | ++ } |
| 151 | ++ |
| 152 | ++put_pdev: |
| 153 | ++ pci_dev_put(pdev); |
| 154 | ++ } |
| 155 | + } |
| 156 | + } |
| 157 | + |
| 158 | +-- |
| 159 | +2.53.0 |
| 160 | + |
0 commit comments