]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
cxl/test: Refactor decoder setup to reduce cxl_test burden
authorDave Jiang <dave.jiang@intel.com>
Fri, 29 Aug 2025 18:09:23 +0000 (11:09 -0700)
committerDave Jiang <dave.jiang@intel.com>
Thu, 18 Sep 2025 16:54:50 +0000 (09:54 -0700)
Group the decoder setup code in switch and endpoint port probe into a
single function for each to reduce the number of functions to be mocked
in cxl_test. Introduce devm_cxl_switch_port_decoders_setup() and
devm_cxl_endpoint_decoders_setup(). These two functions will be mocked
instead with some functions optimized out since the mock version does
not do anything. Remove devm_cxl_setup_hdm(),
devm_cxl_add_passthrough_decoder(), and devm_cxl_enumerate_decoders() in
cxl_test mock code. In turn, mock_cxl_add_passthrough_decoder() can be
removed since cxl_test does not setup passthrough decoders.
__wrap_cxl_hdm_decode_init() and __wrap_cxl_dvsec_rr_decode() can be
removed as well since they only return 0 when called.

[dj: drop 'struct cxl_port' forward declaration (Robert)]

Suggested-by: Robert Richter <rrichter@amd.com>
Reviewed-by: Alison Schofield <alison.schofield@intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Robert Richter <rrichter@amd.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
drivers/cxl/core/core.h
drivers/cxl/core/hdm.c
drivers/cxl/core/pci.c
drivers/cxl/cxl.h
drivers/cxl/cxlpci.h
drivers/cxl/port.c
tools/testing/cxl/Kbuild
tools/testing/cxl/test/cxl.c
tools/testing/cxl/test/mock.c
tools/testing/cxl/test/mock.h

index 2669f251d677566c9d69484e4e9cb53226056380..b07490aa93c7c063d7baab3307b634125a3639f7 100644 (file)
@@ -147,6 +147,11 @@ int cxl_ras_init(void);
 void cxl_ras_exit(void);
 int cxl_gpf_port_setup(struct cxl_dport *dport);
 
+struct cxl_hdm;
+int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
+                       struct cxl_endpoint_dvsec_info *info);
+int cxl_port_get_possible_dports(struct cxl_port *port);
+
 #ifdef CONFIG_CXL_FEATURES
 struct cxl_feat_entry *
 cxl_feature_info(struct cxl_features_state *cxlfs, const uuid_t *uuid);
index cee68bbc7ff6f548eebcfb1708174ab1f3edf909..78bfe4f55b96532519b8cb183697f30dca965d22 100644 (file)
@@ -49,7 +49,7 @@ static int add_hdm_decoder(struct cxl_port *port, struct cxl_decoder *cxld)
  * are claimed and passed to the single dport. Disable the range until the first
  * CXL region is enumerated / activated.
  */
-int devm_cxl_add_passthrough_decoder(struct cxl_port *port)
+static int devm_cxl_add_passthrough_decoder(struct cxl_port *port)
 {
        struct cxl_switch_decoder *cxlsd;
        struct cxl_dport *dport = NULL;
@@ -75,7 +75,6 @@ int devm_cxl_add_passthrough_decoder(struct cxl_port *port)
 
        return add_hdm_decoder(port, &cxlsd->cxld);
 }
-EXPORT_SYMBOL_NS_GPL(devm_cxl_add_passthrough_decoder, "CXL");
 
 static void parse_hdm_decoder_caps(struct cxl_hdm *cxlhdm)
 {
@@ -145,8 +144,8 @@ static bool should_emulate_decoders(struct cxl_endpoint_dvsec_info *info)
  * @port: cxl_port to map
  * @info: cached DVSEC range register info
  */
-struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
-                                  struct cxl_endpoint_dvsec_info *info)
+static struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
+                                         struct cxl_endpoint_dvsec_info *info)
 {
        struct cxl_register_map *reg_map = &port->reg_map;
        struct device *dev = &port->dev;
@@ -201,7 +200,6 @@ struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
 
        return cxlhdm;
 }
-EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_hdm, "CXL");
 
 static void __cxl_dpa_debug(struct seq_file *file, struct resource *r, int depth)
 {
@@ -1166,8 +1164,8 @@ static void cxl_settle_decoders(struct cxl_hdm *cxlhdm)
  * @cxlhdm: Structure to populate with HDM capabilities
  * @info: cached DVSEC range register info
  */
-int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
-                               struct cxl_endpoint_dvsec_info *info)
+static int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
+                                      struct cxl_endpoint_dvsec_info *info)
 {
        void __iomem *hdm = cxlhdm->regs.hdm_decoder;
        struct cxl_port *port = cxlhdm->port;
@@ -1222,4 +1220,71 @@ int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
 
        return 0;
 }
