diff options
Diffstat (limited to 'hw/cxl/cxl-mailbox-utils.c')
-rw-r--r-- | hw/cxl/cxl-mailbox-utils.c | 552 |
1 files changed, 543 insertions, 9 deletions
diff --git a/hw/cxl/cxl-mailbox-utils.c b/hw/cxl/cxl-mailbox-utils.c index 299f232..68c7cc9 100644 --- a/hw/cxl/cxl-mailbox-utils.c +++ b/hw/cxl/cxl-mailbox-utils.c @@ -18,15 +18,16 @@ #include "hw/pci/pci.h" #include "hw/pci-bridge/cxl_upstream_port.h" #include "qemu/cutils.h" +#include "qemu/host-utils.h" #include "qemu/log.h" #include "qemu/units.h" #include "qemu/uuid.h" #include "system/hostmem.h" #include "qemu/range.h" +#include "qapi/qapi-types-cxl.h" #define CXL_CAPACITY_MULTIPLIER (256 * MiB) #define CXL_DC_EVENT_LOG_SIZE 8 -#define CXL_NUM_EXTENTS_SUPPORTED 512 #define CXL_NUM_TAGS_SUPPORTED 0 #define CXL_ALERTS_LIFE_USED_WARN_THRESH (1 << 0) #define CXL_ALERTS_OVER_TEMP_WARN_THRESH (1 << 1) @@ -117,6 +118,13 @@ enum { #define GET_PHYSICAL_PORT_STATE 0x1 TUNNEL = 0x53, #define MANAGEMENT_COMMAND 0x0 + FMAPI_DCD_MGMT = 0x56, + #define GET_DCD_INFO 0x0 + #define GET_HOST_DC_REGION_CONFIG 0x1 + #define SET_DC_REGION_CONFIG 0x2 + #define GET_DC_REGION_EXTENT_LIST 0x3 + #define INITIATE_DC_ADD 0x4 + #define INITIATE_DC_RELEASE 0x5 }; /* CCI Message Format CXL r3.1 Figure 7-19 */ @@ -2750,7 +2758,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd, uint16_t out_pl_len, size; CXLDCExtent *ent; - if (start_extent_id > ct3d->dc.total_extent_count) { + if (start_extent_id > ct3d->dc.nr_extents_accepted) { return CXL_MBOX_INVALID_INPUT; } @@ -2761,7 +2769,7 @@ static CXLRetCode cmd_dcd_get_dyn_cap_ext_list(const struct cxl_cmd *cmd, out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]); stl_le_p(&out->count, record_count); - stl_le_p(&out->total_extents, ct3d->dc.total_extent_count); + stl_le_p(&out->total_extents, ct3d->dc.nr_extents_accepted); stl_le_p(&out->generation_num, ct3d->dc.ext_list_gen_seq); if (record_count > 0) { @@ -2883,16 +2891,20 @@ void cxl_extent_group_list_insert_tail(CXLDCExtentGroupList *list, QTAILQ_INSERT_TAIL(list, group, node); } -void cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list) +uint32_t cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list) { CXLDCExtent *ent, *ent_next; CXLDCExtentGroup *group = QTAILQ_FIRST(list); + uint32_t extents_deleted = 0; QTAILQ_REMOVE(list, group, node); QTAILQ_FOREACH_SAFE(ent, &group->list, node, ent_next) { cxl_remove_extent_from_extent_list(&group->list, ent); + extents_deleted++; } g_free(group); + + return extents_deleted; } /* @@ -3011,7 +3023,7 @@ 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; - uint32_t i; + uint32_t i, num; uint64_t dpa, len; CXLRetCode ret; @@ -3020,7 +3032,8 @@ static CXLRetCode cmd_dcd_add_dyn_cap_rsp(const struct cxl_cmd *cmd, } if (in->num_entries_updated == 0) { - cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending); + num = cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending); + ct3d->dc.total_extent_count -= num; return CXL_MBOX_SUCCESS; } @@ -3051,10 +3064,12 @@ 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; + ct3d->dc.nr_extents_accepted += 1; ct3_set_region_block_backed(ct3d, dpa, len); } /* Remove the first extent group in the pending list */ - cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending); + num = cxl_extent_group_list_delete_front(&ct3d->dc.extents_pending); + ct3d->dc.total_extent_count -= num; return CXL_MBOX_SUCCESS; } @@ -3160,7 +3175,7 @@ free_and_exit: } *updated_list_size = 0; } else { - *updated_list_size = ct3d->dc.total_extent_count + cnt_delta; + *updated_list_size = ct3d->dc.nr_extents_accepted + cnt_delta; } return ret; @@ -3222,11 +3237,495 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd, ct3_set_region_block_backed(ct3d, ent->start_dpa, ent->len); cxl_remove_extent_from_extent_list(&updated_list, ent); } - ct3d->dc.total_extent_count = updated_list_size; + ct3d->dc.total_extent_count += (updated_list_size - + ct3d->dc.nr_extents_accepted); + + ct3d->dc.nr_extents_accepted = updated_list_size; + + return CXL_MBOX_SUCCESS; +} + +/* CXL r3.2 section 7.6.7.6.1: Get DCD Info (Opcode 5600h) */ +static CXLRetCode cmd_fm_get_dcd_info(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint8_t num_hosts; + uint8_t num_regions_supported; + uint8_t rsvd1[2]; + uint16_t supported_add_sel_policy_bitmask; + uint8_t rsvd2[2]; + uint16_t supported_removal_policy_bitmask; + uint8_t sanitize_on_release_bitmask; + uint8_t rsvd3; + uint64_t total_dynamic_capacity; + uint64_t region_blk_size_bitmasks[8]; + } QEMU_PACKED *out = (void *)payload_out; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + CXLDCRegion *region; + int i; + + out->num_hosts = 1; + out->num_regions_supported = ct3d->dc.num_regions; + stw_le_p(&out->supported_add_sel_policy_bitmask, + BIT(CXL_EXTENT_SELECTION_POLICY_PRESCRIPTIVE)); + stw_le_p(&out->supported_removal_policy_bitmask, + BIT(CXL_EXTENT_REMOVAL_POLICY_PRESCRIPTIVE)); + out->sanitize_on_release_bitmask = 0; + + stq_le_p(&out->total_dynamic_capacity, + ct3d->dc.total_capacity / CXL_CAPACITY_MULTIPLIER); + + for (i = 0; i < ct3d->dc.num_regions; i++) { + region = &ct3d->dc.regions[i]; + memcpy(&out->region_blk_size_bitmasks[i], + ®ion->supported_blk_size_bitmask, + sizeof(out->region_blk_size_bitmasks[i])); + } + + *len_out = sizeof(*out); + return CXL_MBOX_SUCCESS; +} + +static void build_dsmas_flags(uint8_t *flags, CXLDCRegion *region) +{ + *flags = 0; + + if (region->nonvolatile) { + *flags |= BIT(CXL_DSMAS_FLAGS_NONVOLATILE); + } + if (region->sharable) { + *flags |= BIT(CXL_DSMAS_FLAGS_SHARABLE); + } + if (region->hw_managed_coherency) { + *flags |= BIT(CXL_DSMAS_FLAGS_HW_MANAGED_COHERENCY); + } + if (region->ic_specific_dc_management) { + *flags |= BIT(CXL_DSMAS_FLAGS_IC_SPECIFIC_DC_MANAGEMENT); + } + if (region->rdonly) { + *flags |= BIT(CXL_DSMAS_FLAGS_RDONLY); + } +} + +/* + * CXL r3.2 section 7.6.7.6.2: + * Get Host DC Region Configuration (Opcode 5601h) + */ +static CXLRetCode cmd_fm_get_host_dc_region_config(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint16_t host_id; + uint8_t region_cnt; + uint8_t start_rid; + } QEMU_PACKED *in = (void *)payload_in; + struct { + uint16_t host_id; + uint8_t num_regions; + uint8_t regions_returned; + struct { + uint64_t base; + uint64_t decode_len; + uint64_t region_len; + uint64_t block_size; + uint8_t flags; + uint8_t rsvd1[3]; + uint8_t sanitize; + uint8_t rsvd2[3]; + } QEMU_PACKED records[]; + } QEMU_PACKED *out = (void *)payload_out; + struct { + uint32_t num_extents_supported; + uint32_t num_extents_available; + uint32_t num_tags_supported; + uint32_t num_tags_available; + } QEMU_PACKED *extra_out; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + uint16_t record_count, out_pl_len, i; + + if (in->start_rid >= ct3d->dc.num_regions) { + return CXL_MBOX_INVALID_INPUT; + } + record_count = MIN(ct3d->dc.num_regions - in->start_rid, in->region_cnt); + + out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]); + extra_out = (void *)out + out_pl_len; + out_pl_len += sizeof(*extra_out); + + assert(out_pl_len <= CXL_MAILBOX_MAX_PAYLOAD_SIZE); + + stw_le_p(&out->host_id, 0); + out->num_regions = ct3d->dc.num_regions; + out->regions_returned = record_count; + + for (i = 0; i < record_count; i++) { + stq_le_p(&out->records[i].base, + ct3d->dc.regions[in->start_rid + i].base); + stq_le_p(&out->records[i].decode_len, + ct3d->dc.regions[in->start_rid + i].decode_len / + CXL_CAPACITY_MULTIPLIER); + stq_le_p(&out->records[i].region_len, + ct3d->dc.regions[in->start_rid + i].len); + stq_le_p(&out->records[i].block_size, + ct3d->dc.regions[in->start_rid + i].block_size); + build_dsmas_flags(&out->records[i].flags, + &ct3d->dc.regions[in->start_rid + i]); + /* Sanitize is bit 0 of flags. */ + out->records[i].sanitize = + ct3d->dc.regions[in->start_rid + i].flags & BIT(0); + } + + stl_le_p(&extra_out->num_extents_supported, CXL_NUM_EXTENTS_SUPPORTED); + stl_le_p(&extra_out->num_extents_available, CXL_NUM_EXTENTS_SUPPORTED - + ct3d->dc.total_extent_count); + stl_le_p(&extra_out->num_tags_supported, CXL_NUM_TAGS_SUPPORTED); + stl_le_p(&extra_out->num_tags_available, CXL_NUM_TAGS_SUPPORTED); + + *len_out = out_pl_len; + return CXL_MBOX_SUCCESS; +} + +/* CXL r3.2 section 7.6.7.6.3: Set Host DC Region Configuration (Opcode 5602) */ +static CXLRetCode cmd_fm_set_dc_region_config(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint8_t reg_id; + uint8_t rsvd[3]; + uint64_t block_sz; + uint8_t flags; + uint8_t rsvd2[3]; + } QEMU_PACKED *in = (void *)payload_in; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + CXLEventDynamicCapacity dcEvent = {}; + CXLDCRegion *region = &ct3d->dc.regions[in->reg_id]; + + /* + * CXL r3.2 7.6.7.6.3: Set DC Region Configuration + * This command shall fail with Unsupported when the Sanitize on Release + * field does not match the region’s configuration... and the device + * does not support reconfiguration of the Sanitize on Release setting. + * + * Currently not reconfigurable, so always fail if sanitize bit (bit 0) + * doesn't match. + */ + if ((in->flags & 0x1) != (region->flags & 0x1)) { + return CXL_MBOX_UNSUPPORTED; + } + + if (in->reg_id >= DCD_MAX_NUM_REGION) { + return CXL_MBOX_UNSUPPORTED; + } + + /* Check that no extents are in the region being reconfigured */ + if (!bitmap_empty(region->blk_bitmap, region->len / region->block_size)) { + return CXL_MBOX_UNSUPPORTED; + } + + /* Check that new block size is supported */ + if (!is_power_of_2(in->block_sz) || + !(in->block_sz & region->supported_blk_size_bitmask)) { + return CXL_MBOX_INVALID_INPUT; + } + + /* Return success if new block size == current block size */ + if (in->block_sz == region->block_size) { + return CXL_MBOX_SUCCESS; + } + + /* Free bitmap and create new one for new block size. */ + qemu_mutex_lock(®ion->bitmap_lock); + g_free(region->blk_bitmap); + region->blk_bitmap = bitmap_new(region->len / in->block_sz); + qemu_mutex_unlock(®ion->bitmap_lock); + region->block_size = in->block_sz; + + /* Create event record and insert into event log */ + cxl_assign_event_header(&dcEvent.hdr, + &dynamic_capacity_uuid, + (1 << CXL_EVENT_TYPE_INFO), + sizeof(dcEvent), + cxl_device_get_timestamp(&ct3d->cxl_dstate)); + dcEvent.type = DC_EVENT_REGION_CONFIG_UPDATED; + dcEvent.validity_flags = 1; + dcEvent.host_id = 0; + dcEvent.updated_region_id = in->reg_id; + + if (cxl_event_insert(&ct3d->cxl_dstate, + CXL_EVENT_TYPE_DYNAMIC_CAP, + (CXLEventRecordRaw *)&dcEvent)) { + cxl_event_irq_assert(ct3d); + } + return CXL_MBOX_SUCCESS; +} + +/* CXL r3.2 section 7.6.7.6.4: Get DC Region Extent Lists (Opcode 5603h) */ +static CXLRetCode cmd_fm_get_dc_region_extent_list(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint16_t host_id; + uint8_t rsvd[2]; + uint32_t extent_cnt; + uint32_t start_extent_id; + } QEMU_PACKED *in = (void *)payload_in; + struct { + uint16_t host_id; + uint8_t rsvd[2]; + uint32_t start_extent_id; + uint32_t extents_returned; + uint32_t total_extents; + uint32_t list_generation_num; + uint8_t rsvd2[4]; + CXLDCExtentRaw records[]; + } QEMU_PACKED *out = (void *)payload_out; + QEMU_BUILD_BUG_ON(sizeof(*in) != 0xc); + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + CXLDCExtent *ent; + CXLDCExtentRaw *out_rec; + uint16_t record_count = 0, record_done = 0, i = 0; + uint16_t out_pl_len, max_size; + + if (in->host_id != 0) { + return CXL_MBOX_INVALID_INPUT; + } + + if (in->start_extent_id > ct3d->dc.nr_extents_accepted) { + return CXL_MBOX_INVALID_INPUT; + } + record_count = MIN(in->extent_cnt, + ct3d->dc.nr_extents_accepted - in->start_extent_id); + max_size = CXL_MAILBOX_MAX_PAYLOAD_SIZE - sizeof(*out); + record_count = MIN(record_count, max_size / sizeof(out->records[0])); + out_pl_len = sizeof(*out) + record_count * sizeof(out->records[0]); + + stw_le_p(&out->host_id, in->host_id); + stl_le_p(&out->start_extent_id, in->start_extent_id); + stl_le_p(&out->extents_returned, record_count); + stl_le_p(&out->total_extents, ct3d->dc.nr_extents_accepted); + stl_le_p(&out->list_generation_num, ct3d->dc.ext_list_gen_seq); + + if (record_count > 0) { + QTAILQ_FOREACH(ent, &ct3d->dc.extents, node) { + if (i++ < in->start_extent_id) { + continue; + } + out_rec = &out->records[record_done]; + stq_le_p(&out_rec->start_dpa, ent->start_dpa); + stq_le_p(&out_rec->len, ent->len); + memcpy(&out_rec->tag, ent->tag, 0x10); + stw_le_p(&out_rec->shared_seq, ent->shared_seq); + + record_done++; + if (record_done == record_count) { + break; + } + } + } + + *len_out = out_pl_len; return CXL_MBOX_SUCCESS; } +/* + * Helper function to convert CXLDCExtentRaw to CXLUpdateDCExtentListInPl + * in order to reuse cxl_detect_malformed_extent_list() function which accepts + * CXLUpdateDCExtentListInPl as a parameter. + */ +static void convert_raw_extents(CXLDCExtentRaw raw_extents[], + CXLUpdateDCExtentListInPl *extent_list, + int count) +{ + int i; + + extent_list->num_entries_updated = count; + + for (i = 0; i < count; i++) { + extent_list->updated_entries[i].start_dpa = raw_extents[i].start_dpa; + extent_list->updated_entries[i].len = raw_extents[i].len; + } +} + +/* CXL r3.2 Section 7.6.7.6.5: Initiate Dynamic Capacity Add (Opcode 5604h) */ +static CXLRetCode cmd_fm_initiate_dc_add(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint16_t host_id; + uint8_t selection_policy; + uint8_t reg_num; + uint64_t length; + uint8_t tag[0x10]; + uint32_t ext_count; + CXLDCExtentRaw extents[]; + } QEMU_PACKED *in = (void *)payload_in; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + int i, rc; + + switch (in->selection_policy) { + case CXL_EXTENT_SELECTION_POLICY_PRESCRIPTIVE: { + /* Adding extents exceeds device's extent tracking ability. */ + if (in->ext_count + ct3d->dc.total_extent_count > + CXL_NUM_EXTENTS_SUPPORTED) { + return CXL_MBOX_RESOURCES_EXHAUSTED; + } + + g_autofree CXLUpdateDCExtentListInPl *list = + g_malloc0(sizeof(*list) + + in->ext_count * sizeof(*list->updated_entries)); + + convert_raw_extents(in->extents, list, in->ext_count); + rc = cxl_detect_malformed_extent_list(ct3d, list); + + for (i = 0; i < in->ext_count; i++) { + CXLDCExtentRaw *ext = &in->extents[i]; + + /* Check requested extents do not overlap with pending ones. */ + if (cxl_extent_groups_overlaps_dpa_range(&ct3d->dc.extents_pending, + ext->start_dpa, + ext->len)) { + return CXL_MBOX_INVALID_EXTENT_LIST; + } + /* Check requested extents do not overlap with existing ones. */ + if (cxl_extents_overlaps_dpa_range(&ct3d->dc.extents, + ext->start_dpa, + ext->len)) { + return CXL_MBOX_INVALID_EXTENT_LIST; + } + } + + if (rc) { + return rc; + } + + CXLDCExtentGroup *group = NULL; + for (i = 0; i < in->ext_count; i++) { + CXLDCExtentRaw *ext = &in->extents[i]; + + group = cxl_insert_extent_to_extent_group(group, ext->start_dpa, + ext->len, ext->tag, + ext->shared_seq); + } + + cxl_extent_group_list_insert_tail(&ct3d->dc.extents_pending, group); + ct3d->dc.total_extent_count += in->ext_count; + cxl_create_dc_event_records_for_extents(ct3d, + DC_EVENT_ADD_CAPACITY, + in->extents, + in->ext_count); + + return CXL_MBOX_SUCCESS; + } + default: { + qemu_log_mask(LOG_UNIMP, + "CXL extent selection policy not supported.\n"); + return CXL_MBOX_INVALID_INPUT; + } + } +} + +#define CXL_EXTENT_REMOVAL_POLICY_MASK 0x0F +#define CXL_FORCED_REMOVAL_MASK (1 << 4) +/* + * CXL r3.2 Section 7.6.7.6.6: + * Initiate Dynamic Capacity Release (Opcode 5605h) + */ +static CXLRetCode cmd_fm_initiate_dc_release(const struct cxl_cmd *cmd, + uint8_t *payload_in, + size_t len_in, + uint8_t *payload_out, + size_t *len_out, + CXLCCI *cci) +{ + struct { + uint16_t host_id; + uint8_t flags; + uint8_t reg_num; + uint64_t length; + uint8_t tag[0x10]; + uint32_t ext_count; + CXLDCExtentRaw extents[]; + } QEMU_PACKED *in = (void *)payload_in; + CXLType3Dev *ct3d = CXL_TYPE3(cci->d); + int i, rc; + + switch (in->flags & CXL_EXTENT_REMOVAL_POLICY_MASK) { + case CXL_EXTENT_REMOVAL_POLICY_PRESCRIPTIVE: { + CXLDCExtentList updated_list; + uint32_t updated_list_size; + g_autofree CXLUpdateDCExtentListInPl *list = + g_malloc0(sizeof(*list) + + in->ext_count * sizeof(*list->updated_entries)); + + convert_raw_extents(in->extents, list, in->ext_count); + rc = cxl_detect_malformed_extent_list(ct3d, list); + if (rc) { + return rc; + } + + /* + * Fail with Invalid PA if an extent is pending and Forced Removal + * flag not set. + */ + if (!(in->flags & CXL_FORCED_REMOVAL_MASK)) { + for (i = 0; i < in->ext_count; i++) { + CXLDCExtentRaw ext = in->extents[i]; + /* + * Check requested extents don't overlap with pending + * extents. + */ + if (cxl_extent_groups_overlaps_dpa_range( + &ct3d->dc.extents_pending, + ext.start_dpa, + ext.len)) { + return CXL_MBOX_INVALID_PA; + } + } + } + + rc = cxl_dc_extent_release_dry_run(ct3d, + list, + &updated_list, + &updated_list_size); + if (rc) { + return rc; + } + cxl_create_dc_event_records_for_extents(ct3d, + DC_EVENT_RELEASE_CAPACITY, + in->extents, + in->ext_count); + return CXL_MBOX_SUCCESS; + } + default: { + qemu_log_mask(LOG_UNIMP, + "CXL extent removal policy not supported.\n"); + return CXL_MBOX_INVALID_INPUT; + } + } +} + static const struct cxl_cmd cxl_cmd_set[256][256] = { [INFOSTAT][BACKGROUND_OPERATION_ABORT] = { "BACKGROUND_OPERATION_ABORT", cmd_infostat_bg_op_abort, 0, 0 }, @@ -3340,6 +3839,36 @@ static const struct cxl_cmd cxl_cmd_set_sw[256][256] = { cmd_tunnel_management_cmd, ~0, 0 }, }; +static const struct cxl_cmd cxl_cmd_set_fm_dcd[256][256] = { + [FMAPI_DCD_MGMT][GET_DCD_INFO] = { "GET_DCD_INFO", + cmd_fm_get_dcd_info, 0, 0 }, + [FMAPI_DCD_MGMT][GET_HOST_DC_REGION_CONFIG] = { "GET_HOST_DC_REGION_CONFIG", + cmd_fm_get_host_dc_region_config, 4, 0 }, + [FMAPI_DCD_MGMT][SET_DC_REGION_CONFIG] = { "SET_DC_REGION_CONFIG", + cmd_fm_set_dc_region_config, 16, + (CXL_MBOX_CONFIG_CHANGE_COLD_RESET | + CXL_MBOX_CONFIG_CHANGE_CONV_RESET | + CXL_MBOX_CONFIG_CHANGE_CXL_RESET | + CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | + CXL_MBOX_IMMEDIATE_DATA_CHANGE) }, + [FMAPI_DCD_MGMT][GET_DC_REGION_EXTENT_LIST] = { "GET_DC_REGION_EXTENT_LIST", + cmd_fm_get_dc_region_extent_list, 12, 0 }, + [FMAPI_DCD_MGMT][INITIATE_DC_ADD] = { "INIT_DC_ADD", + cmd_fm_initiate_dc_add, ~0, + (CXL_MBOX_CONFIG_CHANGE_COLD_RESET | + CXL_MBOX_CONFIG_CHANGE_CONV_RESET | + CXL_MBOX_CONFIG_CHANGE_CXL_RESET | + CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | + CXL_MBOX_IMMEDIATE_DATA_CHANGE) }, + [FMAPI_DCD_MGMT][INITIATE_DC_RELEASE] = { "INIT_DC_RELEASE", + cmd_fm_initiate_dc_release, ~0, + (CXL_MBOX_CONFIG_CHANGE_COLD_RESET | + CXL_MBOX_CONFIG_CHANGE_CONV_RESET | + CXL_MBOX_CONFIG_CHANGE_CXL_RESET | + CXL_MBOX_IMMEDIATE_CONFIG_CHANGE | + CXL_MBOX_IMMEDIATE_DATA_CHANGE) }, +}; + /* * While the command is executing in the background, the device should * update the percentage complete in the Background Command Status Register @@ -3614,7 +4143,12 @@ void cxl_initialize_t3_fm_owned_ld_mctpcci(CXLCCI *cci, DeviceState *d, DeviceState *intf, size_t payload_max) { + CXLType3Dev *ct3d = CXL_TYPE3(d); + cxl_copy_cci_commands(cci, cxl_cmd_set_t3_fm_owned_ld_mctp); + if (ct3d->dc.num_regions) { + cxl_copy_cci_commands(cci, cxl_cmd_set_fm_dcd); + } cci->d = d; cci->intf = intf; cxl_init_cci(cci, payload_max); |