From: Manish Honap Add CXL region management for future guest access. Region Management makes use of APIs provided by CXL_CORE as below: CREATE_REGION flow: 1. Validate request (size, decoder availability) 2. Allocate HPA via cxl_get_hpa_freespace() 3. Allocate DPA via cxl_request_dpa() 4. Create region via cxl_create_region() - commits HDM decoder! 5. Get HPA range via cxl_get_region_range() DESTROY_REGION flow: 1. Detach decoder via cxl_decoder_detach() 2. Free DPA via cxl_dpa_free() 3. Release root decoder via cxl_put_root_decoder() Signed-off-by: Manish Honap --- drivers/vfio/pci/cxl/vfio_cxl_core.c | 118 ++++++++++++++++++++++++++- drivers/vfio/pci/cxl/vfio_cxl_priv.h | 5 ++ drivers/vfio/pci/vfio_pci_priv.h | 8 ++ 3 files changed, 130 insertions(+), 1 deletion(-) diff --git a/drivers/vfio/pci/cxl/vfio_cxl_core.c b/drivers/vfio/pci/cxl/vfio_cxl_core.c index 2da6da1c0605..9c71f592e74e 100644 --- a/drivers/vfio/pci/cxl/vfio_cxl_core.c +++ b/drivers/vfio/pci/cxl/vfio_cxl_core.c @@ -126,6 +126,112 @@ static int vfio_cxl_setup_regs(struct vfio_pci_core_device *vdev) return 0; } +int vfio_cxl_create_cxl_region(struct vfio_pci_core_device *vdev, resource_size_t size) +{ + struct vfio_pci_cxl_state *cxl = vdev->cxl; + resource_size_t max_size; + int ret; + + if (cxl->precommitted) + return 0; + + cxl->cxlrd = cxl_get_hpa_freespace(cxl->cxlmd, 1, + CXL_DECODER_F_RAM | + CXL_DECODER_F_TYPE2, + &max_size); + if (IS_ERR(cxl->cxlrd)) + return PTR_ERR(cxl->cxlrd); + + /* Insufficient HPA space */ + if (max_size < size) { + cxl_put_root_decoder(cxl->cxlrd); + cxl->cxlrd = NULL; + return -ENOSPC; + } + + cxl->cxled = cxl_request_dpa(cxl->cxlmd, CXL_PARTMODE_RAM, size); + if (IS_ERR(cxl->cxled)) { + ret = PTR_ERR(cxl->cxled); + goto err_free_hpa; + } + + cxl->region = cxl_create_region(cxl->cxlrd, &cxl->cxled, 1); + if (IS_ERR(cxl->region)) { + ret = PTR_ERR(cxl->region); + goto err_free_dpa; + } + + return 0; + +err_free_dpa: + cxl_dpa_free(cxl->cxled); +err_free_hpa: + if (cxl->cxlrd) + cxl_put_root_decoder(cxl->cxlrd); + + return ret; +} + +void vfio_cxl_destroy_cxl_region(struct vfio_pci_core_device *vdev) +{ + struct vfio_pci_cxl_state *cxl = vdev->cxl; + + if (!cxl->region) + return; + + cxl_unregister_region(cxl->region); + cxl->region = NULL; + + if (cxl->precommitted) + return; + + cxl_dpa_free(cxl->cxled); + cxl_put_root_decoder(cxl->cxlrd); +} + +static int vfio_cxl_create_region_helper(struct vfio_pci_core_device *vdev, + resource_size_t capacity) +{ + struct vfio_pci_cxl_state *cxl = vdev->cxl; + struct pci_dev *pdev = vdev->pdev; + int ret; + + if (cxl->precommitted) { + cxl->cxled = cxl_get_committed_decoder(cxl->cxlmd, + &cxl->region); + if (IS_ERR(cxl->cxled)) + return PTR_ERR(cxl->cxled); + } else { + ret = vfio_cxl_create_cxl_region(vdev, capacity); + if (ret) + return ret; + } + + if (cxl->region) { + struct range range; + + ret = cxl_get_region_range(cxl->region, &range); + if (ret) + goto failed; + + cxl->region_hpa = range.start; + cxl->region_size = range_len(&range); + + pci_dbg(pdev, "Precommitted decoder: HPA 0x%llx size %lu MB\n", + cxl->region_hpa, cxl->region_size >> 20); + } else { + pci_err(pdev, "Failed to create CXL region\n"); + ret = -ENODEV; + goto failed; + } + + return 0; + +failed: + vfio_cxl_destroy_cxl_region(vdev); + return ret; +} + /** * vfio_pci_cxl_detect_and_init - Detect and initialize CXL Type-2 device * @vdev: VFIO PCI device @@ -172,6 +278,12 @@ void vfio_pci_cxl_detect_and_init(struct vfio_pci_core_device *vdev) pci_disable_device(pdev); + ret = vfio_cxl_create_region_helper(vdev, SZ_256M); + if (ret) + goto failed; + + cxl->precommitted = true; + return; failed: @@ -181,6 +293,10 @@ void vfio_pci_cxl_detect_and_init(struct vfio_pci_core_device *vdev) void vfio_pci_cxl_cleanup(struct vfio_pci_core_device *vdev) { - if (!vdev->cxl) + struct vfio_pci_cxl_state *cxl = vdev->cxl; + + if (!cxl || !cxl->region) return; + + vfio_cxl_destroy_cxl_region(vdev); } diff --git a/drivers/vfio/pci/cxl/vfio_cxl_priv.h b/drivers/vfio/pci/cxl/vfio_cxl_priv.h index 57fed39a80da..985680842a13 100644 --- a/drivers/vfio/pci/cxl/vfio_cxl_priv.h +++ b/drivers/vfio/pci/cxl/vfio_cxl_priv.h @@ -17,6 +17,10 @@ struct vfio_pci_cxl_state { struct cxl_memdev *cxlmd; struct cxl_root_decoder *cxlrd; struct cxl_endpoint_decoder *cxled; + struct cxl_region *region; + resource_size_t region_hpa; + size_t region_size; + void __iomem *region_vaddr; resource_size_t hdm_reg_offset; size_t hdm_reg_size; resource_size_t comp_reg_offset; @@ -24,6 +28,7 @@ struct vfio_pci_cxl_state { u32 hdm_count; u16 dvsec; u8 comp_reg_bar; + bool precommitted; }; /* diff --git a/drivers/vfio/pci/vfio_pci_priv.h b/drivers/vfio/pci/vfio_pci_priv.h index d7df5538dcde..818d99f098bf 100644 --- a/drivers/vfio/pci/vfio_pci_priv.h +++ b/drivers/vfio/pci/vfio_pci_priv.h @@ -137,6 +137,9 @@ static inline void vfio_pci_dma_buf_move(struct vfio_pci_core_device *vdev, void vfio_pci_cxl_detect_and_init(struct vfio_pci_core_device *vdev); void vfio_pci_cxl_cleanup(struct vfio_pci_core_device *vdev); +int vfio_cxl_create_cxl_region(struct vfio_pci_core_device *vdev, + resource_size_t size); +void vfio_cxl_destroy_cxl_region(struct vfio_pci_core_device *vdev); #else @@ -144,6 +147,11 @@ static inline void vfio_pci_cxl_detect_and_init(struct vfio_pci_core_device *vdev) { } static inline void vfio_pci_cxl_cleanup(struct vfio_pci_core_device *vdev) { } +static inline int vfio_cxl_create_cxl_region(struct vfio_pci_core_device *vdev, + resource_size_t size) +{ return 0; } +static inline void +vfio_cxl_destroy_cxl_region(struct vfio_pci_core_device *vdev) { } #endif /* CONFIG_VFIO_CXL_CORE */ -- 2.25.1