[PATCH 5/9] hw/cxl: Map lazy memory backend after host acceptance

Alireza Sanaee via qemu development posted 9 patches 1 week, 1 day ago
[PATCH 5/9] hw/cxl: Map lazy memory backend after host acceptance
Posted by Alireza Sanaee via qemu development 1 week, 1 day ago
In the dc-regions-total-size flow, a requested extent is not backed when it
is queued. It becomes usable only after the host accepts it with Add
Dynamic Capacity Response.

Use that response path to look up the first pending group's metadata for
each accepted extent, enable the selected host backend, and move the
backend and fixed-window references onto the committed extent list. The
accepted range is then marked backed just like the non-lazy path.

This wires host acceptance to the lazy backend lifecycle and leaves the
fixed-window direct aliasing to the following patch.

Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
---
 hw/cxl/cxl-mailbox-utils.c | 76 ++++++++++++++++++++++++++++++++++++--
 1 file changed, 73 insertions(+), 3 deletions(-)

diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
index c5427adb3a..cc7be6e68c 100644
--- a/hw/cxl/cxl-mailbox-utils.c
+++ b/hw/cxl/cxl-mailbox-utils.c
@@ -3668,6 +3668,28 @@ static CXLRetCode cxl_detect_malformed_extent_list(CXLType3Dev *ct3d,
     return CXL_MBOX_SUCCESS;
 }
 
