mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-08-18 07:32:06 -06:00
hw/cxl/cxl-mailbox-utils: Media operations Sanitize and Write Zeros commands CXL r3.2(8.2.10.9.5.3)
CXL spec 3.2 section 8.2.10.9.5.3 describes media operations commands. CXL devices supports media operations Sanitize and Write zero command. Signed-off-by: Vinayak Holikatti <vinayak.kh@samsung.com> Signed-off-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Message-Id: <20250305092501.191929-6-Jonathan.Cameron@huawei.com> Reviewed-by: Michael S. Tsirkin <mst@redhat.com> Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
This commit is contained in:
parent
484df0704e
commit
40ab4ed107
2 changed files with 208 additions and 0 deletions
|
@ -1715,6 +1715,131 @@ static CXLRetCode cmd_sanitize_overwrite(const struct cxl_cmd *cmd,
|
||||||
return CXL_MBOX_BG_STARTED;
|
return CXL_MBOX_BG_STARTED;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct dpa_range_list_entry {
|
||||||
|
uint64_t starting_dpa;
|
||||||
|
uint64_t length;
|
||||||
|
} QEMU_PACKED;
|
||||||
|
|
||||||
|
struct CXLSanitizeInfo {
|
||||||
|
uint32_t dpa_range_count;
|
||||||
|
uint8_t fill_value;
|
||||||
|
struct dpa_range_list_entry dpa_range_list[];
|
||||||
|
} QEMU_PACKED;
|
||||||
|
|
||||||
|
static uint64_t get_vmr_size(CXLType3Dev *ct3d, MemoryRegion **vmr)
|
||||||
|
{
|
||||||
|
MemoryRegion *mr;
|
||||||
|
if (ct3d->hostvmem) {
|
||||||
|
mr = host_memory_backend_get_memory(ct3d->hostvmem);
|
||||||
|
if (vmr) {
|
||||||
|
*vmr = mr;
|
||||||
|
}
|
||||||
|
return memory_region_size(mr);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t get_pmr_size(CXLType3Dev *ct3d, MemoryRegion **pmr)
|
||||||
|
{
|
||||||
|
MemoryRegion *mr;
|
||||||
|
if (ct3d->hostpmem) {
|
||||||
|
mr = host_memory_backend_get_memory(ct3d->hostpmem);
|
||||||
|
if (pmr) {
|
||||||
|
*pmr = mr;
|
||||||
|
}
|
||||||
|
return memory_region_size(mr);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint64_t get_dc_size(CXLType3Dev *ct3d, MemoryRegion **dc_mr)
|
||||||
|
{
|
||||||
|
MemoryRegion *mr;
|
||||||
|
if (ct3d->dc.host_dc) {
|
||||||
|
mr = host_memory_backend_get_memory(ct3d->dc.host_dc);
|
||||||
|
if (dc_mr) {
|
||||||
|
*dc_mr = mr;
|
||||||
|
}
|
||||||
|
return memory_region_size(mr);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int validate_dpa_addr(CXLType3Dev *ct3d, uint64_t dpa_addr,
|
||||||
|
size_t length)
|
||||||
|
{
|
||||||
|
uint64_t vmr_size, pmr_size, dc_size;
|
||||||
|
|
||||||
|
if ((dpa_addr % CXL_CACHE_LINE_SIZE) ||
|
||||||
|
(length % CXL_CACHE_LINE_SIZE) ||
|
||||||
|
(length <= 0)) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
vmr_size = get_vmr_size(ct3d, NULL);
|
||||||
|
pmr_size = get_pmr_size(ct3d, NULL);
|
||||||
|
dc_size = get_dc_size(ct3d, NULL);
|
||||||
|
|
||||||
|
if (dpa_addr + length > vmr_size + pmr_size + dc_size) {
|
||||||
|
return -EINVAL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (dpa_addr > vmr_size + pmr_size) {
|
||||||
|
if (!ct3_test_region_block_backed(ct3d, dpa_addr, length)) {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int sanitize_range(CXLType3Dev *ct3d, uint64_t dpa_addr, size_t length,
|
||||||
|
uint8_t fill_value)
|
||||||
|
{
|
||||||
|
|
||||||
|
uint64_t vmr_size, pmr_size;
|
||||||
|
AddressSpace *as = NULL;
|
||||||
|
MemTxAttrs mem_attrs = {};
|
||||||
|
|
||||||
|
vmr_size = get_vmr_size(ct3d, NULL);
|
||||||
|
pmr_size = get_pmr_size(ct3d, NULL);
|
||||||
|
|
||||||
|
if (dpa_addr < vmr_size) {
|
||||||
|
as = &ct3d->hostvmem_as;
|
||||||
|
} else if (dpa_addr < vmr_size + pmr_size) {
|
||||||
|
as = &ct3d->hostpmem_as;
|
||||||
|
} else {
|
||||||
|
if (!ct3_test_region_block_backed(ct3d, dpa_addr, length)) {
|
||||||
|
return -ENODEV;
|
||||||
|
}
|
||||||
|
as = &ct3d->dc.host_dc_as;
|
||||||
|
}
|
||||||
|
|
||||||
|
return address_space_set(as, dpa_addr, fill_value, length, mem_attrs);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Perform the actual device zeroing */
|
||||||
|
static void __do_sanitize(CXLType3Dev *ct3d)
|
||||||
|
{
|
||||||
|
struct CXLSanitizeInfo *san_info = ct3d->media_op_sanitize;
|
||||||
|
int dpa_range_count = san_info->dpa_range_count;
|
||||||
|
int rc = 0;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for (i = 0; i < dpa_range_count; i++) {
|
||||||
|
rc = sanitize_range(ct3d, san_info->dpa_range_list[i].starting_dpa,
|
||||||
|
san_info->dpa_range_list[i].length,
|
||||||
|
san_info->fill_value);
|
||||||
|
if (rc) {
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit:
|
||||||
|
g_free(ct3d->media_op_sanitize);
|
||||||
|
ct3d->media_op_sanitize = NULL;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
MEDIA_OP_CLASS_GENERAL = 0x0,
|
MEDIA_OP_CLASS_GENERAL = 0x0,
|
||||||
#define MEDIA_OP_GEN_SUBC_DISCOVERY 0x0
|
#define MEDIA_OP_GEN_SUBC_DISCOVERY 0x0
|
||||||
|
@ -1799,6 +1924,65 @@ static CXLRetCode media_operations_discovery(uint8_t *payload_in,
|
||||||
return CXL_MBOX_SUCCESS;
|
return CXL_MBOX_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static CXLRetCode media_operations_sanitize(CXLType3Dev *ct3d,
|
||||||
|
uint8_t *payload_in,
|
||||||
|
size_t len_in,
|
||||||
|
uint8_t *payload_out,
|
||||||
|
size_t *len_out,
|
||||||
|
uint8_t fill_value,
|
||||||
|
CXLCCI *cci)
|
||||||
|
{
|
||||||
|
struct media_operations_sanitize {
|
||||||
|
uint8_t media_operation_class;
|
||||||
|
uint8_t media_operation_subclass;
|
||||||
|
uint8_t rsvd[2];
|
||||||
|
uint32_t dpa_range_count;
|
||||||
|
struct dpa_range_list_entry dpa_range_list[];
|
||||||
|
} QEMU_PACKED *media_op_in_sanitize_pl = (void *)payload_in;
|
||||||
|
uint32_t dpa_range_count = media_op_in_sanitize_pl->dpa_range_count;
|
||||||
|
uint64_t total_mem = 0;
|
||||||
|
size_t dpa_range_list_size;
|
||||||
|
int secs = 0, i;
|
||||||
|
|
||||||
|
if (dpa_range_count == 0) {
|
||||||
|
return CXL_MBOX_SUCCESS;
|
||||||
|
}
|
||||||
|
|
||||||
|
dpa_range_list_size = dpa_range_count * sizeof(struct dpa_range_list_entry);
|
||||||
|
if (len_in < (sizeof(*media_op_in_sanitize_pl) + dpa_range_list_size)) {
|
||||||
|
return CXL_MBOX_INVALID_PAYLOAD_LENGTH;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (i = 0; i < dpa_range_count; i++) {
|
||||||
|
uint64_t start_dpa =
|
||||||
|
media_op_in_sanitize_pl->dpa_range_list[i].starting_dpa;
|
||||||
|
uint64_t length = media_op_in_sanitize_pl->dpa_range_list[i].length;
|
||||||
|
|
||||||
|
if (validate_dpa_addr(ct3d, start_dpa, length)) {
|
||||||
|
return CXL_MBOX_INVALID_INPUT;
|
||||||
|
}
|
||||||
|
total_mem += length;
|
||||||
|
}
|
||||||
|
ct3d->media_op_sanitize = g_malloc0(sizeof(struct CXLSanitizeInfo) +
|
||||||
|
dpa_range_list_size);
|
||||||
|
|
||||||
|
ct3d->media_op_sanitize->dpa_range_count = dpa_range_count;
|
||||||
|
ct3d->media_op_sanitize->fill_value = fill_value;
|
||||||
|
memcpy(ct3d->media_op_sanitize->dpa_range_list,
|
||||||
|
media_op_in_sanitize_pl->dpa_range_list,
|
||||||
|
dpa_range_list_size);
|
||||||
|
secs = get_sanitize_duration(total_mem >> 20);
|
||||||
|
|
||||||
|
/* EBUSY other bg cmds as of now */
|
||||||
|
cci->bg.runtime = secs * 1000UL;
|
||||||
|
*len_out = 0;
|
||||||
|
/*
|
||||||
|
* media op sanitize is targeted so no need to disable media or
|
||||||
|
* clear event logs
|
||||||
|
*/
|
||||||
|
return CXL_MBOX_BG_STARTED;
|
||||||
|
}
|
||||||
|
|
||||||
static CXLRetCode cmd_media_operations(const struct cxl_cmd *cmd,
|
static CXLRetCode cmd_media_operations(const struct cxl_cmd *cmd,
|
||||||
uint8_t *payload_in,
|
uint8_t *payload_in,
|
||||||
size_t len_in,
|
size_t len_in,
|
||||||
|
@ -1812,6 +1996,7 @@ static CXLRetCode cmd_media_operations(const struct cxl_cmd *cmd,
|
||||||
uint8_t rsvd[2];
|
uint8_t rsvd[2];
|
||||||
uint32_t dpa_range_count;
|
uint32_t dpa_range_count;
|
||||||
} QEMU_PACKED *media_op_in_common_pl = (void *)payload_in;
|
} QEMU_PACKED *media_op_in_common_pl = (void *)payload_in;
|
||||||
|
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
|
||||||
uint8_t media_op_cl = 0;
|
uint8_t media_op_cl = 0;
|
||||||
uint8_t media_op_subclass = 0;
|
uint8_t media_op_subclass = 0;
|
||||||
|
|
||||||
|
@ -1830,6 +2015,19 @@ static CXLRetCode cmd_media_operations(const struct cxl_cmd *cmd,
|
||||||
|
|
||||||
return media_operations_discovery(payload_in, len_in, payload_out,
|
return media_operations_discovery(payload_in, len_in, payload_out,
|
||||||
len_out);
|
len_out);
|
||||||
|
case MEDIA_OP_CLASS_SANITIZE:
|
||||||
|
switch (media_op_subclass) {
|
||||||
|
case MEDIA_OP_SAN_SUBC_SANITIZE:
|
||||||
|
return media_operations_sanitize(ct3d, payload_in, len_in,
|
||||||
|
payload_out, len_out, 0xF,
|
||||||
|
cci);
|
||||||
|
case MEDIA_OP_SAN_SUBC_ZERO:
|
||||||
|
return media_operations_sanitize(ct3d, payload_in, len_in,
|
||||||
|
payload_out, len_out, 0,
|
||||||
|
cci);
|
||||||
|
default:
|
||||||
|
return CXL_MBOX_UNSUPPORTED;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
return CXL_MBOX_UNSUPPORTED;
|
return CXL_MBOX_UNSUPPORTED;
|
||||||
}
|
}
|
||||||
|
@ -3147,6 +3345,12 @@ static void bg_timercb(void *opaque)
|
||||||
cxl_dev_enable_media(&ct3d->cxl_dstate);
|
cxl_dev_enable_media(&ct3d->cxl_dstate);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
case 0x4402: /* Media Operations sanitize */
|
||||||
|
{
|
||||||
|
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
|
||||||
|
__do_sanitize(ct3d);
|
||||||
|
}
|
||||||
|
break;
|
||||||
case 0x4304: /* scan media */
|
case 0x4304: /* scan media */
|
||||||
{
|
{
|
||||||
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
|
CXLType3Dev *ct3d = CXL_TYPE3(cci->d);
|
||||||
|
|
|
@ -540,6 +540,8 @@ typedef struct CXLSetFeatureInfo {
|
||||||
size_t data_size;
|
size_t data_size;
|
||||||
} CXLSetFeatureInfo;
|
} CXLSetFeatureInfo;
|
||||||
|
|
||||||
|
struct CXLSanitizeInfo;
|
||||||
|
|
||||||
struct CXLType3Dev {
|
struct CXLType3Dev {
|
||||||
/* Private */
|
/* Private */
|
||||||
PCIDevice parent_obj;
|
PCIDevice parent_obj;
|
||||||
|
@ -606,6 +608,8 @@ struct CXLType3Dev {
|
||||||
uint8_t num_regions; /* 0-8 regions */
|
uint8_t num_regions; /* 0-8 regions */
|
||||||
CXLDCRegion regions[DCD_MAX_NUM_REGION];
|
CXLDCRegion regions[DCD_MAX_NUM_REGION];
|
||||||
} dc;
|
} dc;
|
||||||
|
|
||||||
|
struct CXLSanitizeInfo *media_op_sanitize;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define TYPE_CXL_TYPE3 "cxl-type3"
|
#define TYPE_CXL_TYPE3 "cxl-type3"
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue