Re: [PATCH v4] PCI: Relabel JHL6540 on Lenovo X1 Carbon 7,8

From: Esther Shimanovich
Date: Mon Apr 15 2024 - 18:34:23 EST


Hey!
Asking for some help on implementation.
So I implemented most of this, and successfully tested the quirk on 6
different devices with various types of discrete fixed JHL Thunderbolt
chips.

However I want to add an additional check. A device wouldn't need this
quirk if it already has Thunderbolt functionality built in within its
Root Port.

I tried to use "is_thunderbolt" as an identifier for that type of
device--- but when I tested on a device with a thunderbolt root port,
"is_thunderbolt" was false for all the Thunderbolt PCI components
listed below.

~ # lspci -nn | grep Thunderbolt
00:07.0 PCI bridge [0604]: Intel Corporation Tiger Lake-LP Thunderbolt
4 PCI Express Root Port #1 [8086:9a25] (rev 01)
00:07.2 PCI bridge [0604]: Intel Corporation Tiger Lake-LP Thunderbolt
4 PCI Express Root Port #2 [8086:9a27] (rev 01)
00:0d.0 USB controller [0c03]: Intel Corporation Tiger Lake-LP
Thunderbolt 4 USB Controller [8086:9a13] (rev 01)
00:0d.2 USB controller [0c03]: Intel Corporation Tiger Lake-LP
Thunderbolt 4 NHI #0 [8086:9a1b] (rev 01)
00:0d.3 USB controller [0c03]: Intel Corporation Tiger Lake-LP
Thunderbolt 4 NHI #1 [8086:9a1d] (rev 01)

The device I tested was the Lenovo carbon X1 Gen 9. When
set_pcie_thunderbolt is run, the devices listed above return false on
the pci_find_next_ext_capability check.

I have spent some time trying to see if there are any ACPI values or
any alternative indicators to reliably know if a root port has
thunderbolt capabilities. I do see that ADBG is often set to TBT but
that looks like a debugging tool in ACPI.

I also looked through lspci -vvv and compared the output with a device
that has no Thunderbolt built into its CPU, which gave me nothing.

I also tried looking through values in /sys/bus and searching through
the kernel, looking through logs etc. The only option I see now is
figuring out how to get the string value returned by the lspci and
parsing it, but I'm not 100% sure if all Thunderbolt CPUs would have
Root ports specifically labeled as "Thunderbolt Root Port". I'm also
not sure if that value is supposed to be used in that way.

I was hoping that someone may have a suggestion here.


Just for reference, this is the fix I have so far. I don't want to
submit it as a new patch, until I resolve the above question.

+static bool get_pci_exp_upstream_port(struct pci_dev *dev,
+ struct pci_dev **upstream_port)
+{
+ struct pci_dev *parent = dev;
+
+ // If the dev is an upstream port, return itself
+ if (pci_pcie_type(dev) == PCI_EXP_TYPE_UPSTREAM) {
+ *upstream_port = dev;
+ return true;
+ }
+
+ // Iterate through the dev's parents to find its upstream port
+ while ((parent = pci_upstream_bridge(parent))) {
+ if (pci_pcie_type(parent) == PCI_EXP_TYPE_UPSTREAM) {
+ *upstream_port = parent;
+ return true;
+ }
+ }
+ return false;
+}
+
+static void relabel_internal_thunderbolt_chip(struct pci_dev *dev)
+{
+ struct pci_dev *upstream_port;
+ struct pci_dev *upstream_ports_parent;
+
+ // Get the upstream port closest to the dev
+ if (!(get_pci_exp_upstream_port(dev, &upstream_port)))
+ return;
+
+ // Next, we confirm if the upstream port is directly behind a PCIe root
+ // port.
+ if (!(upstream_ports_parent == pci_upstream_bridge(upstream_port)))
+ return;
+ if (!(pci_pcie_type(upstream_ports_parent) == PCI_EXP_TYPE_ROOT_PORT))
+ return; // quirk does not apply
+
+ // If a device's root port already has thunderbolt capabilities, then
+ // it shouldn't be using this quirk.
+ // TODO: THIS CHECK DOES NOT WORK
+ // I ALSO TRIED USING pci_is_thunderbolt_attached WHICH DIDN'T
WORK EITHER
+ if (!(upstream_ports_parent->is_thunderbolt))
+ return; // thunderbolt functionality is built into root port
+
+ // Apply quirk
+ dev_set_removable(&dev->dev, DEVICE_FIXED);
+
+ // External facing bridges must be marked as such so that devices
+ // below them can correctly be labeled as REMOVABLE
+ if ((pci_pcie_type(dev) == PCI_EXP_TYPE_DOWNSTREAM)
+ && (dev->devfn == 0x08 | dev->devfn == 0x20))
+ dev->external_facing = true;
+}