+/* Find extent details (backend, window, tag, rid) in the first pending group */
+static bool cxl_extent_find_extent_detail(CXLDCExtentGroupList *list,
+                                          uint64_t start_dpa, uint64_t len,
+                                          uint8_t *tag, HostMemoryBackend **hmb,
+                                          struct CXLFixedWindow **fw, int *rid)
+{
+    CXLDCExtent *ent;
+    CXLDCExtentGroup *group = QTAILQ_FIRST(list);
+
+    QTAILQ_FOREACH(ent, &group->list, node) {
+        if (ent->start_dpa == start_dpa && ent->len == len) {
+            *fw = ent->fw;
+            *hmb = ent->hm;
+            memcpy(tag, ent->tag, 0x10);
+            *rid = ent->rid;
+            return true;
+        }
+    }
+
+    return false;
+}
+
 static CXLRetCode cxl_dcd_add_dyn_cap_rsp_dry_run(CXLType3Dev *ct3d,
         const CXLUpdateDCExtentListInPl *in)
 {
@@ -3718,8 +3740,12 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
     CXLUpdateDCExtentListInPl *in = (void *)payload_in;
     CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
     CXLDCExtentList *extent_list = &ct3d->dc.extents;
+    struct CXLFixedWindow *fw;
+    HostMemoryBackend *hmb_dc;
+    uint8_t tag[0x10];
     uint32_t i, num;
     uint64_t dpa, len;
+    int rid;
     CXLRetCode ret;
 
     if (len_in < sizeof(*in)) {
@@ -3756,10 +3782,54 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
     for (i = 0; i < in->num_entries_updated; i++) {
         dpa = in->updated_entries[i].start_dpa;
         len = in->updated_entries[i].len;
+        if (ct3d->dc.total_capacity_cmd) {
+            bool found;
+            MemoryRegion *mr;
+
+            found = cxl_extent_find_extent_detail(&ct3d->dc.extents_pending,
+                                                  dpa, len, tag,
+                                                  &hmb_dc, &fw, &rid);
+
+            /*
+             * Host accepted an extent where device lacks details including
+             * wrong DPA or wrong length.
+             */
+            if (!found) {
+                qemu_log_mask(LOG_GUEST_ERROR,
+                              "Could not find the extent detail for DPA 0x%"
+                              PRIx64 " LEN 0x%" PRIx64 "\n", dpa, len);
+                return CXL_MBOX_INVALID_PA;
+            }
+
+            /* The host memory backend should not be already mapped */
+            if (host_memory_backend_is_mapped(hmb_dc)) {
+                qemu_log_mask(LOG_GUEST_ERROR,
+                              "The host memory backend for DPA 0x%" PRIx64
+                              " LEN 0x%" PRIx64 " is already mapped\n",
+                              dpa, len);
+                return CXL_MBOX_INVALID_PA;
+            }
 
-        cxl_insert_extent_to_extent_list(extent_list,
-                                         NULL, NULL, dpa, len,
-                                         NULL, 0, 0);
+            mr = host_memory_backend_get_memory(hmb_dc);
+            if (!mr) {
+                qemu_log_mask(LOG_GUEST_ERROR,
+                              "Could not get memory region from "
+                              "host memory backend\n");
+                return CXL_MBOX_INVALID_PA;
+            }
+
+            memory_region_set_nonvolatile(mr, false);
+            memory_region_set_enabled(mr, true);
+            host_memory_backend_set_mapped(hmb_dc, true);
+
+            cxl_insert_extent_to_extent_list(extent_list,
+                                             hmb_dc, fw, dpa, len,
+                                             NULL, 0, rid);
+        } else {
+            cxl_insert_extent_to_extent_list(extent_list,
+                                             NULL, NULL, dpa, len,
+                                             NULL, 0, -1);
+        }
         ct3d->dc.total_extent_count += 1;
         ct3d->dc.nr_extents_accepted += 1;
         ct3_set_region_block_backed(ct3d, dpa, len);
-- 
2.50.1 (Apple Git-155)
Re: [PATCH 5/9] hw/cxl: Map lazy memory backend after host acceptance
Posted by Anisa Su 3 days, 15 hours ago
On Wed, Mar 25, 2026 at 06:42:53PM +0000, Alireza Sanaee wrote:
> In the dc-regions-total-size flow, a requested extent is not backed when it
> is queued. It becomes usable only after the host accepts it with Add
> Dynamic Capacity Response.
> 
> Use that response path to look up the first pending group's metadata for
> each accepted extent, enable the selected host backend, and move the
> backend and fixed-window references onto the committed extent list. The
> accepted range is then marked backed just like the non-lazy path.
> 
> This wires host acceptance to the lazy backend lifecycle and leaves the
> fixed-window direct aliasing to the following patch.
> 
> Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
> ---
>  hw/cxl/cxl-mailbox-utils.c | 76 ++++++++++++++++++++++++++++++++++++--
>  1 file changed, 73 insertions(+), 3 deletions(-)
> 
> diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
> index c5427adb3a..cc7be6e68c 100644
> --- a/hw/cxl/cxl-mailbox-utils.c
> +++ b/hw/cxl/cxl-mailbox-utils.c
[snip]
>  static CXLRetCode cxl_dcd_add_dyn_cap_rsp_dry_run(CXLType3Dev *ct3d,
>          const CXLUpdateDCExtentListInPl *in)
>  {
> @@ -3718,8 +3740,12 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
>      CXLUpdateDCExtentListInPl *in = (void *)payload_in;
>      CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
>      CXLDCExtentList *extent_list = &ct3d->dc.extents;
> +    struct CXLFixedWindow *fw;
> +    HostMemoryBackend *hmb_dc;
> +    uint8_t tag[0x10];
>      uint32_t i, num;
>      uint64_t dpa, len;
> +    int rid;
>      CXLRetCode ret;
>  
>      if (len_in < sizeof(*in)) {
> @@ -3756,10 +3782,54 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
>      for (i = 0; i < in->num_entries_updated; i++) {
>          dpa = in->updated_entries[i].start_dpa;
>          len = in->updated_entries[i].len;
> +        if (ct3d->dc.total_capacity_cmd) {
               memcpy(tag, in->updated_entries[i], 0x10);
> +            bool found;
> +            MemoryRegion *mr;
> +
> +            found = cxl_extent_find_extent_detail(&ct3d->dc.extents_pending,
> +                                                  dpa, len, tag,
> +                                                  &hmb_dc, &fw, &rid);
> +
Btw, I'm using this patchset to test my current DCD RFC :) The main thing is I
want to test having multiple extents in the same add request for the new
requirements for tags on the host side. Since we can only add/remove tagged
capacity at once (no incremental add/partial release), would it be possible to
support that? Sorry I didn't have a look sooner

Thanks,
Anisa
 -- 
> 2.50.1 (Apple Git-155)
>
Re: [PATCH 5/9] hw/cxl: Map lazy memory backend after host acceptance
Posted by Anisa Su 3 days, 6 hours ago
On Mon, Mar 30, 2026 at 01:24:54AM -0700, Anisa Su wrote:
> On Wed, Mar 25, 2026 at 06:42:53PM +0000, Alireza Sanaee wrote:
> > In the dc-regions-total-size flow, a requested extent is not backed when it
> > is queued. It becomes usable only after the host accepts it with Add
> > Dynamic Capacity Response.
> > 
> > Use that response path to look up the first pending group's metadata for
> > each accepted extent, enable the selected host backend, and move the
> > backend and fixed-window references onto the committed extent list. The
> > accepted range is then marked backed just like the non-lazy path.
> > 
> > This wires host acceptance to the lazy backend lifecycle and leaves the
> > fixed-window direct aliasing to the following patch.
> > 
> > Signed-off-by: Alireza Sanaee <alireza.sanaee@huawei.com>
> > ---
> >  hw/cxl/cxl-mailbox-utils.c | 76 ++++++++++++++++++++++++++++++++++++--
> >  1 file changed, 73 insertions(+), 3 deletions(-)
> > 
> > diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c
> > index c5427adb3a..cc7be6e68c 100644
> > --- a/hw/cxl/cxl-mailbox-utils.c
> > +++ b/hw/cxl/cxl-mailbox-utils.c
> [snip]
> >  static CXLRetCode cxl_dcd_add_dyn_cap_rsp_dry_run(CXLType3Dev *ct3d,
> >          const CXLUpdateDCExtentListInPl *in)
> >  {
> > @@ -3718,8 +3740,12 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
> >      CXLUpdateDCExtentListInPl *in = (void *)payload_in;
> >      CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
> >      CXLDCExtentList *extent_list = &ct3d->dc.extents;
> > +    struct CXLFixedWindow *fw;
> > +    HostMemoryBackend *hmb_dc;
> > +    uint8_t tag[0x10];
> >      uint32_t i, num;
> >      uint64_t dpa, len;
> > +    int rid;
> >      CXLRetCode ret;
> >  
> >      if (len_in < sizeof(*in)) {
> > @@ -3756,10 +3782,54 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
> >      for (i = 0; i < in->num_entries_updated; i++) {
> >          dpa = in->updated_entries[i].start_dpa;
> >          len = in->updated_entries[i].len;
> > +        if (ct3d->dc.total_capacity_cmd) {
>                memcpy(tag, in->updated_entries[i], 0x10);
^sorry that was totally wrong lol! ignore that. but I did encounter a null tag
on host side when I sent the qmp tag-based rls cmd that resolved when I changed
it to prescriptive, so let me see what happened there
> > +            bool found;
> > +            MemoryRegion *mr;
> > +
> > +            found = cxl_extent_find_extent_detail(&ct3d->dc.extents_pending,
> > +                                                  dpa, len, tag,
> > +                                                  &hmb_dc, &fw, &rid);
> > +
> Btw, I'm using this patchset to test my current DCD RFC :) The main thing is I
> want to test having multiple extents in the same add request for the new
> requirements for tags on the host side. Since we can only add/remove tagged
> capacity at once (no incremental add/partial release), would it be possible to
> support that? Sorry I didn't have a look sooner
> 
> Thanks,
> Anisa
>  -- 
> > 2.50.1 (Apple Git-155)
> >