[PATCH 05/20] cxl: Expose BAR index and offset from register map

mhonap@nvidia.com posted 20 patches 3 weeks, 5 days ago
There is a newer version of this series
[PATCH 05/20] cxl: Expose BAR index and offset from register map
Posted by mhonap@nvidia.com 3 weeks, 5 days ago
From: Manish Honap <mhonap@nvidia.com>

The Register Locator DVSEC (CXL 2.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).

Signed-off-by: Manish Honap <mhonap@nvidia.com>
---
 drivers/cxl/core/regs.c | 29 +++++++++++++++++++++++++++++
 include/cxl/cxl.h       | 11 +++++++++++
 2 files changed, 40 insertions(+)

diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
index 20c2d9fbcfe7..720eb6eb5a45 100644
--- a/drivers/cxl/core/regs.c
+++ b/drivers/cxl/core/regs.c
@@ -287,9 +287,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 >= 0 && bar < PCI_STD_NUM_BARS) ? (u8)bar : 0xFF;
+	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. Callers can use pci_iomap(pdev, bar_index, size) and
+ * base + bar_offset instead of ioremap(map->resource).
+ *
+ * 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 > PCI_STD_NUM_BARS - 1)
+		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.
@@ -308,6 +336,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 684603799fb1..08e327a929ba 100644
--- a/include/cxl/cxl.h
+++ b/include/cxl/cxl.h
@@ -134,9 +134,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;
@@ -144,6 +151,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;
@@ -319,6 +328,8 @@ int cxl_get_hdm_reg_info(struct cxl_dev_state *cxlds, u32 *count,
 			 resource_size_t *offset, resource_size_t *size);
 struct pci_dev;
 enum cxl_regloc_type;
+int cxl_regblock_get_bar_info(const struct cxl_register_map *map, u8 *bar_index,
+			      resource_size_t *bar_offset);
 int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
 		      struct cxl_register_map *map);
 void cxl_probe_component_regs(struct device *dev, void __iomem *base,
-- 
2.25.1
Re: [PATCH 05/20] cxl: Expose BAR index and offset from register map
Posted by Dave Jiang 3 weeks, 4 days ago

On 3/11/26 1:34 PM, mhonap@nvidia.com wrote:
> From: Manish Honap <mhonap@nvidia.com>
> 
> The Register Locator DVSEC (CXL 2.0 8.1.9) describes register blocks by

CXL r4.0

Let's keep it to the latest spec version.

> 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).
> 
> Signed-off-by: Manish Honap <mhonap@nvidia.com>
> ---
>  drivers/cxl/core/regs.c | 29 +++++++++++++++++++++++++++++
>  include/cxl/cxl.h       | 11 +++++++++++
>  2 files changed, 40 insertions(+)
> 
> diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c
> index 20c2d9fbcfe7..720eb6eb5a45 100644
> --- a/drivers/cxl/core/regs.c
> +++ b/drivers/cxl/core/regs.c
> @@ -287,9 +287,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 >= 0 && bar < PCI_STD_NUM_BARS) ? (u8)bar : 0xFF;

map->bar_index = bar should be fine. Otherwise the pci_resource_start() and pci_resource_len() would also be invalid.


> +	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. Callers can use pci_iomap(pdev, bar_index, size) and
> + * base + bar_offset instead of ioremap(map->resource).
> + *
> + * 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 > PCI_STD_NUM_BARS - 1)

map->bar_index == 0xff? Otherwise it's probably a hardware issue right?

DJ

> +		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.
> @@ -308,6 +336,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 684603799fb1..08e327a929ba 100644
> --- a/include/cxl/cxl.h
> +++ b/include/cxl/cxl.h
> @@ -134,9 +134,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;
> @@ -144,6 +151,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;
> @@ -319,6 +328,8 @@ int cxl_get_hdm_reg_info(struct cxl_dev_state *cxlds, u32 *count,
>  			 resource_size_t *offset, resource_size_t *size);
>  struct pci_dev;
>  enum cxl_regloc_type;
> +int cxl_regblock_get_bar_info(const struct cxl_register_map *map, u8 *bar_index,
> +			      resource_size_t *bar_offset);
>  int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type,
>  		      struct cxl_register_map *map);
>  void cxl_probe_component_regs(struct device *dev, void __iomem *base,