]> www.infradead.org Git - users/hch/misc.git/commitdiff
PCI: Track Flit Mode Status & print it with link status
authorIlpo Järvinen <ilpo.jarvinen@linux.intel.com>
Fri, 7 Feb 2025 16:18:35 +0000 (18:18 +0200)
committerBjorn Helgaas <bhelgaas@google.com>
Fri, 21 Feb 2025 23:31:35 +0000 (17:31 -0600)
PCIe r6.0 added Flit mode, which mainly alters HW behavior, but there are
some OS visible changes. The OS visible changes include differences in the
layout of some capabilities and interpretation of the TLP headers (in
diagnostics situations).

To be able to determine which mode the PCIe Link is using, store the Flit
Mode Status (PCIe r6.1 sec 7.5.3.20) information in addition to the Link
speed into struct pci_bus in pcie_update_link_speed().

Link: https://lore.kernel.org/r/20250207161836.2755-2-ilpo.jarvinen@linux.intel.com
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
[bhelgaas: use unsigned int:1 instead of bool, update flit_mode setting]
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/probe.c
include/linux/pci.h

index bb5a8d9f03ad9897c8afcc4aa63aeb69b86ac47d..10130ac9f9797f0172853b0c4a291ade56abb57f 100644 (file)
@@ -292,7 +292,7 @@ int pciehp_check_link_status(struct controller *ctrl)
 {
        struct pci_dev *pdev = ctrl_dev(ctrl);
        bool found;
-       u16 lnk_status;
+       u16 lnk_status, linksta2;
 
        if (!pcie_wait_for_link(pdev, true)) {
                ctrl_info(ctrl, "Slot(%s): No link\n", slot_name(ctrl));
@@ -319,7 +319,8 @@ int pciehp_check_link_status(struct controller *ctrl)
                return -1;
        }
 
-       __pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status);
+       pcie_capability_read_word(pdev, PCI_EXP_LNKSTA2, &linksta2);
+       __pcie_update_link_speed(ctrl->pcie->port->subordinate, lnk_status, linksta2);
 
        if (!found) {
                ctrl_info(ctrl, "Slot(%s): No device found\n",
index 869d204a70a372d240b1a6988a2159a79999e1ca..313c6686375221cfd7cd590caac25109877d9d9e 100644 (file)
@@ -6190,21 +6190,25 @@ void __pcie_print_link_status(struct pci_dev *dev, bool verbose)
        enum pci_bus_speed speed, speed_cap;
        struct pci_dev *limiting_dev = NULL;
        u32 bw_avail, bw_cap;
+       char *flit_mode = "";
 
        bw_cap = pcie_bandwidth_capable(dev, &speed_cap, &width_cap);
        bw_avail = pcie_bandwidth_available(dev, &limiting_dev, &speed, &width);
 
+       if (dev->bus && dev->bus->flit_mode)
+               flit_mode = ", in Flit mode";
+
        if (bw_avail >= bw_cap && verbose)
-               pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth (%s x%d link)\n",
+               pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth (%s x%d link)%s\n",
                         bw_cap / 1000, bw_cap % 1000,
-                        pci_speed_string(speed_cap), width_cap);
+                        pci_speed_string(speed_cap), width_cap, flit_mode);
        else if (bw_avail < bw_cap)
-               pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth, limited by %s x%d link at %s (capable of %u.%03u Gb/s with %s x%d link)\n",
+               pci_info(dev, "%u.%03u Gb/s available PCIe bandwidth, limited by %s x%d link at %s (capable of %u.%03u Gb/s with %s x%d link)%s\n",
                         bw_avail / 1000, bw_avail % 1000,
                         pci_speed_string(speed), width,
                         limiting_dev ? pci_name(limiting_dev) : "<unknown>",
                         bw_cap / 1000, bw_cap % 1000,
-                        pci_speed_string(speed_cap), width_cap);
+                        pci_speed_string(speed_cap), width_cap, flit_mode);
 }
 
 /**
index 01e51db8d285af54673db3ea526ceda073c94ec9..9da7da58e0def42edcb6e6b720a61ec6237fd850 100644 (file)
@@ -406,9 +406,10 @@ const char *pci_speed_string(enum pci_bus_speed speed);
 void __pcie_print_link_status(struct pci_dev *dev, bool verbose);
 void pcie_report_downtraining(struct pci_dev *dev);
 
-static inline void __pcie_update_link_speed(struct pci_bus *bus, u16 linksta)
+static inline void __pcie_update_link_speed(struct pci_bus *bus, u16 linksta, u16 linksta2)
 {
        bus->cur_bus_speed = pcie_link_speed[linksta & PCI_EXP_LNKSTA_CLS];
+       bus->flit_mode = (linksta2 & PCI_EXP_LNKSTA2_FLIT) ? 1 : 0;
 }
 void pcie_update_link_speed(struct pci_bus *bus);
 
index b6536ed599c3727ebfc92697ee8d0906e8167902..e6f11498a3459f9dd243262da643d792a514a242 100644 (file)
@@ -788,10 +788,11 @@ EXPORT_SYMBOL_GPL(pci_speed_string);
 void pcie_update_link_speed(struct pci_bus *bus)
 {
        struct pci_dev *bridge = bus->self;
-       u16 linksta;
+       u16 linksta, linksta2;
 
        pcie_capability_read_word(bridge, PCI_EXP_LNKSTA, &linksta);
-       __pcie_update_link_speed(bus, linksta);
+       pcie_capability_read_word(bridge, PCI_EXP_LNKSTA2, &linksta2);
+       __pcie_update_link_speed(bus, linksta, linksta2);
 }
 EXPORT_SYMBOL_GPL(pcie_update_link_speed);
 
index 47b31ad724fa5bf7abd7c3dc572947551b0f2148..e4bf67bf8172196c364f041e74aef15dded1601d 100644 (file)
@@ -681,6 +681,7 @@ struct pci_bus {
        struct bin_attribute    *legacy_mem;    /* Legacy mem */
        unsigned int            is_added:1;
        unsigned int            unsafe_warn:1;  /* warned about RW1C config write */
+       unsigned int            flit_mode:1;    /* Link in Flit mode */
 };
 
 #define to_pci_bus(n)  container_of(n, struct pci_bus, dev)