From: Manish Honap CXL core has the information of what CXL register groups a device has. When initializing the device, the CXL core probes the register groups and saves the information. The probing sequence is quite complicated. vfio-cxl requires the HDM register information to emulate the HDM decoder registers. Introduce cxl_get_hdm_reg_info() for vfio-cxl to leverage the HDM register information in the CXL core. Thus, it doesn't need to implement its own probing sequence. Co-developed-by: Zhi Wang Signed-off-by: Zhi Wang Signed-off-by: Manish Honap --- drivers/cxl/core/pci.c | 45 ++++++++++++++++++++++++++++++++++++++++++ include/cxl/cxl.h | 3 +++ 2 files changed, 48 insertions(+) diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c index ba2d393c540a..52ed0b4f5e78 100644 --- a/drivers/cxl/core/pci.c +++ b/drivers/cxl/core/pci.c @@ -449,6 +449,51 @@ int cxl_hdm_decode_init(struct cxl_dev_state *cxlds, struct cxl_hdm *cxlhdm, } EXPORT_SYMBOL_NS_GPL(cxl_hdm_decode_init, "CXL"); +/** + * cxl_get_hdm_reg_info - Get HDM decoder register block location and count + * @cxlds: CXL device state (must have component regs enumerated) + * @count: Output: number of HDM decoders (from DVSEC cap). Only set when + * the device has a valid HDM decoder capability. + * @offset: Output: byte offset of the HDM decoder register block within the + * component register BAR. Only set when valid. + * @size: Output: size in bytes of the HDM decoder register block. Only set + * when valid. + * + * Reads the CXL component register map and DVSEC capability to return the + * Host Managed Device Memory (HDM) decoder register block offset and size, + * and the number of HDM decoders. This function requires cxlds->cxl_dvsec + * to be non-zero. + * + * Return: 0 on success. A negative errno is returned when config read + * failure or when the decoder registers are not valid. + */ +int cxl_get_hdm_reg_info(struct cxl_dev_state *cxlds, u32 *count, + resource_size_t *offset, resource_size_t *size) +{ + struct pci_dev *pdev = to_pci_dev(cxlds->dev); + struct cxl_component_reg_map *map = + &cxlds->reg_map.component_map; + int d = cxlds->cxl_dvsec; + u16 cap; + int rc; + + /* HDM decoder registers not implemented */ + if (!map->hdm_decoder.valid || !d) + return -ENODEV; + + rc = pci_read_config_word(pdev, + d + PCI_DVSEC_CXL_CAP, &cap); + if (rc) + return rc; + + *count = FIELD_GET(PCI_DVSEC_CXL_HDM_COUNT, cap); + *offset = map->hdm_decoder.offset; + *size = map->hdm_decoder.size; + + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_get_hdm_reg_info, "CXL"); + #define CXL_DOE_TABLE_ACCESS_REQ_CODE 0x000000ff #define CXL_DOE_TABLE_ACCESS_REQ_CODE_READ 0 #define CXL_DOE_TABLE_ACCESS_TABLE_TYPE 0x0000ff00 diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h index 50acbd13bcf8..8456177b523e 100644 --- a/include/cxl/cxl.h +++ b/include/cxl/cxl.h @@ -284,4 +284,7 @@ int cxl_dpa_free(struct cxl_endpoint_decoder *cxled); struct cxl_region *cxl_create_region(struct cxl_root_decoder *cxlrd, struct cxl_endpoint_decoder **cxled, int ways); + +int cxl_get_hdm_reg_info(struct cxl_dev_state *cxlds, u32 *count, + resource_size_t *offset, resource_size_t *size); #endif /* __CXL_CXL_H__ */ -- 2.25.1