diff options
Diffstat (limited to 'drivers/cxl/core.c')
-rw-r--r-- | drivers/cxl/core.c | 74 |
1 files changed, 62 insertions, 12 deletions
diff --git a/drivers/cxl/core.c b/drivers/cxl/core.c index 38979c97158d..f836aaab03e0 100644 --- a/drivers/cxl/core.c +++ b/drivers/cxl/core.c @@ -3,6 +3,7 @@ #include <linux/io-64-nonatomic-lo-hi.h> #include <linux/device.h> #include <linux/module.h> +#include <linux/pci.h> #include "cxl.h" /** @@ -13,18 +14,20 @@ */ /** - * cxl_setup_device_regs() - Detect CXL Device register blocks + * cxl_probe_device_regs() - Detect CXL Device register blocks * @dev: Host device of the @base mapping * @base: Mapping of CXL 2.0 8.2.8 CXL Device Register Interface - * @regs: Base pointers for device register blocks (see CXL_DEVICE_REGS()) + * @map: Map object describing the register block information found + * + * Probe for device register information and return it in map object. */ -void cxl_setup_device_regs(struct device *dev, void __iomem *base, - struct cxl_device_regs *regs) +void cxl_probe_device_regs(struct device *dev, void __iomem *base, + struct cxl_device_reg_map *map) { int cap, cap_count; u64 cap_array; - *regs = (struct cxl_device_regs) { 0 }; + *map = (struct cxl_device_reg_map){ 0 }; cap_array = readq(base + CXLDEV_CAP_ARRAY_OFFSET); if (FIELD_GET(CXLDEV_CAP_ARRAY_ID_MASK, cap_array) != @@ -34,30 +37,36 @@ void cxl_setup_device_regs(struct device *dev, void __iomem *base, cap_count = FIELD_GET(CXLDEV_CAP_ARRAY_COUNT_MASK, cap_array); for (cap = 1; cap <= cap_count; cap++) { - void __iomem *register_block; - u32 offset; + u32 offset, length; u16 cap_id; cap_id = FIELD_GET(CXLDEV_CAP_HDR_CAP_ID_MASK, readl(base + cap * 0x10)); offset = readl(base + cap * 0x10 + 0x4); - register_block = base + offset; + length = readl(base + cap * 0x10 + 0x8); switch (cap_id) { case CXLDEV_CAP_CAP_ID_DEVICE_STATUS: dev_dbg(dev, "found Status capability (0x%x)\n", offset); - regs->status = register_block; + + map->status.valid = true; + map->status.offset = offset; + map->status.size = length; break; case CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX: dev_dbg(dev, "found Mailbox capability (0x%x)\n", offset); - regs->mbox = register_block; + map->mbox.valid = true; + map->mbox.offset = offset; + map->mbox.size = length; break; case CXLDEV_CAP_CAP_ID_SECONDARY_MAILBOX: dev_dbg(dev, "found Secondary Mailbox capability (0x%x)\n", offset); break; case CXLDEV_CAP_CAP_ID_MEMDEV: dev_dbg(dev, "found Memory Device capability (0x%x)\n", offset); - regs->memdev = register_block; + map->memdev.valid = true; + map->memdev.offset = offset; + map->memdev.size = length; break; default: if (cap_id >= 0x8000) @@ -68,7 +77,48 @@ void cxl_setup_device_regs(struct device *dev, void __iomem *base, } } } -EXPORT_SYMBOL_GPL(cxl_setup_device_regs); +EXPORT_SYMBOL_GPL(cxl_probe_device_regs); + +int cxl_map_device_regs(struct pci_dev *pdev, + struct cxl_device_regs *regs, + struct cxl_register_map *map) +{ + struct device *dev = &pdev->dev; + resource_size_t phys_addr; + + phys_addr = pci_resource_start(pdev, map->barno); + phys_addr += map->block_offset; + + if (map->device_map.status.valid) { + resource_size_t addr; + resource_size_t length; + + addr = phys_addr + map->device_map.status.offset; + length = map->device_map.status.size; + regs->status = devm_ioremap(dev, addr, length); + } + + if (map->device_map.mbox.valid) { + resource_size_t addr; + resource_size_t length; + + addr = phys_addr + map->device_map.mbox.offset; + length = map->device_map.mbox.size; + regs->mbox = devm_ioremap(dev, addr, length); + } + + if (map->device_map.memdev.valid) { + resource_size_t addr; + resource_size_t length; + + addr = phys_addr + map->device_map.memdev.offset; + length = map->device_map.memdev.size; + regs->memdev = devm_ioremap(dev, addr, length); + } + + return 0; +} +EXPORT_SYMBOL_GPL(cxl_map_device_regs); struct bus_type cxl_bus_type = { .name = "cxl", |