-EXPORT_SYMBOL_NS_GPL(devm_cxl_enumerate_decoders, "CXL");
+
+/**
+ * devm_cxl_switch_port_decoders_setup - allocate and setup switch decoders
+ * @port: CXL port context
+ *
+ * Return 0 or -errno on error
+ */
+int devm_cxl_switch_port_decoders_setup(struct cxl_port *port)
+{
+       struct cxl_hdm *cxlhdm;
+
+       if (is_cxl_root(port) || is_cxl_endpoint(port))
+               return -EOPNOTSUPP;
+
+       cxlhdm = devm_cxl_setup_hdm(port, NULL);
+       if (!IS_ERR(cxlhdm))
+               return devm_cxl_enumerate_decoders(cxlhdm, NULL);
+
+       if (PTR_ERR(cxlhdm) != -ENODEV) {
+               dev_err(&port->dev, "Failed to map HDM decoder capability\n");
+               return PTR_ERR(cxlhdm);
+       }
+
+       if (cxl_port_get_possible_dports(port) == 1) {
+               dev_dbg(&port->dev, "Fallback to passthrough decoder\n");
+               return devm_cxl_add_passthrough_decoder(port);
+       }
+
+       dev_err(&port->dev, "HDM decoder capability not found\n");
+       return -ENXIO;
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_switch_port_decoders_setup, "CXL");
+
+/**
+ * devm_cxl_endpoint_decoders_setup - allocate and setup endpoint decoders
+ * @port: CXL port context
+ *
+ * Return 0 or -errno on error
+ */
+int devm_cxl_endpoint_decoders_setup(struct cxl_port *port)
+{
+       struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
+       struct cxl_endpoint_dvsec_info info = { .port = port };
+       struct cxl_dev_state *cxlds = cxlmd->cxlds;
+       struct cxl_hdm *cxlhdm;
+       int rc;
+
+       if (!is_cxl_endpoint(port))
+               return -EOPNOTSUPP;
+
+       rc = cxl_dvsec_rr_decode(cxlds, &info);
+       if (rc < 0)
+               return rc;
+
+       cxlhdm = devm_cxl_setup_hdm(port, &info);
+       if (IS_ERR(cxlhdm)) {
+               if (PTR_ERR(cxlhdm) == -ENODEV)
+                       dev_err(&port->dev, "HDM decoder registers not found\n");
+               return PTR_ERR(cxlhdm);
+       }
+
+       rc = cxl_hdm_decode_init(cxlds, cxlhdm, &info);
+       if (rc)
+               return rc;
+
+       return devm_cxl_enumerate_decoders(cxlhdm, &info);
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_endpoint_decoders_setup, "CXL");
index b50551601c2e46c2a60b281263e03c4a0cf0bfb8..fa02366d35f2d822198faee5ae479765bf7088fd 100644 (file)
@@ -1169,3 +1169,45 @@ int cxl_gpf_port_setup(struct cxl_dport *dport)
 
        return 0;
 }
+
+static int count_dports(struct pci_dev *pdev, void *data)
+{
+       struct cxl_walk_context *ctx = data;
+       int type = pci_pcie_type(pdev);
+
+       if (pdev->bus != ctx->bus)
+               return 0;
+       if (!pci_is_pcie(pdev))
+               return 0;
+       if (type != ctx->type)
+               return 0;
+
+       ctx->count++;
+       return 0;
+}
+
+int cxl_port_get_possible_dports(struct cxl_port *port)
+{
+       struct pci_bus *bus = cxl_port_to_pci_bus(port);
+       struct cxl_walk_context ctx;
+       int type;
+
+       if (!bus) {
+               dev_err(&port->dev, "No PCI bus found for port %s\n",
+                       dev_name(&port->dev));
+               return -ENXIO;
+       }
+
+       if (pci_is_root_bus(bus))
+               type = PCI_EXP_TYPE_ROOT_PORT;
+       else
+               type = PCI_EXP_TYPE_DOWNSTREAM;
+
+       ctx = (struct cxl_walk_context) {
+               .bus = bus,
+               .type = type,
+       };
+       pci_walk_bus(bus, count_dports, &ctx);
+
+       return ctx.count;
+}
index 4b858f3d44c62acee66010e6cc2b47b801da84ea..672f43b7a87fc75bf39abf9be6e8559ed6744fde 100644 (file)
@@ -810,12 +810,9 @@ struct cxl_endpoint_dvsec_info {
        struct range dvsec_range[2];
 };
 
