]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cxl/core: Fix caching dport GPF DVSEC issue
authorLi Ming <ming.li@zohomail.com>
Sun, 23 Mar 2025 09:31:08 +0000 (17:31 +0800)
committerDave Jiang <dave.jiang@intel.com>
Wed, 9 Apr 2025 19:48:18 +0000 (12:48 -0700)
Per Table 8-2 in CXL r3.2 section 8.1.1 and CXL r3.2 section 8.1.6, only
CXL Downstream switch ports and CXL root ports have GPF DVSEC for CXL
Port(DVSEC ID 04h).

CXL subsystem has a gpf_dvsec in struct cxl_port which is used to cache
the offset of a GPF DVSEC in PCIe configuration space. It will be
updated during the first EP attaching to the cxl_port, so the gpf_dvsec
can only cache the GPF DVSEC offset of the dport which the first EP is
under. Will not have chance to update it during other EPs attaching.
That means CXL subsystem will use the same GPF DVSEC offset for all
dports under the port, it will be a problem if the GPF DVSEC offset
cached in cxl_port is not the right offset for a dport.

Moving gpf_dvsec from struct cxl_port to struct cxl_dport, make every
cxl dport has their own GPF DVSEC offset caching, and each cxl dport
uses its own GPF DVSEC offset for GPF DVSEC accessing.

Fixes: a52b6a2c1c99 ("cxl/pci: Support Global Persistent Flush (GPF)")
Signed-off-by: Li Ming <ming.li@zohomail.com>
Reviewed-by: Davidlohr Bueso <dave@stgolabs.net>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Tested-by: Davidlohr Bueso <dave@stgolabs.net>
Link: https://patch.msgid.link/20250323093110.233040-2-ming.li@zohomail.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
drivers/cxl/core/core.h
drivers/cxl/core/pci.c
drivers/cxl/core/port.c
drivers/cxl/cxl.h

index 15699299dc11d4c8dd83a5fd5db97b58afd594eb..17b692eb325713bde91fadfc44045f99e3a3c24c 100644 (file)
@@ -119,7 +119,7 @@ int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
 
 int cxl_ras_init(void);
 void cxl_ras_exit(void);
-int cxl_gpf_port_setup(struct device *dport_dev, struct cxl_port *port);
+int cxl_gpf_port_setup(struct cxl_dport *dport);
 int cxl_acpi_get_extended_linear_cache_size(struct resource *backing_res,
                                            int nid, resource_size_t *size);
 
index 96fecb799cbcf7672b49ac6a2dc2983d8914c4b5..aab0a505d527e2a5c9c35e3d0e7e83abcf107f14 100644 (file)
@@ -1128,26 +1128,26 @@ static int update_gpf_port_dvsec(struct pci_dev *pdev, int dvsec, int phase)
        return rc;
 }
 
-int cxl_gpf_port_setup(struct device *dport_dev, struct cxl_port *port)
+int cxl_gpf_port_setup(struct cxl_dport *dport)
 {
        struct pci_dev *pdev;
 
-       if (!port)
+       if (!dport)
                return -EINVAL;
 
-       if (!port->gpf_dvsec) {
+       if (!dport->gpf_dvsec) {
                int dvsec;
 
-               dvsec = cxl_gpf_get_dvsec(dport_dev, true);
+               dvsec = cxl_gpf_get_dvsec(dport->dport_dev, true);
                if (!dvsec)
                        return -EINVAL;
 
-               port->gpf_dvsec = dvsec;
+               dport->gpf_dvsec = dvsec;
        }
 
-       pdev = to_pci_dev(dport_dev);
-       update_gpf_port_dvsec(pdev, port->gpf_dvsec, 1);
-       update_gpf_port_dvsec(pdev, port->gpf_dvsec, 2);
+       pdev = to_pci_dev(dport->dport_dev);
+       update_gpf_port_dvsec(pdev, dport->gpf_dvsec, 1);
+       update_gpf_port_dvsec(pdev, dport->gpf_dvsec, 2);
 
        return 0;
 }
index 0fd6646c1a2e8e570aafb06e75d30969a595dd32..726bd4a7de2703acf1f2823e9714364c1351839a 100644 (file)
@@ -1678,7 +1678,7 @@ retry:
                        if (rc && rc != -EBUSY)
                                return rc;
 
-                       cxl_gpf_port_setup(dport_dev, port);
+                       cxl_gpf_port_setup(dport);
 
                        /* Any more ports to add between this one and the root? */
                        if (!dev_is_cxl_root_child(&port->dev))
index be8a7dc77719bdfb81aa02904e14cc04e507bd65..2d81ccd83916d674340b75c1a854d630a1aa5afa 100644 (file)
@@ -592,7 +592,6 @@ struct cxl_dax_region {
  * @cdat: Cached CDAT data
  * @cdat_available: Should a CDAT attribute be available in sysfs
  * @pci_latency: Upstream latency in picoseconds
- * @gpf_dvsec: Cached GPF port DVSEC
  */
 struct cxl_port {
        struct device dev;
@@ -616,7 +615,6 @@ struct cxl_port {
        } cdat;
        bool cdat_available;
        long pci_latency;
-       int gpf_dvsec;
 };
 
 /**
@@ -664,6 +662,7 @@ struct cxl_rcrb_info {
  * @regs: Dport parsed register blocks
  * @coord: access coordinates (bandwidth and latency performance attributes)
  * @link_latency: calculated PCIe downstream latency
+ * @gpf_dvsec: Cached GPF port DVSEC
  */
 struct cxl_dport {
        struct device *dport_dev;
@@ -675,6 +674,7 @@ struct cxl_dport {
        struct cxl_regs regs;
        struct access_coordinate coord[ACCESS_COORDINATE_MAX];
        long link_latency;
+       int gpf_dvsec;
 };
 
 /**