Add a dc-regions-total-size property that allows creating a CXL type3
device with DC regions but without a backing memory device at init time. In
Dynamic Capacity scenarios, memory can show up asynchronously from
different resources (RAM, PMEM, file-backed). For these cases, only the
total DC size needs to be known upfront.
When dc-regions-total-size is set (instead of volatile-dc-memdev), the
device initializes DC regions using the specified total size but does not
set up any backing memory. Any FMAPI or QMP command that attempts to add or
release extents will fail with an error, since no backing device is
available yet. The runtime hookup of tagged memory backends will be added
in a subsequent patch.
Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
---
hw/cxl/cxl-mailbox-utils.c | 8 ++++
hw/mem/cxl_type3.c | 92 ++++++++++++++++++++++---------------
include/hw/cxl/cxl_device.h | 1 +
3 files changed, 65 insertions(+), 36 deletions(-)
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index c83b5f90d4..e6e136cf44 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -4270,6 +4270,10 @@ static CXLRetCode cmd_fm_initiate_dc_add(const struct cxl_cmd *cmd,
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
int i, rc;
+ if (ct3d->dc.total_capacity_cmd) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
switch (in->selection_policy) {
case CXL_EXTENT_SELECTION_POLICY_PRESCRIPTIVE: {
/* Adding extents exceeds device's extent tracking ability. */
@@ -4357,6 +4361,10 @@ static CXLRetCode cmd_fm_initiate_dc_release(const struct cxl_cmd *cmd,
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
int i, rc;
+ if (ct3d->dc.total_capacity_cmd) {
+ return CXL_MBOX_UNSUPPORTED;
+ }
+
switch (in->flags & CXL_EXTENT_REMOVAL_POLICY_MASK) {
case CXL_EXTENT_REMOVAL_POLICY_PRESCRIPTIVE: {
CXLDCExtentList updated_list;
diff --git a/hw/mem/cxl_type3.c b/hw/mem/cxl_type3.c
index d9fc0bec8f..45fb6c55bc 100644
--- a/hw/mem/cxl_type3.c
+++ b/hw/mem/cxl_type3.c
@@ -190,12 +190,15 @@ static int ct3_build_cdat_table(CDATSubHeader ***cdat_table, void *priv)
}
if (ct3d->dc.num_regions) {
- if (!ct3d->dc.host_dc) {
- return -EINVAL;
- }
- dc_mr = host_memory_backend_get_memory(ct3d->dc.host_dc);
- if (!dc_mr) {
- return -EINVAL;
+ /* Only check if DC is static (has a backing device) */
+ if (ct3d->dc.total_capacity_cmd == 0) {
+ if (!ct3d->dc.host_dc) {
+ return -EINVAL;
+ }
+ dc_mr = host_memory_backend_get_memory(ct3d->dc.host_dc);
+ if (!dc_mr) {
+ return -EINVAL;
+ }
}
len += CT3_CDAT_NUM_ENTRIES * ct3d->dc.num_regions;
}
@@ -216,7 +219,7 @@ static int ct3_build_cdat_table(CDATSubHeader ***cdat_table, void *priv)
cur_ent += CT3_CDAT_NUM_ENTRIES;
}
- if (dc_mr) {
+ if (dc_mr || ct3d->dc.total_capacity_cmd) {
int i;
uint64_t region_base = vmr_size + pmr_size;
@@ -651,8 +654,12 @@ static bool cxl_create_dc_regions(CXLType3Dev *ct3d, Error **errp)
MemoryRegion *mr;
uint64_t dc_size;
- mr = host_memory_backend_get_memory(ct3d->dc.host_dc);
- dc_size = memory_region_size(mr);
+ if (ct3d->dc.total_capacity_cmd != 0) {
+ dc_size = ct3d->dc.total_capacity_cmd;
+ } else {
+ mr = host_memory_backend_get_memory(ct3d->dc.host_dc);
+ dc_size = memory_region_size(mr);
+ }
region_len = DIV_ROUND_UP(dc_size, ct3d->dc.num_regions);
if (dc_size % (ct3d->dc.num_regions * CXL_CAPACITY_MULTIPLIER) != 0) {
@@ -818,36 +825,41 @@ static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
MemoryRegion *dc_mr;
char *dc_name;
- if (!ct3d->dc.host_dc) {
- error_setg(errp, "dynamic capacity must have a backing device");
- return false;
- }
+ /* Only require backing device if total_capacity_cmd is zero */
+ if (ct3d->dc.total_capacity_cmd == 0) {
+ if (!ct3d->dc.host_dc) {
+ error_setg(errp, "dynamic capacity must have a backing device");
+ return false;
+ }
- dc_mr = host_memory_backend_get_memory(ct3d->dc.host_dc);
- if (!dc_mr) {
- error_setg(errp, "dynamic capacity must have a backing device");
- return false;
- }
+ dc_mr = host_memory_backend_get_memory(ct3d->dc.host_dc);
+ if (!dc_mr) {
+ error_setg(errp, "dynamic capacity must have a backing device");
+ return false;
+ }
- if (host_memory_backend_is_mapped(ct3d->dc.host_dc)) {
- error_setg(errp, "memory backend %s can't be used multiple times.",
- object_get_canonical_path_component(OBJECT(ct3d->dc.host_dc)));
- return false;
- }
- /*
- * Set DC regions as volatile for now, non-volatile support can
- * be added in the future if needed.
- */
- memory_region_set_nonvolatile(dc_mr, false);
- memory_region_set_enabled(dc_mr, true);
- host_memory_backend_set_mapped(ct3d->dc.host_dc, true);
- if (ds->id) {
- dc_name = g_strdup_printf("cxl-dcd-dpa-dc-space:%s", ds->id);
- } else {
- dc_name = g_strdup("cxl-dcd-dpa-dc-space");
+ if (host_memory_backend_is_mapped(ct3d->dc.host_dc)) {
+ error_setg(errp,
+ "memory backend %s can't be used multiple times.",
+ object_get_canonical_path_component(
+ OBJECT(ct3d->dc.host_dc)));
+ return false;
+ }
+ /*
+ * Set DC regions as volatile for now, non-volatile support can
+ * be added in the future if needed.
+ */
+ memory_region_set_nonvolatile(dc_mr, false);
+ memory_region_set_enabled(dc_mr, true);
+ host_memory_backend_set_mapped(ct3d->dc.host_dc, true);
+ if (ds->id) {
+ dc_name = g_strdup_printf("cxl-dcd-dpa-dc-space:%s", ds->id);
+ } else {
+ dc_name = g_strdup("cxl-dcd-dpa-dc-space");
+ }
+ address_space_init(&ct3d->dc.host_dc_as, dc_mr, dc_name);
+ g_free(dc_name);
}
- address_space_init(&ct3d->dc.host_dc_as, dc_mr, dc_name);
- g_free(dc_name);
if (!cxl_create_dc_regions(ct3d, errp)) {
error_append_hint(errp, "setup DC regions failed");
@@ -1361,6 +1373,8 @@ static const Property ct3_props[] = {
DEFINE_PROP_UINT8("num-dc-regions", CXLType3Dev, dc.num_regions, 0),
DEFINE_PROP_LINK("volatile-dc-memdev", CXLType3Dev, dc.host_dc,
TYPE_MEMORY_BACKEND, HostMemoryBackend *),
+ DEFINE_PROP_SIZE("dc-regions-total-size", CXLType3Dev,
+ dc.total_capacity_cmd, 0),
DEFINE_PROP_PCIE_LINK_SPEED("x-speed", CXLType3Dev,
speed, PCIE_LINK_SPEED_32),
DEFINE_PROP_PCIE_LINK_WIDTH("x-width", CXLType3Dev,
@@ -2305,6 +2319,12 @@ static void qmp_cxl_process_dynamic_capacity_prescriptive(const char *path,
return;
}
+ if (dcd->dc.total_capacity_cmd) {
+ error_setg(errp,
+ "dc-regions-total-size is set: extent add/release via QMP "
+ "not yet supported without a backing device at init");
+ return;
+ }
if (rid >= dcd->dc.num_regions) {
error_setg(errp, "region id is too large");
diff --git a/include/hw/cxl/cxl_device.h b/include/hw/cxl/cxl_device.h
index ba551fa5f9..630cf44e0e 100644
--- a/include/hw/cxl/cxl_device.h
+++ b/include/hw/cxl/cxl_device.h
@@ -785,6 +785,7 @@ struct CXLType3Dev {
* memory region size.
*/
uint64_t total_capacity; /* 256M aligned */
+ uint64_t total_capacity_cmd; /* 256M aligned */
CXLDCExtentList extents;
CXLDCExtentGroupList extents_pending;
uint32_t total_extent_count;
--
2.50.1 (Apple Git-155)
© 2016 - 2026 Red Hat, Inc.