ldflags-y += --wrap=hmat_get_extended_linear_cache_size
ldflags-y += --wrap=devm_cxl_add_dport_by_dev
ldflags-y += --wrap=devm_cxl_switch_port_decoders_setup
+ldflags-y += --wrap=walk_hmem_resources
+ldflags-y += --wrap=region_intersects
+ldflags-y += --wrap=region_intersects_soft_reserve
DRIVERS := ../../../drivers
+DAX_HMEM_SRC := $(DRIVERS)/dax/hmem
CXL_SRC := $(DRIVERS)/cxl
CXL_CORE_SRC := $(DRIVERS)/cxl/core
ccflags-y := -I$(srctree)/drivers/cxl/
cxl_core-y += cxl_core_test.o
cxl_core-y += cxl_core_exports.o
+obj-m += dax_hmem.o
+dax_hmem-y := $(DAX_HMEM_SRC)/hmem.o
+
KBUILD_CFLAGS := $(filter-out -Wmissing-prototypes -Wmissing-declarations, $(KBUILD_CFLAGS))
obj-m += test/
obj-m += cxl_translate.o
cxl_test-y := cxl.o
+cxl_test-y += hmem_test.o
cxl_mock-y := mock.o
cxl_mock_mem-y := mem.o
cxl_endpoint_get_perf_coordinates(port, ep_c);
}
+/*
+ * Simulate that the first half of mock CXL Window 0 is "Soft Reserve" capacity
+ */
+static int mock_walk_hmem_resources(struct device *host, walk_hmem_fn fn)
+{
+ struct acpi_cedt_cfmws *cfmws = mock_cfmws[0];
+ struct resource window =
+ DEFINE_RES_MEM(cfmws->base_hpa, cfmws->window_size / 2);
+
+ dev_dbg(host, "walk cxl_test resource: %pr\n", &window);
+ return fn(host, 0, &window);
+}
+
+/*
+ * This should only be called by the dax_hmem case, treat mismatches (negative
+ * result) as "fallback to base region_intersects()". Simulate that the first
+ * half of mock CXL Window 0 is IORES_DESC_CXL capacity.
+ */
+static int mock_region_intersects(resource_size_t start, size_t size,
+ unsigned long flags, unsigned long desc)
+{
+ struct resource res = DEFINE_RES_MEM(start, size);
+ struct acpi_cedt_cfmws *cfmws = mock_cfmws[0];
+ struct resource window =
+ DEFINE_RES_MEM(cfmws->base_hpa, cfmws->window_size / 2);
+
+ if (resource_overlaps(&res, &window))
+ return REGION_INTERSECTS;
+ pr_debug("warning: no cxl_test CXL intersection for %pr\n", &res);
+ return -1;
+}
+
+
+static int
+mock_region_intersects_soft_reserve(resource_size_t start, size_t size)
+{
+ struct resource res = DEFINE_RES_MEM(start, size);
+ struct acpi_cedt_cfmws *cfmws = mock_cfmws[0];
+ struct resource window =
+ DEFINE_RES_MEM(cfmws->base_hpa, cfmws->window_size / 2);
+
+ if (resource_overlaps(&res, &window))
+ return REGION_INTERSECTS;
+ pr_debug("warning: no cxl_test soft reserve intersection for %pr\n", &res);
+ return -1;
+}
+
static struct cxl_mock_ops cxl_mock_ops = {
.is_mock_adev = is_mock_adev,
.is_mock_bridge = is_mock_bridge,
.devm_cxl_add_dport_by_dev = mock_cxl_add_dport_by_dev,
.hmat_get_extended_linear_cache_size =
mock_hmat_get_extended_linear_cache_size,
+ .walk_hmem_resources = mock_walk_hmem_resources,
+ .region_intersects = mock_region_intersects,
+ .region_intersects_soft_reserve = mock_region_intersects_soft_reserve,
.list = LIST_HEAD_INIT(cxl_mock_ops.list),
};
if (rc)
goto err_root;
+ rc = hmem_test_init();
+ if (rc)
+ goto err_mem;
+
return 0;
+err_mem:
+ cxl_mem_exit();
err_root:
platform_device_put(cxl_acpi);
err_rch:
{
int i;
+ hmem_test_exit();
cxl_mem_exit();
platform_device_unregister(cxl_acpi);
cxl_rch_topo_exit();
--- /dev/null
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright (C) 2026 Intel Corporation */
+#include <linux/moduleparam.h>
+#include <linux/workqueue.h>
+#include "../../../drivers/dax/bus.h"
+
+static bool hmem_test;
+
+static void hmem_test_work(struct work_struct *work)
+{
+}
+
+static void hmem_test_release(struct device *dev)
+{
+ struct hmem_platform_device *hpdev =
+ container_of(dev, typeof(*hpdev), pdev.dev);
+
+ memset(hpdev, 0, sizeof(*hpdev));
+}
+
+static struct hmem_platform_device hmem_test_device = {
+ .pdev = {
+ .name = "hmem_platform",
+ .id = 1,
+ .dev = {
+ .release = hmem_test_release,
+ },
+ },
+ .work = __WORK_INITIALIZER(hmem_test_device.work, hmem_test_work),
+};
+
+int hmem_test_init(void)
+{
+ if (!hmem_test)
+ return 0;
+
+ return platform_device_register(&hmem_test_device.pdev);
+}
+
+void hmem_test_exit(void)
+{
+ if (hmem_test)
+ platform_device_unregister(&hmem_test_device.pdev);
+}
+
+module_param(hmem_test, bool, 0444);
+MODULE_PARM_DESC(hmem_test, "Enable/disable the dax_hmem test platform device");
struct cxl_dpa_info range_info = { 0 };
int rc;
+ /* Increase async probe race window */
+ usleep_range(500*1000, 1000*1000);
+
mdata = devm_kzalloc(dev, sizeof(*mdata), GFP_KERNEL);
if (!mdata)
return -ENOMEM;
}
EXPORT_SYMBOL_NS_GPL(__wrap_devm_cxl_add_dport_by_dev, "CXL");
+int __wrap_region_intersects(resource_size_t start, size_t size,
+ unsigned long flags, unsigned long desc)
+{
+ int rc = -1;
+ int index;
+ struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
+
+ if (ops)
+ rc = ops->region_intersects(start, size, flags, desc);
+ if (rc < 0)
+ rc = region_intersects(start, size, flags, desc);
+ put_cxl_mock_ops(index);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(__wrap_region_intersects);
+
+int __wrap_region_intersects_soft_reserve(resource_size_t start, size_t size)
+{
+ int rc = -1;
+ int index;
+ struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
+
+ if (ops)
+ rc = ops->region_intersects_soft_reserve(start, size);
+ if (rc < 0)
+ rc = region_intersects_soft_reserve(start, size);
+ put_cxl_mock_ops(index);
+
+ return rc;
+}
+EXPORT_SYMBOL_GPL(__wrap_region_intersects_soft_reserve);
+
+int __wrap_walk_hmem_resources(struct device *host, walk_hmem_fn fn)
+{
+ int index, rc = 0;
+ bool is_mock = strcmp(dev_name(host), "hmem_platform.1") == 0;
+ struct cxl_mock_ops *ops = get_cxl_mock_ops(&index);
+
+ if (is_mock) {
+ if (ops)
+ rc = ops->walk_hmem_resources(host, fn);
+ } else {
+ rc = walk_hmem_resources(host, fn);
+ }
+ put_cxl_mock_ops(index);
+ return rc;
+}
+EXPORT_SYMBOL_GPL(__wrap_walk_hmem_resources);
+
MODULE_LICENSE("GPL v2");
MODULE_DESCRIPTION("cxl_test: emulation module");
MODULE_IMPORT_NS("ACPI");
#include <linux/list.h>
#include <linux/acpi.h>
+#include <linux/dax.h>
#include <cxl.h>
struct cxl_mock_ops {
int (*hmat_get_extended_linear_cache_size)(struct resource *backing_res,
int nid,
resource_size_t *cache_size);
+ int (*walk_hmem_resources)(struct device *host, walk_hmem_fn fn);
+ int (*region_intersects)(resource_size_t start, size_t size,
+ unsigned long flags, unsigned long desc);
+ int (*region_intersects_soft_reserve)(resource_size_t start,
+ size_t size);
};
+int hmem_test_init(void);
+void hmem_test_exit(void);
void register_cxl_mock_ops(struct cxl_mock_ops *ops);
void unregister_cxl_mock_ops(struct cxl_mock_ops *ops);
struct cxl_mock_ops *get_cxl_mock_ops(int *index);