From: Manish Honap <[email protected]> cxl_map_component_regs() claims each mapped sub-block with devm_request_mem_region(). A driver that requests the whole component register BAR itself, such as vfio-cxl, would then collide with that claim and fail to map the HDM decoder and RAS blocks.
Add cxl_reg_map_set_owned_resource() so such a driver records the resource it already owns, the whole component register BAR, on the register map. Skip the sub-block request for a block inside that resource, and fail with -ENXIO for a block outside it. Assisted-by: LLM Signed-off-by: Manish Honap <[email protected]> --- drivers/cxl/core/regs.c | 46 +++++++++++++++++++++++++++++++++++++++-- include/cxl/cxl.h | 2 ++ include/cxl/pci.h | 3 +++ 3 files changed, 49 insertions(+), 2 deletions(-) diff --git a/drivers/cxl/core/regs.c b/drivers/cxl/core/regs.c index 9235520b2f4e..c3df99de92c3 100644 --- a/drivers/cxl/core/regs.c +++ b/drivers/cxl/core/regs.c @@ -216,6 +216,39 @@ void __iomem *devm_cxl_iomap_block(struct device *dev, resource_size_t addr, } EXPORT_SYMBOL_NS_GPL(devm_cxl_iomap_block, "CXL"); +/** + * cxl_reg_map_set_owned_resource() - record the BAR a driver owns + * @map: register map of the component register block + * @res: resource of the whole component register BAR, which the caller + * requests itself, before or after this call + * + * A driver that requests the whole component register BAR itself, such as + * vfio-cxl, records that BAR here. cxl_map_component_regs() then maps the + * blocks inside @res without requesting them again and refuses any block + * outside it. A register map has at most one owned resource. + * + * Call this after cxl_pci_setup_regs() has filled @map: enumeration rewrites + * the whole map and drops a previously recorded owned resource. + * + * Return: 0 on success, -EBUSY if an owned resource is already set, or + * -EINVAL if @map has not been set up or its block lies outside @res. + */ +int cxl_reg_map_set_owned_resource(struct cxl_register_map *map, + struct resource *res) +{ + struct resource block = DEFINE_RES_MEM(map->resource, map->max_size); + + if (WARN_ON_ONCE(map->owned)) + return -EBUSY; + if (WARN_ON_ONCE(map->resource == CXL_RESOURCE_NONE || + !resource_contains(res, &block))) + return -EINVAL; + + map->owned = res; + return 0; +} +EXPORT_SYMBOL_NS_GPL(cxl_reg_map_set_owned_resource, "CXL"); + int cxl_map_component_regs(const struct cxl_register_map *map, struct cxl_component_regs *regs, unsigned long map_mask) @@ -234,6 +267,7 @@ int cxl_map_component_regs(const struct cxl_register_map *map, struct mapinfo *mi = &mapinfo[i]; resource_size_t addr; resource_size_t length; + struct resource res; if (!mi->rmap->valid) continue; @@ -241,8 +275,16 @@ int cxl_map_component_regs(const struct cxl_register_map *map, continue; addr = map->resource + mi->rmap->offset; length = mi->rmap->size; - *(mi->addr) = devm_cxl_iomap_block(host, addr, length); - if (!*(mi->addr)) + res = DEFINE_RES_MEM(addr, length); + + if (map->owned) { + if (!resource_contains(map->owned, &res)) + return -ENXIO; + *mi->addr = devm_cxl_ioremap_block(host, addr, length); + } else { + *mi->addr = devm_cxl_iomap_block(host, addr, length); + } + if (!*mi->addr) return -ENOMEM; } diff --git a/include/cxl/cxl.h b/include/cxl/cxl.h index 3e70f74685b6..4bd0fec4951f 100644 --- a/include/cxl/cxl.h +++ b/include/cxl/cxl.h @@ -153,6 +153,7 @@ struct cxl_pmu_reg_map { * @bar: PCI BAR containing the register block * @bar_offset: register block offset relative to @bar * @reg_type: see enum cxl_regloc_type + * @owned: driver-owned resource whose sub-blocks are mapped without re-requesting * @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 @@ -165,6 +166,7 @@ struct cxl_register_map { int bar; resource_size_t bar_offset; u8 reg_type; + struct resource *owned; union { struct cxl_component_reg_map component_map; struct cxl_device_reg_map device_map; diff --git a/include/cxl/pci.h b/include/cxl/pci.h index b15d7e415e27..0b74819fea6d 100644 --- a/include/cxl/pci.h +++ b/include/cxl/pci.h @@ -18,9 +18,12 @@ enum cxl_regloc_type { struct cxl_register_map; struct pci_dev; +struct resource; int cxl_pci_setup_regs(struct pci_dev *pdev, enum cxl_regloc_type type, struct cxl_register_map *map); +int cxl_reg_map_set_owned_resource(struct cxl_register_map *map, + struct resource *res); int cxl_find_regblock(struct pci_dev *pdev, enum cxl_regloc_type type, struct cxl_register_map *map); int cxl_setup_regs(struct cxl_register_map *map); -- 2.53.0

