@@ -250,6 +250,125 @@ void __init pci_acpi_crs_quirks(void)
250
250
pr_info ("Please notify linux-pci@vger.kernel.org so future kernels can do this automatically\n" );
251
251
}
252
252
253
+ /*
254
+ * Check if pdev is part of a PCIe switch that is directly below the
255
+ * specified bridge.
256
+ */
257
+ static bool pcie_switch_directly_under (struct pci_dev * bridge ,
258
+ struct pci_dev * pdev )
259
+ {
260
+ struct pci_dev * parent = pci_upstream_bridge (pdev );
261
+
262
+ /* If the device doesn't have a parent, it's not under anything */
263
+ if (!parent )
264
+ return false;
265
+
266
+ /*
267
+ * If the device has a PCIe type, check if it is below the
268
+ * corresponding PCIe switch components (if applicable). Then check
269
+ * if its upstream port is directly beneath the specified bridge.
270
+ */
271
+ switch (pci_pcie_type (pdev )) {
272
+ case PCI_EXP_TYPE_UPSTREAM :
273
+ return parent == bridge ;
274
+
275
+ case PCI_EXP_TYPE_DOWNSTREAM :
276
+ if (pci_pcie_type (parent ) != PCI_EXP_TYPE_UPSTREAM )
277
+ return false;
278
+ parent = pci_upstream_bridge (parent );
279
+ return parent == bridge ;
280
+
281
+ case PCI_EXP_TYPE_ENDPOINT :
282
+ if (pci_pcie_type (parent ) != PCI_EXP_TYPE_DOWNSTREAM )
283
+ return false;
284
+ parent = pci_upstream_bridge (parent );
285
+ if (!parent || pci_pcie_type (parent ) != PCI_EXP_TYPE_UPSTREAM )
286
+ return false;
287
+ parent = pci_upstream_bridge (parent );
288
+ return parent == bridge ;
289
+ }
290
+
291
+ return false;
292
+ }
293
+
294
+ static bool pcie_has_usb4_host_interface (struct pci_dev * pdev )
295
+ {
296
+ struct fwnode_handle * fwnode ;
297
+
298
+ /*
299
+ * For USB4, the tunneled PCIe Root or Downstream Ports are marked
300
+ * with the "usb4-host-interface" ACPI property, so we look for
301
+ * that first. This should cover most cases.
302
+ */
303
+ fwnode = fwnode_find_reference (dev_fwnode (& pdev -> dev ),
304
+ "usb4-host-interface" , 0 );
305
+ if (!IS_ERR (fwnode )) {
306
+ fwnode_handle_put (fwnode );
307
+ return true;
308
+ }
309
+
310
+ /*
311
+ * Any integrated Thunderbolt 3/4 PCIe Root Ports from Intel
312
+ * before Alder Lake do not have the "usb4-host-interface"
313
+ * property so we use their PCI IDs instead. All these are
314
+ * tunneled. This list is not expected to grow.
315
+ */
316
+ if (pdev -> vendor == PCI_VENDOR_ID_INTEL ) {
317
+ switch (pdev -> device ) {
318
+ /* Ice Lake Thunderbolt 3 PCIe Root Ports */
319
+ case 0x8a1d :
320
+ case 0x8a1f :
321
+ case 0x8a21 :
322
+ case 0x8a23 :
323
+ /* Tiger Lake-LP Thunderbolt 4 PCIe Root Ports */
324
+ case 0x9a23 :
325
+ case 0x9a25 :
326
+ case 0x9a27 :
327
+ case 0x9a29 :
328
+ /* Tiger Lake-H Thunderbolt 4 PCIe Root Ports */
329
+ case 0x9a2b :
330
+ case 0x9a2d :
331
+ case 0x9a2f :
332
+ case 0x9a31 :
333
+ return true;
334
+ }
335
+ }
336
+
337
+ return false;
338
+ }
339
+
340
+ bool arch_pci_dev_is_removable (struct pci_dev * pdev )
341
+ {
342
+ struct pci_dev * parent , * root ;
343
+
344
+ /* pdev without a parent or Root Port is never tunneled */
345
+ parent = pci_upstream_bridge (pdev );
346
+ if (!parent )
347
+ return false;
348
+ root = pcie_find_root_port (pdev );
349
+ if (!root )
350
+ return false;
351
+
352
+ /* Internal PCIe devices are not tunneled */
353
+ if (!root -> external_facing )
354
+ return false;
355
+
356
+ /* Anything directly behind a "usb4-host-interface" is tunneled */
357
+ if (pcie_has_usb4_host_interface (parent ))
358
+ return true;
359
+
360
+ /*
361
+ * Check if this is a discrete Thunderbolt/USB4 controller that is
362
+ * directly behind the non-USB4 PCIe Root Port marked as
363
+ * "ExternalFacingPort". Those are not behind a PCIe tunnel.
364
+ */
365
+ if (pcie_switch_directly_under (root , pdev ))
366
+ return false;
367
+
368
+ /* PCIe devices after the discrete chip are tunneled */
369
+ return true;
370
+ }
371
+
253
372
#ifdef CONFIG_PCI_MMCONFIG
254
373
static int check_segment (u16 seg , struct device * dev , char * estr )
255
374
{
0 commit comments