[PATCH v4 4/9] dax/hmem: Defer handling of Soft Reserved ranges that overlap CXL windows

Smita Koralahalli
2025-11-20T03:19:48Z

From: Dan Williams <dan.j.williams@intel.com>

Defer handling of Soft Reserved ranges that intersect CXL windows at
probe time. Delay processing until after device discovery so that the
CXL stack can publish windows and assemble regions before HMEM claims
those address ranges.

Add a deferral path that schedules deferred work when HMEM detects a
Soft Reserved range intersecting a CXL window during probe. The deferred
work runs after probe completes and allows the CXL subsystem to finish
resource discovery and region setup before HMEM takes any action.

This change does not address region assembly failures. It only delays
HMEM handling to avoid prematurely claiming ranges that CXL may own.

Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Signed-off-by: Smita Koralahalli <Smita.KoralahalliChannabasappa@amd.com>
---
drivers/dax/hmem/hmem.c | 66 +++++++++++++++++++++++++++++++++++++++--
1 file changed, 64 insertions(+), 2 deletions(-)

diff --git a/drivers/dax/hmem/hmem.c b/drivers/dax/hmem/hmem.c
index c2c110b194e5..f70a0688bd11 100644
--- a/drivers/dax/hmem/hmem.c
+++ b/drivers/dax/hmem/hmem.c
@@ -58,9 +58,21 @@ static void release_hmem(void *pdev)
platform_device_unregister(pdev);
}

+static enum dax_cxl_mode {
+ DAX_CXL_MODE_DEFER,
+ DAX_CXL_MODE_REGISTER,
+ DAX_CXL_MODE_DROP,
+} dax_cxl_mode;
+
+struct dax_defer_work {
+ struct platform_device *pdev;
+ struct work_struct work;
+};
+
static int hmem_register_device(struct device *host, int target_nid,
const struct resource *res)
{
+ struct dax_defer_work *work = dev_get_drvdata(host);
struct platform_device *pdev;
struct memregion_info info;
long id;
@@ -69,8 +81,18 @@ static int hmem_register_device(struct device *host, int target_nid,
if (IS_ENABLED(CONFIG_DEV_DAX_CXL) &&
region_intersects(res->start, resource_size(res), IORESOURCE_MEM,
IORES_DESC_CXL) != REGION_DISJOINT) {
- dev_dbg(host, "deferring range to CXL: %pr\n", res);
- return 0;
+ switch (dax_cxl_mode) {
+ case DAX_CXL_MODE_DEFER:
+ dev_dbg(host, "deferring range to CXL: %pr\n", res);
+ schedule_work(&work->work);
+ return 0;
+ case DAX_CXL_MODE_REGISTER:
+ dev_dbg(host, "registering CXL range: %pr\n", res);
+ break;
+ case DAX_CXL_MODE_DROP:
+ dev_dbg(host, "dropping CXL range: %pr\n", res);
+ return 0;
+ }
}

rc = region_intersects_soft_reserve(res->start, resource_size(res),
@@ -125,8 +147,48 @@ static int hmem_register_device(struct device *host, int target_nid,
return rc;
}

+static int handle_deferred_cxl(struct device *host, int target_nid,
+ const struct resource *res)
+{
+ /* TODO: Handle region assembly failures */
+ return 0;
+}
+
+static void process_defer_work(struct work_struct *_work)
+{
+ struct dax_defer_work *work = container_of(_work, typeof(*work), work);
+ struct platform_device *pdev = work->pdev;
+
+ /* relies on cxl_acpi and cxl_pci having had a chance to load */
+ wait_for_device_probe();
+
+ walk_hmem_resources(&pdev->dev, handle_deferred_cxl);
+}
+
+static void kill_defer_work(void *_work)
+{
+ struct dax_defer_work *work = container_of(_work, typeof(*work), work);
+
+ cancel_work_sync(&work->work);
+ kfree(work);
+}
+
static int dax_hmem_platform_probe(struct platform_device *pdev)
{
+ struct dax_defer_work *work = kzalloc(sizeof(*work), GFP_KERNEL);
+ int rc;
+
+ if (!work)
+ return -ENOMEM;
+
+ work->pdev = pdev;
+ INIT_WORK(&work->work, process_defer_work);
+
+ rc = devm_add_action_or_reset(&pdev->dev, kill_defer_work, work);
+ if (rc)
+ return rc;
+
+ platform_set_drvdata(pdev, work);
return walk_hmem_resources(&pdev->dev, hmem_register_device);
}

--
2.17.1