Skip to content

Commit 549b5c1

Browse files
djbwdavejiang
authored andcommitted
tools/testing/cxl: Test dax_hmem takeover of CXL regions
When platform firmware is committed to publishing EFI_CONVENTIONAL_MEMORY in the memory map, but CXL fails to assemble the region, dax_hmem can attempt to attach a dax device to the memory range. Take advantage of the new ability to support multiple "hmem_platform" devices, and to enable regression testing of several scenarios: * CXL correctly assembles a region, check dax_hmem fails to attach dax * CXL fails to assemble a region, check dax_hmem successfully attaches dax * Check that loading the dax_cxl driver loads the dax_hmem driver * Attempt to race cxl_mock_mem async probe vs dax_hmem probe flushing. Check that both positive and negative cases. Signed-off-by: Dan Williams <dan.j.williams@intel.com> Reviewed-by: Ira Weiny <ira.weiny@intel.com> Reviewed-by: Dave Jiang <dave.jiang@intel.com> Reviewed-by: Alison Schofield <alison.schofield@intel.com> Tested-by: Alison Schofield <alison.schofield@intel.com> Link: https://patch.msgid.link/20260327052821.440749-10-dan.j.williams@intel.com Signed-off-by: Dave Jiang <dave.jiang@intel.com>
1 parent 78b8f1a commit 549b5c1

7 files changed

Lines changed: 173 additions & 0 deletions

File tree

tools/testing/cxl/Kbuild

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,12 @@ ldflags-y += --wrap=devm_cxl_endpoint_decoders_setup
1111
ldflags-y += --wrap=hmat_get_extended_linear_cache_size
1212
ldflags-y += --wrap=devm_cxl_add_dport_by_dev
1313
ldflags-y += --wrap=devm_cxl_switch_port_decoders_setup
14+
ldflags-y += --wrap=walk_hmem_resources
15+
ldflags-y += --wrap=region_intersects
16+
ldflags-y += --wrap=region_intersects_soft_reserve
1417

1518
DRIVERS := ../../../drivers
19+
DAX_HMEM_SRC := $(DRIVERS)/dax/hmem
1620
CXL_SRC := $(DRIVERS)/cxl
1721
CXL_CORE_SRC := $(DRIVERS)/cxl/core
1822
ccflags-y := -I$(srctree)/drivers/cxl/
@@ -70,6 +74,9 @@ cxl_core-y += config_check.o
7074
cxl_core-y += cxl_core_test.o
7175
cxl_core-y += cxl_core_exports.o
7276

77+
obj-m += dax_hmem.o
78+
dax_hmem-y := $(DAX_HMEM_SRC)/hmem.o
79+
7380
KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS))
7481

7582
obj-m += test/

tools/testing/cxl/test/Kbuild

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ obj-m += cxl_mock_mem.o
77
obj-m += cxl_translate.o
88

99
cxl_test-y := cxl.o
10+
cxl_test-y += hmem_test.o
1011
cxl_mock-y := mock.o
1112
cxl_mock_mem-y := mem.o
1213

tools/testing/cxl/test/cxl.c

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1121,6 +1121,53 @@ static void mock_cxl_endpoint_parse_cdat(struct cxl_port *port)
11211121
cxl_endpoint_get_perf_coordinates(port, ep_c);
11221122
}
11231123

1124+
/*
1125+
* Simulate that the first half of mock CXL Window 0 is "Soft Reserve" capacity
1126+
*/
1127+
static int mock_walk_hmem_resources(struct device *host, walk_hmem_fn fn)
1128+
{
1129+
struct acpi_cedt_cfmws *cfmws = mock_cfmws[0];
1130+
struct resource window =
1131+
DEFINE_RES_MEM(cfmws->base_hpa, cfmws->window_size / 2);
1132+
1133+
dev_dbg(host, "walk cxl_test resource: %pr\n", &window);
1134+
return fn(host, 0, &window);
1135+
}
1136+
1137+
/*
1138+
* This should only be called by the dax_hmem case, treat mismatches (negative
1139+
* result) as "fallback to base region_intersects()". Simulate that the first
1140+
* half of mock CXL Window 0 is IORES_DESC_CXL capacity.
1141+
*/
1142+
static int mock_region_intersects(resource_size_t start, size_t size,
1143+
unsigned long flags, unsigned long desc)
1144+
{
1145+
struct resource res = DEFINE_RES_MEM(start, size);
1146+
struct acpi_cedt_cfmws *cfmws = mock_cfmws[0];
1147+
struct resource window =
1148+
DEFINE_RES_MEM(cfmws->base_hpa, cfmws->window_size / 2);
1149+
1150+
if (resource_overlaps(&res, &window))
1151+
return REGION_INTERSECTS;
1152+
pr_debug("warning: no cxl_test CXL intersection for %pr\n", &res);
1153+
return -1;
1154+
}
1155+
1156+
1157+
static int
1158+
mock_region_intersects_soft_reserve(resource_size_t start, size_t size)
1159+
{
1160+
struct resource res = DEFINE_RES_MEM(start, size);
1161+
struct acpi_cedt_cfmws *cfmws = mock_cfmws[0];
1162+
struct resource window =
1163+
DEFINE_RES_MEM(cfmws->base_hpa, cfmws->window_size / 2);
1164+
1165+
if (resource_overlaps(&res, &window))
1166+
return REGION_INTERSECTS;
1167+
pr_debug("warning: no cxl_test soft reserve intersection for %pr\n", &res);
1168+
return -1;
1169+
}
1170+
11241171
static struct cxl_mock_ops cxl_mock_ops = {
11251172
.is_mock_adev = is_mock_adev,
11261173
.is_mock_bridge = is_mock_bridge,
@@ -1136,6 +1183,9 @@ static struct cxl_mock_ops cxl_mock_ops = {
11361183
.devm_cxl_add_dport_by_dev = mock_cxl_add_dport_by_dev,
11371184
.hmat_get_extended_linear_cache_size =
11381185
mock_hmat_get_extended_linear_cache_size,
1186+
.walk_hmem_resources = mock_walk_hmem_resources,
1187+
.region_intersects = mock_region_intersects,
1188+
.region_intersects_soft_reserve = mock_region_intersects_soft_reserve,
11391189
.list = LIST_HEAD_INIT(cxl_mock_ops.list),
11401190
};
11411191

@@ -1561,8 +1611,14 @@ static __init int cxl_test_init(void)
15611611
if (rc)
15621612
goto err_root;
15631613

1614+
rc = hmem_test_init();
1615+
if (rc)
1616+
goto err_mem;
1617+
15641618
return 0;
15651619

1620+
err_mem:
1621+
cxl_mem_exit();
15661622
err_root:
15671623
platform_device_put(cxl_acpi);
15681624
err_rch:
@@ -1600,6 +1656,7 @@ static __exit void cxl_test_exit(void)
16001656
{
16011657
int i;
16021658

1659+
hmem_test_exit();
16031660
cxl_mem_exit();
16041661
platform_device_unregister(cxl_acpi);
16051662
cxl_rch_topo_exit();

tools/testing/cxl/test/hmem_test.c

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// SPDX-License-Identifier: GPL-2.0
2+
/* Copyright (C) 2026 Intel Corporation */
3+
#include <linux/moduleparam.h>
4+
#include <linux/workqueue.h>
5+
#include "../../../drivers/dax/bus.h"
6+
7+
static bool hmem_test;
8+
9+
static void hmem_test_work(struct work_struct *work)
10+
{
11+
}
12+
13+
static void hmem_test_release(struct device *dev)
14+
{
15+
struct hmem_platform_device *hpdev =
16+
container_of(dev, typeof(*hpdev), pdev.dev);
17+
18+
memset(hpdev, 0, sizeof(*hpdev));
19+
}
20+
21+
static struct hmem_platform_device hmem_test_device = {
22+
.pdev = {
23+
.name = "hmem_platform",
24+
.id = 1,
25+
.dev = {
26+
.release = hmem_test_release,
27+
},
28+
},
29+
.work = __WORK_INITIALIZER(hmem_test_device.work, hmem_test_work),
30+
};
31+
32+
int hmem_test_init(void)
33+
{
34+
if (!hmem_test)
35+
return 0;
36+
37+
return platform_device_register(&hmem_test_device.pdev);
38+
}
39+
40+
void hmem_test_exit(void)
41+
{
42+
if (hmem_test)
43+
platform_device_unregister(&hmem_test_device.pdev);
44+
}
45+
46+
module_param(hmem_test, bool, 0444);
47+
MODULE_PARM_DESC(hmem_test, "Enable/disable the dax_hmem test platform device");

tools/testing/cxl/test/mem.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1695,6 +1695,9 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
16951695
struct cxl_dpa_info range_info = { 0 };
16961696
int rc;
16971697

1698+
/* Increase async probe race window */
1699+
usleep_range(500*1000, 1000*1000);
1700+
16981701
mdata = devm_kzalloc(dev, sizeof(*mdata), GFP_KERNEL);
16991702
if (!mdata)
17001703
return -ENOMEM;

tools/testing/cxl/test/mock.c

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,56 @@ struct cxl_dport *__wrap_devm_cxl_add_dport_by_dev(struct cxl_port *port,
251251
}
252252
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_dport_by_dev, "CXL");
253253

254+
int __wrap_region_intersects(resource_size_t start, size_t size,
255+
unsigned long flags, unsigned long desc)
256+
{
257+
int rc = -1;
258+
int index;
259+
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
260+
261+
if (ops)
262+
rc = ops->region_intersects(start, size, flags, desc);
263+
if (rc < 0)
264+
rc = region_intersects(start, size, flags, desc);
265+
put_cxl_mock_ops(index);
266+
267+
return rc;
268+
}
269+
EXPORT_SYMBOL_GPL(__wrap_region_intersects);
270+
271+
int __wrap_region_intersects_soft_reserve(resource_size_t start, size_t size)
272+
{
273+
int rc = -1;
274+
int index;
275+
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
276+
277+
if (ops)
278+
rc = ops->region_intersects_soft_reserve(start, size);
279+
if (rc < 0)
280+
rc = region_intersects_soft_reserve(start, size);
281+
put_cxl_mock_ops(index);
282+
283+
return rc;
284+
}
285+
EXPORT_SYMBOL_GPL(__wrap_region_intersects_soft_reserve);
286+
287+
int __wrap_walk_hmem_resources(struct device *host, walk_hmem_fn fn)
288+
{
289+
int index, rc = 0;
290+
bool is_mock = strcmp(dev_name(host), "hmem_platform.1") == 0;
291+
struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
292+
293+
if (is_mock) {
294+
if (ops)
295+
rc = ops->walk_hmem_resources(host, fn);
296+
} else {
297+
rc = walk_hmem_resources(host, fn);
298+
}
299+
put_cxl_mock_ops(index);
300+
return rc;
301+
}
302+
EXPORT_SYMBOL_GPL(__wrap_walk_hmem_resources);
303+
254304
MODULE_LICENSE("GPL v2");
255305
MODULE_DESCRIPTION("cxl_test: emulation module");
256306
MODULE_IMPORT_NS("ACPI");

tools/testing/cxl/test/mock.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
#include <linux/list.h>
44
#include <linux/acpi.h>
5+
#include <linux/dax.h>
56
#include <cxl.h>
67

78
struct cxl_mock_ops {
@@ -27,8 +28,15 @@ struct cxl_mock_ops {
2728
int (*hmat_get_extended_linear_cache_size)(struct resource *backing_res,
2829
int nid,
2930
resource_size_t *cache_size);
31+
int (*walk_hmem_resources)(struct device *host, walk_hmem_fn fn);
32+
int (*region_intersects)(resource_size_t start, size_t size,
33+
unsigned long flags, unsigned long desc);
34+
int (*region_intersects_soft_reserve)(resource_size_t start,
35+
size_t size);
3036
};
3137

38+
int hmem_test_init(void);
39+
void hmem_test_exit(void);
3240
void register_cxl_mock_ops(struct cxl_mock_ops *ops);
3341
void unregister_cxl_mock_ops(struct cxl_mock_ops *ops);
3442
struct cxl_mock_ops *get_cxl_mock_ops(int *index);

0 commit comments

Comments
 (0)