Skip to content

Commit d96eb90

Browse files
committed
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>
1 parent 4f06d81 commit d96eb90

9 files changed

Lines changed: 123 additions & 7 deletions

File tree

drivers/cxl/core/core.h

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -146,8 +146,6 @@ int cxl_port_get_switch_dport_bandwidth(struct cxl_port *port,
146146
int cxl_ras_init(void);
147147
void cxl_ras_exit(void);
148148
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);
151149

152150
struct cxl_hdm;
153151
int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm,

drivers/cxl/core/pci.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -41,14 +41,14 @@ static int pci_get_port_num(struct pci_dev *pdev)
4141
}
4242

4343
/**
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
4545
* @port: cxl_port that hosts the dport
4646
* @dport_dev: 'struct device' of the dport
4747
*
4848
* Returns the allocated dport on success or ERR_PTR() of -errno on error
4949
*/
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)
5252
{
5353
struct cxl_register_map map;
5454
struct pci_dev *pdev;
@@ -69,6 +69,7 @@ struct cxl_dport *devm_cxl_add_dport_by_dev(struct cxl_port *port,
6969
device_lock_assert(&port->dev);
7070
return devm_cxl_add_dport(port, dport_dev, port_num, map.resource);
7171
}
72+
EXPORT_SYMBOL_NS_GPL(__devm_cxl_add_dport_by_dev, "CXL");
7273

7374
struct cxl_walk_context {
7475
struct pci_bus *bus;

drivers/cxl/cxl.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -906,6 +906,10 @@ void cxl_coordinates_combine(struct access_coordinate *out,
906906
struct access_coordinate *c2);
907907

908908
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);
909913

910914
/*
911915
* Unit test builds overrides this to __weak, find the 'strong' version
@@ -916,4 +920,20 @@ bool cxl_endpoint_decoder_reset_detected(struct cxl_port *port);
916920
#endif
917921

918922
u16 cxl_gpf_get_dvsec(struct device *dev);
923+
924+
/*
925+
* Declaration for functions that are mocked by cxl_test that are called by
926+
* cxl_core. The respective functions are defined as __foo() and called by
927+
* cxl_core as foo(). The macros below ensures that those functions would
928+
* exist as foo(). See tools/testing/cxl/cxl_core_exports.c and
929+
* tools/testing/cxl/exports.h for setting up the mock functions. The dance
930+
* is done to avoid a circular dependency where cxl_core calls a function that
931+
* ends up being a mock function and goes to * cxl_test where it calls a
932+
* cxl_core function.
933+
*/
934+
#ifndef CXL_TEST_ENABLE
935+
#define DECLARE_TESTABLE(x) __##x
936+
#define devm_cxl_add_dport_by_dev DECLARE_TESTABLE(devm_cxl_add_dport_by_dev)
937+
#endif
938+
919939
#endif /* __CXL_H__ */

tools/testing/cxl/Kbuild

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ CXL_SRC := $(DRIVERS)/cxl
1818
CXL_CORE_SRC := $(DRIVERS)/cxl/core
1919
ccflags-y := -I$(srctree)/drivers/cxl/
2020
ccflags-y += -D__mock=__weak
21+
ccflags-y += -DCXL_TEST_ENABLE=1
2122
ccflags-y += -DTRACE_INCLUDE_PATH=$(CXL_CORE_SRC) -I$(srctree)/drivers/cxl/core/
2223

2324
obj-m += cxl_acpi.o

tools/testing/cxl/cxl_core_exports.c

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,18 @@
22
/* Copyright(c) 2022 Intel Corporation. All rights reserved. */
33

44
#include "cxl.h"
5+
#include "exports.h"
56

67
/* Exporting of cxl_core symbols that are only used by cxl_test */
78
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");

tools/testing/cxl/exports.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
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

tools/testing/cxl/test/cxl.c

Lines changed: 51 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -944,10 +944,12 @@ static int mock_cxl_endpoint_decoders_setup(struct cxl_port *port)
944944
return __mock_cxl_decoders_setup(port);
945945
}
946946

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)
948950
{
949951
struct platform_device **array;
950-
int i, array_size;
952+
int array_size;
951953

952954
if (port->depth == 1) {
953955
if (is_multi_bridge(port->uport_dev)) {
@@ -981,6 +983,22 @@ static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
981983
return -ENXIO;
982984
}
983985

986+
*port_array = array;
987+
*port_array_size = array_size;
988+
989+
return 0;
990+
}
991+
992+
static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
993+
{
994+
struct platform_device **array;
995+
int i, array_size;
996+
int rc;
997+
998+
rc = get_port_array(port, &array, &array_size);
999+
if (rc)
1000+
return rc;
1001+
9841002
for (i = 0; i < array_size; i++) {
9851003
struct platform_device *pdev = array[i];
9861004
struct cxl_dport *dport;
@@ -1002,6 +1020,36 @@ static int mock_cxl_port_enumerate_dports(struct cxl_port *port)
10021020
return 0;
10031021
}
10041022

1023+
static struct cxl_dport *mock_cxl_add_dport_by_dev(struct cxl_port *port,
1024+
struct device *dport_dev)
1025+
{
1026+
struct platform_device **array;
1027+
int rc, i, array_size;
1028+
1029+
rc = get_port_array(port, &array, &array_size);
1030+
if (rc)
1031+
return ERR_PTR(rc);
1032+
1033+
for (i = 0; i < array_size; i++) {
1034+
struct platform_device *pdev = array[i];
1035+
1036+
if (pdev->dev.parent != port->uport_dev) {
1037+
dev_dbg(&port->dev, "%s: mismatch parent %s\n",
1038+
dev_name(port->uport_dev),
1039+
dev_name(pdev->dev.parent));
1040+
continue;
1041+
}
1042+
1043+
if (&pdev->dev != dport_dev)
1044+
continue;
1045+
1046+
return devm_cxl_add_dport(port, &pdev->dev, pdev->id,
1047+
CXL_RESOURCE_NONE);
1048+
}
1049+
1050+
return ERR_PTR(-ENODEV);
1051+
}
1052+
10051053
/*
10061054
* Faking the cxl_dpa_perf for the memdev when appropriate.
10071055
*/
@@ -1062,6 +1110,7 @@ static struct cxl_mock_ops cxl_mock_ops = {
10621110
.devm_cxl_endpoint_decoders_setup = mock_cxl_endpoint_decoders_setup,
10631111
.devm_cxl_port_enumerate_dports = mock_cxl_port_enumerate_dports,
10641112
.cxl_endpoint_parse_cdat = mock_cxl_endpoint_parse_cdat,
1113+
.devm_cxl_add_dport_by_dev = mock_cxl_add_dport_by_dev,
10651114
.list = LIST_HEAD_INIT(cxl_mock_ops.list),
10661115
};
10671116

tools/testing/cxl/test/mock.c

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,19 +10,26 @@
1010
#include <cxlmem.h>
1111
#include <cxlpci.h>
1212
#include "mock.h"
13+
#include "../exports.h"
1314

1415
static LIST_HEAD(mock);
1516

17+
static struct cxl_dport *
18+
redirect_devm_cxl_add_dport_by_dev(struct cxl_port *port,
19+
struct device *dport_dev);
20+
1621
void register_cxl_mock_ops(struct cxl_mock_ops *ops)
1722
{
1823
list_add_rcu(&ops->list, &mock);
24+
_devm_cxl_add_dport_by_dev = redirect_devm_cxl_add_dport_by_dev;
1925
}
2026
EXPORT_SYMBOL_GPL(register_cxl_mock_ops);
2127

2228
DEFINE_STATIC_SRCU(cxl_mock_srcu);
2329

2430
void unregister_cxl_mock_ops(struct cxl_mock_ops *ops)
2531
{
32+
_devm_cxl_add_dport_by_dev = __devm_cxl_add_dport_by_dev;
2633
list_del_rcu(&ops->list);
2734
synchronize_srcu(&cxl_mock_srcu);
2835
}
@@ -258,6 +265,22 @@ void __wrap_cxl_dport_init_ras_reporting(struct cxl_dport *dport, struct device
258265
}
259266
EXPORT_SYMBOL_NS_GPL(__wrap_cxl_dport_init_ras_reporting, "CXL");
260267

268+
struct cxl_dport *redirect_devm_cxl_add_dport_by_dev(struct cxl_port *port,
269+
struct device *dport_dev)
270+
{
271+
int index;
272+
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
273+
struct cxl_dport *dport;
274+
275+
if (ops && ops->is_mock_port(port->uport_dev))
276+
dport = ops->devm_cxl_add_dport_by_dev(port, dport_dev);
277+
else
278+
dport = __devm_cxl_add_dport_by_dev(port, dport_dev);
279+
put_cxl_mock_ops(index);
280+
281+
return dport;
282+
}
283+
261284
MODULE_LICENSE("GPL v2");
262285
MODULE_DESCRIPTION("cxl_test: emulation module");
263286
MODULE_IMPORT_NS("ACPI");

tools/testing/cxl/test/mock.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@ struct cxl_mock_ops {
2323
int (*devm_cxl_switch_port_decoders_setup)(struct cxl_port *port);
2424
int (*devm_cxl_endpoint_decoders_setup)(struct cxl_port *port);
2525
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);
2628
};
2729

2830
void register_cxl_mock_ops(struct cxl_mock_ops *ops);

0 commit comments

Comments
 (0)