-struct cxl_hdm;
-struct cxl_hdm *devm_cxl_setup_hdm(struct cxl_port *port,
-                                  struct cxl_endpoint_dvsec_info *info);
-int devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
-                               struct cxl_endpoint_dvsec_info *info);
-int devm_cxl_add_passthrough_decoder(struct cxl_port *port);
+int devm_cxl_switch_port_decoders_setup(struct cxl_port *port);
+int devm_cxl_endpoint_decoders_setup(struct cxl_port *port);
+
 struct cxl_dev_state;
 int cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
                        struct cxl_endpoint_dvsec_info *info);
index 54e219b0049eaa626f073feb2f368fa639272e9f..7ae621e618e79a2e345a28ae7328bceed2c2045a 100644 (file)
@@ -129,8 +129,6 @@ static inline bool cxl_pci_flit_256(struct pci_dev *pdev)
 
 int devm_cxl_port_enumerate_dports(struct cxl_port *port);
 struct cxl_dev_state;
-int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
-                       struct cxl_endpoint_dvsec_info *info);
 void read_cdat_data(struct cxl_port *port);
 void cxl_cor_error_detected(struct pci_dev *pdev);
 pci_ers_result_t cxl_error_detected(struct pci_dev *pdev,
index cf32dc50b7a61c3a9dd3f6a8f1bff80d26454f0d..d8cae2b5bac6c8adc249c8bda053a3000ef82cbb 100644 (file)
@@ -59,7 +59,6 @@ static int discover_region(struct device *dev, void *unused)
 
 static int cxl_switch_port_probe(struct cxl_port *port)
 {
-       struct cxl_hdm *cxlhdm;
        int rc;
 
        /* Cache the data early to ensure is_visible() works */
@@ -71,43 +70,14 @@ static int cxl_switch_port_probe(struct cxl_port *port)
 
        cxl_switch_parse_cdat(port);
 
-       cxlhdm = devm_cxl_setup_hdm(port, NULL);
-       if (!IS_ERR(cxlhdm))
-               return devm_cxl_enumerate_decoders(cxlhdm, NULL);
-
-       if (PTR_ERR(cxlhdm) != -ENODEV) {
-               dev_err(&port->dev, "Failed to map HDM decoder capability\n");
-               return PTR_ERR(cxlhdm);
-       }
-
-       if (rc == 1) {
-               dev_dbg(&port->dev, "Fallback to passthrough decoder\n");
-               return devm_cxl_add_passthrough_decoder(port);
-       }
-
-       dev_err(&port->dev, "HDM decoder capability not found\n");
-       return -ENXIO;
+       return devm_cxl_switch_port_decoders_setup(port);
 }
 
 static int cxl_endpoint_port_probe(struct cxl_port *port)
 {
-       struct cxl_endpoint_dvsec_info info = { .port = port };
        struct cxl_memdev *cxlmd = to_cxl_memdev(port->uport_dev);
-       struct cxl_dev_state *cxlds = cxlmd->cxlds;
-       struct cxl_hdm *cxlhdm;
        int rc;
 
-       rc = cxl_dvsec_rr_decode(cxlds, &info);
-       if (rc < 0)
-               return rc;
-
-       cxlhdm = devm_cxl_setup_hdm(port, &info);
-       if (IS_ERR(cxlhdm)) {
-               if (PTR_ERR(cxlhdm) == -ENODEV)
-                       dev_err(&port->dev, "HDM decoder registers not found\n");
-               return PTR_ERR(cxlhdm);
-       }
-
        /* Cache the data early to ensure is_visible() works */
        read_cdat_data(port);
        cxl_endpoint_parse_cdat(port);
@@ -117,11 +87,7 @@ static int cxl_endpoint_port_probe(struct cxl_port *port)
        if (rc)
                return rc;
 
-       rc = cxl_hdm_decode_init(cxlds, cxlhdm, &info);
-       if (rc)
-               return rc;
-
-       rc = devm_cxl_enumerate_decoders(cxlhdm, &info);
+       rc = devm_cxl_endpoint_decoders_setup(port);
        if (rc)
                return rc;
 
index d07f14cb7aa4537ecab1ae38129a904560b69aa6..51b8ab289eae95369cbf0df3df18b97c9d9ea582 100644 (file)
@@ -5,16 +5,13 @@ ldflags-y += --wrap=acpi_evaluate_integer
 ldflags-y += --wrap=acpi_pci_find_root
 ldflags-y += --wrap=nvdimm_bus_register
 ldflags-y += --wrap=devm_cxl_port_enumerate_dports
-ldflags-y += --wrap=devm_cxl_setup_hdm
-ldflags-y += --wrap=devm_cxl_add_passthrough_decoder
-ldflags-y += --wrap=devm_cxl_enumerate_decoders
 ldflags-y += --wrap=cxl_await_media_ready
-ldflags-y += --wrap=cxl_hdm_decode_init
-ldflags-y += --wrap=cxl_dvsec_rr_decode
 ldflags-y += --wrap=devm_cxl_add_rch_dport
 ldflags-y += --wrap=cxl_rcd_component_reg_phys
 ldflags-y += --wrap=cxl_endpoint_parse_cdat
 ldflags-y += --wrap=cxl_dport_init_ras_reporting
+ldflags-y += --wrap=devm_cxl_switch_port_decoders_setup
+ldflags-y += --wrap=devm_cxl_endpoint_decoders_setup
 
 DRIVERS := ../../../drivers
 CXL_SRC := $(DRIVERS)/cxl
index 8faf4143d04ef036ed10a61b2f945eabbcc3b2e0..8b5c559a4a8c9c77f98736c302375e25ec647979 100644 (file)
@@ -643,13 +643,6 @@ static struct cxl_hdm *mock_cxl_setup_hdm(struct cxl_port *port,
        return cxlhdm;
 }
 
-static int mock_cxl_add_passthrough_decoder(struct cxl_port *port)
-{
-       dev_err(&port->dev, "unexpected passthrough decoder for cxl_test\n");
-       return -EOPNOTSUPP;
-}
-
-
 struct target_map_ctx {
        u32 *target_map;
        int index;
@@ -921,6 +914,36 @@ static int mock_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
        return 0;
 }
 
+static int __mock_cxl_decoders_setup(struct cxl_port *port)
+{
+       struct cxl_hdm *cxlhdm;
+
+       cxlhdm = mock_cxl_setup_hdm(port, NULL);
+       if (IS_ERR(cxlhdm)) {
+               if (PTR_ERR(cxlhdm) != -ENODEV)
+                       dev_err(&port->dev, "Failed to map HDM decoder capability\n");
+               return PTR_ERR(cxlhdm);
+       }
+
+       return mock_cxl_enumerate_decoders(cxlhdm, NULL);
+}
+
+static int mock_cxl_switch_port_decoders_setup(struct cxl_port *port)
+{
+       if (is_cxl_root(port) || is_cxl_endpoint(port))
+               return -EOPNOTSUPP;
+
+       return __mock_cxl_decoders_setup(port);
+}
+
+static int mock_cxl_endpoint_decoders_setup(struct cxl_port *port)
+{
+       if (!is_cxl_endpoint(port))
+               return -EOPNOTSUPP;
+
+       return __mock_cxl_decoders_setup(port);
+}
+
 static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
 {
        struct platform_device **array;
@@ -1035,10 +1058,9 @@ static struct cxl_mock_ops cxl_mock_ops = {
        .acpi_table_parse_cedt = mock_acpi_table_parse_cedt,
        .acpi_evaluate_integer = mock_acpi_evaluate_integer,
        .acpi_pci_find_root = mock_acpi_pci_find_root,
+       .devm_cxl_switch_port_decoders_setup = mock_cxl_switch_port_decoders_setup,
+       .devm_cxl_endpoint_decoders_setup = mock_cxl_endpoint_decoders_setup,
        .devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports,
-       .devm_cxl_setup_hdm = mock_cxl_setup_hdm,
-       .devm_cxl_add_passthrough_decoder = mock_cxl_add_passthrough_decoder,
-       .devm_cxl_enumerate_decoders = mock_cxl_enumerate_decoders,
        .cxl_endpoint_parse_cdat = mock_cxl_endpoint_parse_cdat,
        .list = LIST_HEAD_INIT(cxl_mock_ops.list),
 };
index 1989ae020df3d9e721927937479b64c524290839..f335889b7756ae4dfadc945848a466bd15e62fa1 100644 (file)
@@ -131,55 +131,35 @@ __wrap_nvdimm_bus_register(struct device *dev,
 }
 EXPORT_SYMBOL_GPL(__wrap_nvdimm_bus_register);
 
-struct cxl_hdm *__wrap_devm_cxl_setup_hdm(struct cxl_port *port,
-                                         struct cxl_endpoint_dvsec_info *info)
-
-{
-       int index;
-       struct cxl_hdm *cxlhdm;
-       struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
-
-       if (ops && ops->is_mock_port(port->uport_dev))
-               cxlhdm = ops->devm_cxl_setup_hdm(port, info);
-       else
-               cxlhdm = devm_cxl_setup_hdm(port, info);
-       put_cxl_mock_ops(index);
-
-       return cxlhdm;
-}
-EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_setup_hdm, "CXL");
-
-int __wrap_devm_cxl_add_passthrough_decoder(struct cxl_port *port)
+int __wrap_devm_cxl_switch_port_decoders_setup(struct cxl_port *port)
 {
        int rc, index;
        struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
 
        if (ops && ops->is_mock_port(port->uport_dev))
-               rc = ops->devm_cxl_add_passthrough_decoder(port);
+               rc = ops->devm_cxl_switch_port_decoders_setup(port);
        else
-               rc = devm_cxl_add_passthrough_decoder(port);
+               rc = devm_cxl_switch_port_decoders_setup(port);
        put_cxl_mock_ops(index);
 
        return rc;
 }
-EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_passthrough_decoder, "CXL");
+EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_switch_port_decoders_setup, "CXL");
 
