aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/cxl/core.c
diff options
context:
space:
mode:
authorIra Weiny <ira.weiny@intel.com>2021-06-03 17:50:36 -0700
committerDan Williams <dan.j.williams@intel.com>2021-06-05 17:37:16 -0700
commit30af97296f48d84bc4a6abbaabb92c796a84ca57 (patch)
tree214e2d12ce72c06f88c9126ff21ef2ca392eeeaf /drivers/cxl/core.c
parentcxl/pci: Reserve all device regions at once (diff)
downloadlinux-dev-30af97296f48d84bc4a6abbaabb92c796a84ca57.tar.xz
linux-dev-30af97296f48d84bc4a6abbaabb92c796a84ca57.zip
cxl/pci: Map registers based on capabilities
The information required to map registers based on capabilities is contained within the bars themselves. This means the bar must be mapped to read the information needed and then unmapped to map the individual parts of the BAR based on capabilities. Change cxl_setup_device_regs() to return a new cxl_register_map, change the name to cxl_probe_device_regs(). Allocate and place cxl_register_maps on a list while processing all of the specified register blocks. After probing all the register blocks go back and map smaller registers blocks based on their capabilities and dispose of the cxl_register_maps. NOTE: pci_iomap() is not managed automatically via pcim_enable_device() so be careful to call pci_iounmap() correctly. Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com> Signed-off-by: Ira Weiny <ira.weiny@intel.com> Link: https://lore.kernel.org/r/20210604005036.4187184-1-ira.weiny@intel.com Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Diffstat (limited to 'drivers/cxl/core.c')
-rw-r--r--drivers/cxl/core.c74
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",