From: Manish Honap <mhonap@nvidia.com>
The Register Locator DVSEC (CXL 4.0 8.1.9) describes register blocks
by BAR index (BIR) and offset within the BAR. CXL core currently only
stores the resolved HPA (resource + offset) in struct cxl_register_map,
so callers that need to use pci_iomap() or report the BAR to userspace
must reverse-engineer the BAR from the HPA.
Add bar_index and bar_offset to struct cxl_register_map and fill them
in cxl_decode_regblock() when the regblock is BAR-backed (BIR 0-5).
Add cxl_regblock_get_bar_info() so callers (e.g. vfio-cxl) can get BAR
index and offset directly and use pci_iomap() instead of ioremap(HPA).
Add cxl_regblock_get_bar_info() to return those fields; -EINVAL if
the map is not BAR-backed.
Signed-off-by: Manish Honap <mhonap@nvidia.com>
---
drivers/cxl/core/regs.c | 29 +++++++++++++++++++++++++++++
include/cxl/cxl.h | 15 +++++++++++++++
2 files changed, 44 insertions(+)
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index e828df0629d0..43661e51230a 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -288,9 +288,37 @@ static bool cxl_decode_regblock(struct pci_dev *pdev, u32 reg_lo, u32 reg_hi,
map->reg_type = reg_type;
map->resource = pci_resource_start(pdev, bar) + offset;
map->max_size = pci_resource_len(pdev, bar) - offset;
+ map->bar_index = bar;
+ map->bar_offset = offset;
return true;
}
+/**
+ * cxl_regblock_get_bar_info() - Get BAR index and offset for a BAR-backed
+ * regblock
+ * @map: Register map from cxl_find_regblock() or cxl_find_regblock_instance()
+ * @bar_index: Output BAR index (0-5). Optional, may be NULL.
+ * @bar_offset: Output offset within the BAR. Optional, may be NULL.
+ *
+ * When the register block was found via the Register Locator DVSEC and
+ * lives in a PCI BAR (BIR 0-5), this returns the BAR index and the offset
+ * within that BAR.
+ *
+ * Return: 0 if the regblock is BAR-backed (bar_index <= 5), -EINVAL otherwise.
+ */
+int cxl_regblock_get_bar_info(const struct cxl_register_map *map, u8 *bar_index,
+ resource_size_t *bar_offset)
+{
+ if (!map || map->bar_index == 0xff)
+ return -EINVAL;
+ if (bar_index)
+ *bar_index = map->bar_index;
+ if (bar_offset)
+ *bar_offset = map->bar_offset;
+ return 0;
+}
+EXPORT_SYMBOL_NS_GPL(cxl_regblock_get_bar_info, "CXL");
+
/*
* __cxl_find_regblock_instance() - Locate a register block or count instances by type / index
* Use CXL_INSTANCES_COUNT for @index if counting instances.
@@ -309,6 +337,7 @@ static int __cxl_find_regblock_instance(struct pci_dev *pdev, enum cxl_regloc_ty
*map = (struct cxl_register_map) {
.host = &pdev->dev,
+ .bar_index = 0xFF,
.resource = CXL_RESOURCE_NONE,
};
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 45d911735883..52eb40352edc 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -106,9 +106,16 @@ struct cxl_pmu_reg_map {
* @resource: physical resource base of the register block
* @max_size: maximum mapping size to perform register search
* @reg_type: see enum cxl_regloc_type
+ * @bar_index: PCI BAR index (0-5) when regblock is BAR-backed; 0xFF otherwise
+ * @bar_offset: offset within the BAR; only valid when bar_index <= 5
* @component_map: cxl_reg_map for component registers
* @device_map: cxl_reg_maps for device registers
* @pmu_map: cxl_reg_maps for CXL Performance Monitoring Units
+ *
+ * When the register block is described by the Register Locator DVSEC with
+ * a BAR Indicator (BIR 0-5), bar_index and bar_offset are set so callers can
+ * use pci_iomap(pdev, bar_index, size) and base + bar_offset instead of
+ * ioremap(resource).
*/
struct cxl_register_map {
struct device *host;
@@ -116,6 +123,8 @@ struct cxl_register_map {
resource_size_t resource;
resource_size_t max_size;
u8 reg_type;
+ u8 bar_index;
+ resource_size_t bar_offset;
union {
struct cxl_component_reg_map component_map;
struct cxl_device_reg_map device_map;
@@ -300,6 +309,8 @@ int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
void cxl_probe_component_regs(struct device *dev, void __iomem *base,
struct cxl_component_reg_map *map);
int cxl_await_range_active(struct cxl_dev_state *cxlds);
+int cxl_regblock_get_bar_info(const struct cxl_register_map *map, u8 *bar_index,
+ resource_size_t *bar_offset);
#else
@@ -317,6 +328,10 @@ cxl_probe_component_regs(struct device *dev, void __iomem *base,
{ }
static inline int cxl_await_range_active(struct cxl_dev_state *cxlds)
{ return -EOPNOTSUPP; }
+static inline int
+cxl_regblock_get_bar_info(const struct cxl_register_map *map, u8 *bar_index,
+ resource_size_t *bar_offset)
+{ return -EINVAL; }
#endif /* CONFIG_CXL_BUS */
--
2.25.1