-int __wrap_devm_cxl_enumerate_decoders(struct cxl_hdm *cxlhdm,
-                                      struct cxl_endpoint_dvsec_info *info)
+int __wrap_devm_cxl_endpoint_decoders_setup(struct cxl_port *port)
 {
        int rc, index;
-       struct cxl_port *port = cxlhdm->port;
        struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
 
        if (ops && ops->is_mock_port(port->uport_dev))
-               rc = ops->devm_cxl_enumerate_decoders(cxlhdm, info);
+               rc = ops->devm_cxl_endpoint_decoders_setup(port);
        else
-               rc = devm_cxl_enumerate_decoders(cxlhdm, info);
+               rc = devm_cxl_endpoint_decoders_setup(port);
        put_cxl_mock_ops(index);
 
        return rc;
 }
-EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_enumerate_decoders, "CXL");
+EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_endpoint_decoders_setup, "CXL");
 
 int __wrap_devm_cxl_port_enumerate_dports(struct cxl_port *port)
 {
@@ -211,39 +191,6 @@ int __wrap_cxl_await_media_ready(struct cxl_dev_state *cxlds)
 }
 EXPORT_SYMBOL_NS_GPL(__wrap_cxl_await_media_ready, "CXL");
 
-int __wrap_cxl_hdm_decode_init(struct cxl_dev_state *cxlds,
-                              struct cxl_hdm *cxlhdm,
-                              struct cxl_endpoint_dvsec_info *info)
-{
-       int rc = 0, index;
-       struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
-
-       if (ops && ops->is_mock_dev(cxlds->dev))
-               rc = 0;
-       else
-               rc = cxl_hdm_decode_init(cxlds, cxlhdm, info);
-       put_cxl_mock_ops(index);
-
-       return rc;
-}
-EXPORT_SYMBOL_NS_GPL(__wrap_cxl_hdm_decode_init, "CXL");
-
-int __wrap_cxl_dvsec_rr_decode(struct cxl_dev_state *cxlds,
-                              struct cxl_endpoint_dvsec_info *info)
-{
-       int rc = 0, index;
-       struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
-
-       if (ops && ops->is_mock_dev(cxlds->dev))
-               rc = 0;
-       else
-               rc = cxl_dvsec_rr_decode(cxlds, info);
-       put_cxl_mock_ops(index);
-
-       return rc;
-}
-EXPORT_SYMBOL_NS_GPL(__wrap_cxl_dvsec_rr_decode, "CXL");
-
 struct cxl_dport *__wrap_devm_cxl_add_rch_dport(struct cxl_port *port,
                                                struct device *dport_dev,
                                                int port_id,
index d1b0271d282203b7bccac68aedef0646d1391d59..9d5ad3fd55ecc696d8fca3a03c7fdec7908e9218 100644 (file)
@@ -20,11 +20,8 @@ struct cxl_mock_ops {
        bool (*is_mock_port)(struct device *dev);
        bool (*is_mock_dev)(struct device *dev);
        int (*devm_cxl_port_enumerate_dports)(struct cxl_port *port);
-       struct cxl_hdm *(*devm_cxl_setup_hdm)(
-               struct cxl_port *port, struct cxl_endpoint_dvsec_info *info);
-       int (*devm_cxl_add_passthrough_decoder)(struct cxl_port *port);
-       int (*devm_cxl_enumerate_decoders)(
-               struct cxl_hdm *hdm, struct cxl_endpoint_dvsec_info *info);
+       int (*devm_cxl_switch_port_decoders_setup)(struct cxl_port *port);
+       int (*devm_cxl_endpoint_decoders_setup)(struct cxl_port *port);
        void (*cxl_endpoint_parse_cdat)(struct cxl_port *port);
 };