]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
PCI: Introduce pcie_is_cxl()
authorTerry Bowman <terry.bowman@amd.com>
Wed, 14 Jan 2026 18:20:24 +0000 (12:20 -0600)
committerDave Jiang <dave.jiang@intel.com>
Thu, 22 Jan 2026 21:55:27 +0000 (14:55 -0700)
CXL is a protocol that runs on top of PCIe electricals. Its error model
also runs on top of the PCIe AER error model by standardizing "internal"
errors as "CXL" errors. Linux has historically ignored internal errors.

CXL protocol error handling is then a task of enhancing the PCIe AER
core to understand that PCIe ports (upstream and downstream) and
endpoints may throw internal errors that represent standard CXL protocol
errors.

The proposed method to make that determination is to teach 'struct
pci_dev' to cache when its link has trained the CXL.mem and/or CXL.cache
protocols and then treat all internal errors as CXL errors. A design
goal is to not burden the PCIe AER core with CXL knowledge beyond just
enough to forward error notifications to the CXL RAS core. The forwarded
notification looks up a 'struct cxl_port' or 'struct cxl_dport'
companion device to the PCI device.

Introduce set_pcie_cxl() with logic checking for CXL.mem or CXL.cache
status in the CXL Flex Bus DVSEC status register. The CXL Flex Bus DVSEC
presence is used because it is required for all the CXL PCIe devices.[1]

[1] CXL 3.1 Spec, 8.1.1 PCIe Designated Vendor-Specific Extended
    Capability (DVSEC) ID Assignment, Table 8-2

Signed-off-by: Terry Bowman <terry.bowman@amd.com>
Reviewed-by: Ira Weiny <ira.weiny@intel.com>
Reviewed-by: Kuppuswamy Sathyanarayanan <sathyanarayanan.kuppuswamy@linux.intel.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Alejandro Lucero <alucerop@amd.com>
Reviewed-by: Ben Cheatham <benjamin.cheatham@amd.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Link: https://patch.msgid.link/20260114182055.46029-4-terry.bowman@amd.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
drivers/pci/probe.c
include/linux/pci.h
include/uapi/linux/pci_regs.h

index 41183aed8f5d94c514e9d1787107999acbba7c4f..bd7ce41d0c7aec0bce2c410fa9d152fa3f224b83 100644 (file)
@@ -1735,6 +1735,35 @@ static void set_pcie_thunderbolt(struct pci_dev *dev)
                dev->is_thunderbolt = 1;
 }
 
+static void set_pcie_cxl(struct pci_dev *dev)
+{
+       struct pci_dev *bridge;
+       u16 dvsec, cap;
+
+       if (!pci_is_pcie(dev))
+               return;
+
+       /*
+        * Update parent's CXL state because alternate protocol training
+        * may have changed
+        */
+       bridge = pci_upstream_bridge(dev);
+       if (bridge)
+               set_pcie_cxl(bridge);
+
+       dvsec = pci_find_dvsec_capability(dev, PCI_VENDOR_ID_CXL,
+                                         PCI_DVSEC_CXL_FLEXBUS_PORT);
+       if (!dvsec)
+               return;
+
+       pci_read_config_word(dev, dvsec + PCI_DVSEC_CXL_FLEXBUS_PORT_STATUS,
+                            &cap);
+
+       dev->is_cxl = FIELD_GET(PCI_DVSEC_CXL_FLEXBUS_PORT_STATUS_CACHE, cap) ||
+               FIELD_GET(PCI_DVSEC_CXL_FLEXBUS_PORT_STATUS_MEM, cap);
+
+}
+
 static void set_pcie_untrusted(struct pci_dev *dev)
 {
        struct pci_dev *parent = pci_upstream_bridge(dev);
@@ -2065,6 +2094,8 @@ int pci_setup_device(struct pci_dev *dev)
        /* Need to have dev->cfg_size ready */
        set_pcie_thunderbolt(dev);
 
+       set_pcie_cxl(dev);
+
        set_pcie_untrusted(dev);
 
        if (pci_is_pcie(dev))
index 864775651c6fae125972cdfb062fd4d684cf294c..f8e8b3df794dd6268f81ca1e2e8d26f67f8cd635 100644 (file)
@@ -463,6 +463,7 @@ struct pci_dev {
        unsigned int    is_pciehp:1;
        unsigned int    shpc_managed:1;         /* SHPC owned by shpchp */
        unsigned int    is_thunderbolt:1;       /* Thunderbolt controller */
+       unsigned int    is_cxl:1;               /* Compute Express Link (CXL) */
        /*
         * Devices marked being untrusted are the ones that can potentially
         * execute DMA attacks and similar. They are typically connected
@@ -791,6 +792,11 @@ static inline bool pci_is_display(struct pci_dev *pdev)
        return (pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY;
 }
 
+static inline bool pcie_is_cxl(struct pci_dev *pci_dev)
+{
+       return pci_dev->is_cxl;
+}
+
 #define for_each_pci_bridge(dev, bus)                          \
        list_for_each_entry(dev, &bus->devices, bus_list)       \
                if (!pci_is_bridge(dev)) {} else
index 662582bdccf0a485cfe8da0859baa30a24030f3f..b6622fd60fd9674132d111676820ebc9a8f0bf40 100644 (file)
 /* CXL r4.0, 8.1.7: GPF DVSEC for CXL Device */
 #define PCI_DVSEC_CXL_DEVICE_GPF                       5
 
+/* CXL r4.0, 8.1.8: Flex Bus DVSEC */
+#define PCI_DVSEC_CXL_FLEXBUS_PORT                     7
+#define  PCI_DVSEC_CXL_FLEXBUS_PORT_STATUS             0xE
+#define   PCI_DVSEC_CXL_FLEXBUS_PORT_STATUS_CACHE      _BITUL(0)
+#define   PCI_DVSEC_CXL_FLEXBUS_PORT_STATUS_MEM                _BITUL(2)
+
 /* CXL r4.0, 8.1.9: Register Locator DVSEC */
 #define PCI_DVSEC_CXL_REG_LOCATOR                      8
 #define  PCI_DVSEC_CXL_REG_LOCATOR_BLOCK1              0xC