From: Manish Honap <[email protected]>

The Register Locator DVSEC (CXL r4.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 pci_iomap() or want to 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 cxl drivers
(vfio-cxl, in-kernel accelerator drivers) can read the values
without touching the struct internals.  Export under the CXL
namespace.

Signed-off-by: Manish Honap <[email protected]>
---
 drivers/cxl/core/pci.c  |  2 ++
 drivers/cxl/core/regs.c | 34 ++++++++++++++++++++++++++++++++++
 include/cxl/cxl.h       | 12 ++++++++++++
 3 files changed, 48 insertions(+)

diff --git a/drivers/cxl/core/pci.c b/drivers/cxl/core/pci.c
index c44595447bd8..9b9b17db9ee4 100644
--- a/drivers/cxl/core/pci.c
+++ b/drivers/cxl/core/pci.c
@@ -764,6 +764,8 @@ static int cxl_rcrb_get_comp_regs(struct pci_dev *pdev,
        *map = (struct cxl_register_map) {
                .host = &pdev->dev,
                .resource = CXL_RESOURCE_NONE,
+               .bar_index = 0xff,
+               .bar_offset = 0,
        };
 
        component_reg_phys = cxl_rcd_component_reg_phys(&pdev->dev, dport);
diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index e828df0629d0..6af5739aa776 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -285,12 +285,46 @@ static bool cxl_decode_regblock(struct pci_dev *pdev, u32 
reg_lo, u32 reg_hi,
                return false;
        }
 
+       if (bar >= 0 && bar <= 5) {
+               map->bar_index = (u8)bar;
+               map->bar_offset = offset;
+       } else {
+               map->bar_index = 0xff;
+               map->bar_offset = 0;
+       }
+
        map->reg_type = reg_type;
        map->resource = pci_resource_start(pdev, bar) + offset;
        map->max_size = pci_resource_len(pdev, bar) - offset;
        return true;
 }
 
+/**
+ * cxl_regblock_get_bar_info - read BAR index and offset for a regblock
+ * @map: regblock map produced by cxl_find_regblock()
+ * @bar_index: out, PCI BAR index (0-5)
+ * @bar_offset: out, byte offset of the regblock within the BAR
+ *
+ * Exported for cxl drivers (vfio-cxl, in-kernel accelerator drivers)
+ * that need to map the regblock via pci_iomap() or report the BAR to
+ * userspace.
+ *
+ * Return: 0 on success, -EINVAL if the regblock is not BAR-backed or
+ * if any out pointer is NULL.
+ */
+int cxl_regblock_get_bar_info(const struct cxl_register_map *map,
+                             u8 *bar_index, resource_size_t *bar_offset)
+{
+       if (!map || !bar_index || !bar_offset)
+               return -EINVAL;
+       if (map->bar_index > 5)
+               return -EINVAL;
+       *bar_index = map->bar_index;
+       *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.
diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h
index 3dcc034360af..3bcb71d80c91 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -100,9 +100,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;
@@ -110,6 +117,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;
@@ -234,4 +243,7 @@ int cxl_get_hdm_info(struct cxl_dev_state *cxlds, u8 *count,
                     resource_size_t *offset, resource_size_t *size);
 
 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);
 #endif /* __CXL_CXL_H__ */
-- 
2.25.1


Reply via email to