Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cxl/test: Add mock version of devm_cxl_add_dport_by_dev()

devm_cxl_add_dport_by_dev() outside of cxl_test is done through PCI
hierarchy. However with cxl_test, it needs to be done through the
platform device hierarchy. Add the mock function for
devm_cxl_add_dport_by_dev().

When cxl_core calls a cxl_core exported function and that function is
mocked by cxl_test, the call chain causes a circular dependency issue. Dan
provided a workaround to avoid this issue. Apply the method to changes from
the late dport allocation changes in order to enable cxl-test.

In cxl_core they are defined with "__" added in front of the function. A
macro is used to define the original function names for when non-test
version of the kernel is built. A bit of macros and typedefs are used to
allow mocking of those functions in cxl_test.

Co-developed-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Jonathan Cameron <jonathan.cameron@huawei.com>
Reviewed-by: Li Ming <ming.li@zohomail.com>
Tested-by: Alison Schofield <alison.schofield@intel.com>
Tested-by: Robert Richter <rrichter@amd.com>
Signed-off-by: Dave Jiang <dave.jiang@intel.com>

+123 -7
-2
drivers/cxl/core/core.h
··· 146 146 int cxl_ras_init(void); 147 147 void cxl_ras_exit(void); 148 148 int cxl_gpf_port_setup(struct cxl_dport *dport); 149 - struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, 150 - struct device *dport_dev); 151 149 152 150 struct cxl_hdm; 153 151 int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,
+4 -3
drivers/cxl/core/pci.c
··· 41 41 } 42 42 43 43 /** 44 - * devm_cxl_add_dport_by_dev - allocate a dport by the dport device 44 + * __devm_cxl_add_dport_by_dev - allocate a dport by dport device 45 45 * @port: cxl_port that hosts the dport 46 46 * @dport_dev: 'struct device' of the dport 47 47 * 48 48 * Returns the allocated dport on success or ERR_PTR() of -errno on error 49 49 */ 50 - struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, 51 - struct device *dport_dev) 50 + struct cxl_dport *__devm_cxl_add_dport_by_dev(struct cxl_port *port, 51 + struct device *dport_dev) 52 52 { 53 53 struct cxl_register_map map; 54 54 struct pci_dev *pdev; ··· 69 69 device_lock_assert(&port->dev); 70 70 return devm_cxl_add_dport(port, dport_dev, port_num, map.resource); 71 71 } 72 + EXPORT_SYMBOL_NS_GPL(__devm_cxl_add_dport_by_dev, "CXL"); 72 73 73 74 struct cxl_walk_context { 74 75 struct pci_bus *bus;
+20
drivers/cxl/cxl.h
··· 906 906 struct access_coordinate *c2); 907 907 908 908 bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port); 909 + struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, 910 + struct device *dport_dev); 911 + struct cxl_dport *__devm_cxl_add_dport_by_dev(struct cxl_port *port, 912 + struct device *dport_dev); 909 913 910 914 /* 911 915 * Unit test builds overrides this to __weak, find the 'strong' version ··· 920 916 #endif 921 917 922 918 u16 cxl_gpf_get_dvsec(struct device *dev); 919 + 920 + /* 921 + * Declaration for functions that are mocked by cxl_test that are called by 922 + * cxl_core. The respective functions are defined as __foo() and called by 923 + * cxl_core as foo(). The macros below ensures that those functions would 924 + * exist as foo(). See tools/testing/cxl/cxl_core_exports.c and 925 + * tools/testing/cxl/exports.h for setting up the mock functions. The dance 926 + * is done to avoid a circular dependency where cxl_core calls a function that 927 + * ends up being a mock function and goes to * cxl_test where it calls a 928 + * cxl_core function. 929 + */ 930 + #ifndef CXL_TEST_ENABLE 931 + #define DECLARE_TESTABLE(x) __##x 932 + #define devm_cxl_add_dport_by_dev DECLARE_TESTABLE(devm_cxl_add_dport_by_dev) 933 + #endif 934 + 923 935 #endif /* __CXL_H__ */
+1
tools/testing/cxl/Kbuild
··· 18 18 CXL_CORE_SRC := $(DRIVERS)/cxl/core 19 19 ccflags-y := -I$(srctree)/drivers/cxl/ 20 20 ccflags-y += -D__mock=__weak 21 + ccflags-y += -DCXL_TEST_ENABLE=1 21 22 ccflags-y += -DTRACE_INCLUDE_PATH=$(CXL_CORE_SRC) -I$(srctree)/drivers/cxl/core/ 22 23 23 24 obj-m += cxl_acpi.o
+12
tools/testing/cxl/cxl_core_exports.c
··· 2 2 /* Copyright(c) 2022 Intel Corporation. All rights reserved. */ 3 3 4 4 #include "cxl.h" 5 + #include "exports.h" 5 6 6 7 /* Exporting of cxl_core symbols that are only used by cxl_test */ 7 8 EXPORT_SYMBOL_NS_GPL(cxl_num_decoders_committed, "CXL"); 9 + 10 + cxl_add_dport_by_dev_fn _devm_cxl_add_dport_by_dev = 11 + __devm_cxl_add_dport_by_dev; 12 + EXPORT_SYMBOL_NS_GPL(_devm_cxl_add_dport_by_dev, "CXL"); 13 + 14 + struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port, 15 + struct device *dport_dev) 16 + { 17 + return _devm_cxl_add_dport_by_dev(port, dport_dev); 18 + } 19 + EXPORT_SYMBOL_NS_GPL(devm_cxl_add_dport_by_dev, "CXL");
+10
tools/testing/cxl/exports.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* Copyright(c) 2025 Intel Corporation */ 3 + #ifndef __MOCK_CXL_EXPORTS_H_ 4 + #define __MOCK_CXL_EXPORTS_H_ 5 + 6 + typedef struct cxl_dport *(*cxl_add_dport_by_dev_fn)(struct cxl_port *port, 7 + struct device *dport_dev); 8 + extern cxl_add_dport_by_dev_fn _devm_cxl_add_dport_by_dev; 9 + 10 + #endif
+51 -2
tools/testing/cxl/test/cxl.c
··· 944 944 return __mock_cxl_decoders_setup(port); 945 945 } 946 946 947 - static int mock_cxl_port_enumerate_dports(struct cxl_port *port) 947 + static int get_port_array(struct cxl_port *port, 948 + struct platform_device ***port_array, 949 + int *port_array_size) 948 950 { 949 951 struct platform_device **array; 950 - int i, array_size; 952 + int array_size; 951 953 952 954 if (port->depth == 1) { 953 955 if (is_multi_bridge(port->uport_dev)) { ··· 983 981 return -ENXIO; 984 982 } 985 983 984 + *port_array = array; 985 + *port_array_size = array_size; 986 + 987 + return 0; 988 + } 989 + 990 + static int mock_cxl_port_enumerate_dports(struct cxl_port *port) 991 + { 992 + struct platform_device **array; 993 + int i, array_size; 994 + int rc; 995 + 996 + rc = get_port_array(port, &array, &array_size); 997 + if (rc) 998 + return rc; 999 + 986 1000 for (i = 0; i < array_size; i++) { 987 1001 struct platform_device *pdev = array[i]; 988 1002 struct cxl_dport *dport; ··· 1018 1000 } 1019 1001 1020 1002 return 0; 1003 + } 1004 + 1005 + static struct cxl_dport *mock_cxl_add_dport_by_dev(struct cxl_port *port, 1006 + struct device *dport_dev) 1007 + { 1008 + struct platform_device **array; 1009 + int rc, i, array_size; 1010 + 1011 + rc = get_port_array(port, &array, &array_size); 1012 + if (rc) 1013 + return ERR_PTR(rc); 1014 + 1015 + for (i = 0; i < array_size; i++) { 1016 + struct platform_device *pdev = array[i]; 1017 + 1018 + if (pdev->dev.parent != port->uport_dev) { 1019 + dev_dbg(&port->dev, "%s: mismatch parent %s\n", 1020 + dev_name(port->uport_dev), 1021 + dev_name(pdev->dev.parent)); 1022 + continue; 1023 + } 1024 + 1025 + if (&pdev->dev != dport_dev) 1026 + continue; 1027 + 1028 + return devm_cxl_add_dport(port, &pdev->dev, pdev->id, 1029 + CXL_RESOURCE_NONE); 1030 + } 1031 + 1032 + return ERR_PTR(-ENODEV); 1021 1033 } 1022 1034 1023 1035 /* ··· 1110 1062 .devm_cxl_endpoint_decoders_setup = mock_cxl_endpoint_decoders_setup, 1111 1063 .devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports, 1112 1064 .cxl_endpoint_parse_cdat = mock_cxl_endpoint_parse_cdat, 1065 + .devm_cxl_add_dport_by_dev = mock_cxl_add_dport_by_dev, 1113 1066 .list = LIST_HEAD_INIT(cxl_mock_ops.list), 1114 1067 }; 1115 1068
+23
tools/testing/cxl/test/mock.c
··· 10 10 #include <cxlmem.h> 11 11 #include <cxlpci.h> 12 12 #include "mock.h" 13 + #include "../exports.h" 13 14 14 15 static LIST_HEAD(mock); 16 + 17 + static struct cxl_dport * 18 + redirect_devm_cxl_add_dport_by_dev(struct cxl_port *port, 19 + struct device *dport_dev); 15 20 16 21 void register_cxl_mock_ops(struct cxl_mock_ops *ops) 17 22 { 18 23 list_add_rcu(&ops->list, &mock); 24 + _devm_cxl_add_dport_by_dev = redirect_devm_cxl_add_dport_by_dev; 19 25 } 20 26 EXPORT_SYMBOL_GPL(register_cxl_mock_ops); 21 27 ··· 29 23 30 24 void unregister_cxl_mock_ops(struct cxl_mock_ops *ops) 31 25 { 26 + _devm_cxl_add_dport_by_dev = __devm_cxl_add_dport_by_dev; 32 27 list_del_rcu(&ops->list); 33 28 synchronize_srcu(&cxl_mock_srcu); 34 29 } ··· 264 257 put_cxl_mock_ops(index); 265 258 } 266 259 EXPORT_SYMBOL_NS_GPL(__wrap_cxl_dport_init_ras_reporting, "CXL"); 260 + 261 + struct cxl_dport *redirect_devm_cxl_add_dport_by_dev(struct cxl_port *port, 262 + struct device *dport_dev) 263 + { 264 + int index; 265 + struct cxl_mock_ops *ops = get_cxl_mock_ops(&index); 266 + struct cxl_dport *dport; 267 + 268 + if (ops && ops->is_mock_port(port->uport_dev)) 269 + dport = ops->devm_cxl_add_dport_by_dev(port, dport_dev); 270 + else 271 + dport = __devm_cxl_add_dport_by_dev(port, dport_dev); 272 + put_cxl_mock_ops(index); 273 + 274 + return dport; 275 + } 267 276 268 277 MODULE_LICENSE("GPL v2"); 269 278 MODULE_DESCRIPTION("cxl_test: emulation module");
+2
tools/testing/cxl/test/mock.h
··· 23 23 int (*devm_cxl_switch_port_decoders_setup)(struct cxl_port *port); 24 24 int (*devm_cxl_endpoint_decoders_setup)(struct cxl_port *port); 25 25 void (*cxl_endpoint_parse_cdat)(struct cxl_port *port); 26 + struct cxl_dport *(*devm_cxl_add_dport_by_dev)(struct cxl_port *port, 27 + struct device *dport_dev); 26 28 }; 27 29 28 30 void register_cxl_mock_ops(struct cxl_mock_ops *ops);