hw/cxl/events: Add qmp interfaces to add/release dynamic capacity extents

To simulate FM functionalities for initiating Dynamic Capacity Add
(Opcode 5604h) and Dynamic Capacity Release (Opcode 5605h) as in CXL spec
r3.1 7.6.7.6.5 and 7.6.7.6.6, we implemented two QMP interfaces to issue
add/release dynamic capacity extents requests.

With the change, we allow to release an extent only when its DPA range
is contained by a single accepted extent in the device. That is to say,
extent superset release is not supported yet.

1. Add dynamic capacity extents:

For example, the command to add two continuous extents (each 128MiB long)
to region 0 (starting at DPA offset 0) looks like below:

{ "execute": "qmp_capabilities" }

{ "execute": "cxl-add-dynamic-capacity",
  "arguments": {
      "path": "/machine/peripheral/cxl-dcd0",
      "host-id": 0,
      "selection-policy": "prescriptive",
      "region": 0,
      "extents": [
      {
          "offset": 0,
          "len": 134217728
      },
      {
          "offset": 134217728,
          "len": 134217728
      }
      ]
  }
}

2. Release dynamic capacity extents:

For example, the command to release an extent of size 128MiB from region 0
(DPA offset 128MiB) looks like below:

{ "execute": "cxl-release-dynamic-capacity",
  "arguments": {
      "path": "/machine/peripheral/cxl-dcd0",
      "host-id": 0,
      "removal-policy":"prescriptive",
      "region": 0,
      "extents": [
      {
          "offset": 134217728,
          "len": 134217728
      }
      ]
  }
}

Tested-by: Svetly Todorov <svetly.todorov@memverge.com>
Reviewed-by: Gregory Price <gregory.price@memverge.com>
Signed-off-by: Fan Ni <fan.ni@samsung.com>
Message-Id: <20240523174651.1089554-12-nifan.cxl@gmail.com>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
Fan Ni 2024-05-23 10:44:51 -07:00 committed by Michael S. Tsirkin
parent 16fd1b1216
commit d0b9b28a5b
6 changed files with 563 additions and 13 deletions

View file

@ -1405,7 +1405,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd,
* Check whether any bit between addr[nr, nr+size) is set,
* return true if any bit is set, otherwise return false
*/
static bool test_any_bits_set(const unsigned long *addr, unsigned long nr,
bool test_any_bits_set(const unsigned long *addr, unsigned long nr,
unsigned long size)
{
unsigned long res = find_next_bit(addr, size + nr, nr);
@ -1444,7 +1444,7 @@ CXLDCRegion *cxl_find_dc_region(CXLType3Dev *ct3d, uint64_t dpa, uint64_t len)
return NULL;
}
static void cxl_insert_extent_to_extent_list(CXLDCExtentList *list,
void cxl_insert_extent_to_extent_list(CXLDCExtentList *list,
uint64_t dpa,
uint64_t len,
uint8_t *tag,
@ -1470,6 +1470,44 @@ void cxl_remove_extent_from_extent_list(CXLDCExtentList *list,
g_free(extent);
}
/*
* Add a new extent to the extent "group" if group exists;
* otherwise, create a new group
* Return value: the extent group where the extent is inserted.
*/
CXLDCExtentGroup *cxl_insert_extent_to_extent_group(CXLDCExtentGroup *group,
uint64_t dpa,
uint64_t len,
uint8_t *tag,
uint16_t shared_seq)
{
if (!group) {
group = g_new0(CXLDCExtentGroup, 1);
QTAILQ_INIT(&group->list);
}
cxl_insert_extent_to_extent_list(&group->list, dpa, len,
tag, shared_seq);
return group;
}
void cxl_extent_group_list_insert_tail(CXLDCExtentGroupList *list,
CXLDCExtentGroup *group)
{
QTAILQ_INSERT_TAIL(list, group, node);
}
void cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list)
{
CXLDCExtent *ent, *ent_next;
CXLDCExtentGroup *group = QTAILQ_FIRST(list);
QTAILQ_REMOVE(list, group, node);
QTAILQ_FOREACH_SAFE(ent, &group->list, node, ent_next) {
cxl_remove_extent_from_extent_list(&group->list, ent);
}
g_free(group);
}
/*
* CXL r3.1 Table 8-168: Add Dynamic Capacity Response Input Payload
* CXL r3.1 Table 8-170: Release Dynamic Capacity Input Payload
@ -1541,6 +1579,7 @@ static CXLRetCode cxl_dcd_add_dyn_cap_rsp_dry_run(CXLType3Dev *ct3d,
{
uint32_t i;
CXLDCExtent *ent;
CXLDCExtentGroup *ext_group;
uint64_t dpa, len;
Range range1, range2;
@ -1551,9 +1590,13 @@ static CXLRetCode cxl_dcd_add_dyn_cap_rsp_dry_run(CXLType3Dev *ct3d,
range_init_nofail(&range1, dpa, len);
/*
* TODO: once the pending extent list is added, check against
* the list will be added here.
* The host-accepted DPA range must be contained by the first extent
* group in the pending list
*/
ext_group = QTAILQ_FIRST(&ct3d->dc.extents_pending);
if (!cxl_extents_contains_dpa_range(&ext_group->list, dpa, len)) {
return CXL_MBOX_INVALID_PA;
}
/* to-be-added range should not overlap with range already accepted */
QTAILQ_FOREACH(ent, &ct3d->dc.extents, node) {
@ -1586,10 +1629,7 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
CXLRetCode ret;
if (in->num_entries_updated == 0) {
/*
* TODO: once the pending list is introduced, extents in the beginning
* will get wiped out.
*/
cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending);
return CXL_MBOX_SUCCESS;
}
@ -1615,11 +1655,9 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd,
cxl_insert_extent_to_extent_list(extent_list, dpa, len, NULL, 0);
ct3d->dc.total_extent_count += 1;
/*
* TODO: we will add a pending extent list based on event log record
* and process the list accordingly here.
*/
}
/* Remove the first extent group in the pending list */
cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending);
return CXL_MBOX_SUCCESS;
}