hw/mem/cxl_type3: Add DPA range validation for accesses to DC regions
All DPA ranges in the DC regions are invalid to access until an extent covering the range has been successfully accepted by the host. A bitmap is added to each region to record whether a DC block in the region has been backed by a DC extent. Each bit in the bitmap represents a DC block. When a DC extent is accepted, all the bits representing the blocks in the extent are set, which will be cleared when the extent is released. Tested-by: Svetly Todorov <svetly.todorov@memverge.com> Reviewed-by: Gregory Price <gregory.price@memverge.com> Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Fan Ni <fan.ni@samsung.com> Message-Id: <20240523174651.1089554-13-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:
parent
d0b9b28a5b
commit
e4180db4e6
@ -1655,6 +1655,7 @@ 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;
|
||||
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);
|
||||
@ -1813,10 +1814,12 @@ static CXLRetCode cmd_dcd_release_dyn_cap(const struct cxl_cmd *cmd,
|
||||
* list and update the extent count;
|
||||
*/
|
||||
QTAILQ_FOREACH_SAFE(ent, &ct3d->dc.extents, node, ent_next) {
|
||||
ct3_clear_region_block_backed(ct3d, ent->start_dpa, ent->len);
|
||||
cxl_remove_extent_from_extent_list(&ct3d->dc.extents, ent);
|
||||
}
|
||||
copy_extent_list(&ct3d->dc.extents, &updated_list);
|
||||
QTAILQ_FOREACH_SAFE(ent, &updated_list, node, ent_next) {
|
||||
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;
|
||||
|
@ -672,6 +672,7 @@ static bool cxl_create_dc_regions(CXLType3Dev *ct3d, Error **errp)
|
||||
.flags = 0,
|
||||
};
|
||||
ct3d->dc.total_capacity += region->len;
|
||||
region->blk_bitmap = bitmap_new(region->len / region->block_size);
|
||||
}
|
||||
QTAILQ_INIT(&ct3d->dc.extents);
|
||||
QTAILQ_INIT(&ct3d->dc.extents_pending);
|
||||
@ -683,6 +684,8 @@ static void cxl_destroy_dc_regions(CXLType3Dev *ct3d)
|
||||
{
|
||||
CXLDCExtent *ent, *ent_next;
|
||||
CXLDCExtentGroup *group, *group_next;
|
||||
int i;
|
||||
CXLDCRegion *region;
|
||||
|
||||
QTAILQ_FOREACH_SAFE(ent, &ct3d->dc.extents, node, ent_next) {
|
||||
cxl_remove_extent_from_extent_list(&ct3d->dc.extents, ent);
|
||||
@ -695,6 +698,11 @@ static void cxl_destroy_dc_regions(CXLType3Dev *ct3d)
|
||||
}
|
||||
g_free(group);
|
||||
}
|
||||
|
||||
for (i = 0; i < ct3d->dc.num_regions; i++) {
|
||||
region = &ct3d->dc.regions[i];
|
||||
g_free(region->blk_bitmap);
|
||||
}
|
||||
}
|
||||
|
||||
static bool cxl_setup_memory(CXLType3Dev *ct3d, Error **errp)
|
||||
@ -926,6 +934,70 @@ static void ct3_exit(PCIDevice *pci_dev)
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the DPA range [dpa, dap + len - 1] to be backed and accessible. This
|
||||
* happens when a DC extent is added and accepted by the host.
|
||||
*/
|
||||
void ct3_set_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
|
||||
uint64_t len)
|
||||
{
|
||||
CXLDCRegion *region;
|
||||
|
||||
region = cxl_find_dc_region(ct3d, dpa, len);
|
||||
if (!region) {
|
||||
return;
|
||||
}
|
||||
|
||||
bitmap_set(region->blk_bitmap, (dpa - region->base) / region->block_size,
|
||||
len / region->block_size);
|
||||
}
|
||||
|
||||
/*
|
||||
* Check whether the DPA range [dpa, dpa + len - 1] is backed with DC extents.
|
||||
* Used when validating read/write to dc regions
|
||||
*/
|
||||
bool ct3_test_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
|
||||
uint64_t len)
|
||||
{
|
||||
CXLDCRegion *region;
|
||||
uint64_t nbits;
|
||||
long nr;
|
||||
|
||||
region = cxl_find_dc_region(ct3d, dpa, len);
|
||||
if (!region) {
|
||||
return false;
|
||||
}
|
||||
|
||||
nr = (dpa - region->base) / region->block_size;
|
||||
nbits = DIV_ROUND_UP(len, region->block_size);
|
||||
/*
|
||||
* if bits between [dpa, dpa + len) are all 1s, meaning the DPA range is
|
||||
* backed with DC extents, return true; else return false.
|
||||
*/
|
||||
return find_next_zero_bit(region->blk_bitmap, nr + nbits, nr) == nr + nbits;
|
||||
}
|
||||
|
||||
/*
|
||||
* Mark the DPA range [dpa, dap + len - 1] to be unbacked and inaccessible.
|
||||
* This happens when a dc extent is released by the host.
|
||||
*/
|
||||
void ct3_clear_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
|
||||
uint64_t len)
|
||||
{
|
||||
CXLDCRegion *region;
|
||||
uint64_t nbits;
|
||||
long nr;
|
||||
|
||||
region = cxl_find_dc_region(ct3d, dpa, len);
|
||||
if (!region) {
|
||||
return;
|
||||
}
|
||||
|
||||
nr = (dpa - region->base) / region->block_size;
|
||||
nbits = len / region->block_size;
|
||||
bitmap_clear(region->blk_bitmap, nr, nbits);
|
||||
}
|
||||
|
||||
static bool cxl_type3_dpa(CXLType3Dev *ct3d, hwaddr host_addr, uint64_t *dpa)
|
||||
{
|
||||
int hdm_inc = R_CXL_HDM_DECODER1_BASE_LO - R_CXL_HDM_DECODER0_BASE_LO;
|
||||
@ -1030,6 +1102,10 @@ static int cxl_type3_hpa_to_as_and_dpa(CXLType3Dev *ct3d,
|
||||
*as = &ct3d->hostpmem_as;
|
||||
*dpa_offset -= vmr_size;
|
||||
} else {
|
||||
if (!ct3_test_region_block_backed(ct3d, *dpa_offset, size)) {
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
*as = &ct3d->dc.host_dc_as;
|
||||
*dpa_offset -= (vmr_size + pmr_size);
|
||||
}
|
||||
|
@ -456,6 +456,7 @@ typedef struct CXLDCRegion {
|
||||
uint64_t block_size;
|
||||
uint32_t dsmadhandle;
|
||||
uint8_t flags;
|
||||
unsigned long *blk_bitmap;
|
||||
} CXLDCRegion;
|
||||
|
||||
struct CXLType3Dev {
|
||||
@ -577,4 +578,10 @@ CXLDCExtentGroup *cxl_insert_extent_to_extent_group(CXLDCExtentGroup *group,
|
||||
void cxl_extent_group_list_insert_tail(CXLDCExtentGroupList *list,
|
||||
CXLDCExtentGroup *group);
|
||||
void cxl_extent_group_list_delete_front(CXLDCExtentGroupList *list);
|
||||
void ct3_set_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
|
||||
uint64_t len);
|
||||
void ct3_clear_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
|
||||
uint64_t len);
|
||||
bool ct3_test_region_block_backed(CXLType3Dev *ct3d, uint64_t dpa,
|
||||
uint64_t len);
|
||||
#endif
|
||||
|
Loading…
x
Reference in New Issue
Block a user