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

Configure Feed

Select the types of activity you want to include in your feed.

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>

authored by

Dan Williams and committed by
Dave Jiang
549b5c12 78b8f1a7

+173
+7
tools/testing/cxl/Kbuild
··· 11 11 ldflags-y += --wrap=hmat_get_extended_linear_cache_size 12 12 ldflags-y += --wrap=devm_cxl_add_dport_by_dev 13 13 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 14 17 15 18 DRIVERS := ../../../drivers 19 + DAX_HMEM_SRC := $(DRIVERS)/dax/hmem 16 20 CXL_SRC := $(DRIVERS)/cxl 17 21 CXL_CORE_SRC := $(DRIVERS)/cxl/core 18 22 ccflags-y := -I$(srctree)/drivers/cxl/ ··· 73 69 cxl_core-y += config_check.o 74 70 cxl_core-y += cxl_core_test.o 75 71 cxl_core-y += cxl_core_exports.o 72 + 73 + obj-m += dax_hmem.o 74 + dax_hmem-y := $(DAX_HMEM_SRC)/hmem.o 76 75 77 76 KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS)) 78 77
+1
tools/testing/cxl/test/Kbuild
··· 7 7 obj-m += cxl_translate.o 8 8 9 9 cxl_test-y := cxl.o 10 + cxl_test-y += hmem_test.o 10 11 cxl_mock-y := mock.o 11 12 cxl_mock_mem-y := mem.o 12 13
+57
tools/testing/cxl/test/cxl.c
··· 1121 1121 cxl_endpoint_get_perf_coordinates(port, ep_c); 1122 1122 } 1123 1123 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 + 1124 1171 static struct cxl_mock_ops cxl_mock_ops = { 1125 1172 .is_mock_adev = is_mock_adev, 1126 1173 .is_mock_bridge = is_mock_bridge, ··· 1183 1136 .devm_cxl_add_dport_by_dev = mock_cxl_add_dport_by_dev, 1184 1137 .hmat_get_extended_linear_cache_size = 1185 1138 mock_hmat_get_extended_linear_cache_size, 1139 + .walk_hmem_resources = mock_walk_hmem_resources, 1140 + .region_intersects = mock_region_intersects, 1141 + .region_intersects_soft_reserve = mock_region_intersects_soft_reserve, 1186 1142 .list = LIST_HEAD_INIT(cxl_mock_ops.list), 1187 1143 }; 1188 1144 ··· 1611 1561 if (rc) 1612 1562 goto err_root; 1613 1563 1564 + rc = hmem_test_init(); 1565 + if (rc) 1566 + goto err_mem; 1567 + 1614 1568 return 0; 1615 1569 1570 + err_mem: 1571 + cxl_mem_exit(); 1616 1572 err_root: 1617 1573 platform_device_put(cxl_acpi); 1618 1574 err_rch: ··· 1656 1600 { 1657 1601 int i; 1658 1602 1603 + hmem_test_exit(); 1659 1604 cxl_mem_exit(); 1660 1605 platform_device_unregister(cxl_acpi); 1661 1606 cxl_rch_topo_exit();
+47
tools/testing/cxl/test/hmem_test.c
··· 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");
+3
tools/testing/cxl/test/mem.c
··· 1695 1695 struct cxl_dpa_info range_info = { 0 }; 1696 1696 int rc; 1697 1697 1698 + /* Increase async probe race window */ 1699 + usleep_range(500*1000, 1000*1000); 1700 + 1698 1701 mdata = devm_kzalloc(dev, sizeof(*mdata), GFP_KERNEL); 1699 1702 if (!mdata) 1700 1703 return -ENOMEM;
+50
tools/testing/cxl/test/mock.c
··· 251 251 } 252 252 EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_dport_by_dev, "CXL"); 253 253 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 + 254 304 MODULE_LICENSE("GPL v2"); 255 305 MODULE_DESCRIPTION("cxl_test: emulation module"); 256 306 MODULE_IMPORT_NS("ACPI");
+8
tools/testing/cxl/test/mock.h
··· 2 2 3 3 #include <linux/list.h> 4 4 #include <linux/acpi.h> 5 + #include <linux/dax.h> 5 6 #include <cxl.h> 6 7 7 8 struct cxl_mock_ops { ··· 28 27 int (*hmat_get_extended_linear_cache_size)(struct resource *backing_res, 29 28 int nid, 30 29 resource_size_t *cache_size); 30 + int (*walk_hmem_resources)(struct device *host, walk_hmem_fn fn); 31 + int (*region_intersects)(resource_size_t start, size_t size, 32 + unsigned long flags, unsigned long desc); 33 + int (*region_intersects_soft_reserve)(resource_size_t start, 34 + size_t size); 31 35 }; 32 36 37 + int hmem_test_init(void); 38 + void hmem_test_exit(void); 33 39 void register_cxl_mock_ops(struct cxl_mock_ops *ops); 34 40 void unregister_cxl_mock_ops(struct cxl_mock_ops *ops); 35 41 struct cxl_mock_ops *get_cxl_mock_ops(int *index);