cxl/core: Refactor CXL register lookup for bridge reuse
authorDan Williams <dan.j.williams@intel.com>
Fri, 14 May 2021 05:22:05 +0000 (22:22 -0700)
committerDan Williams <dan.j.williams@intel.com>
Fri, 14 May 2021 23:13:19 +0000 (16:13 -0700)
While CXL Memory Device endpoints locate the CXL MMIO registers in a PCI
BAR, CXL root bridges have their MMIO base address described by platform
firmware. Refactor the existing register lookup into a generic facility
for endpoints and bridges to share.

Reviewed-by: Ben Widawsky <ben.widawsky@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Link: https://lore.kernel.org/r/162096972534.1865304.3218686216153688039.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
drivers/cxl/core.c
drivers/cxl/cxl.h
drivers/cxl/mem.c

index 7f8d203..84b90db 100644 (file)
@@ -1,7 +1,9 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(c) 2020 Intel Corporation. All rights reserved. */
+#include <linux/io-64-nonatomic-lo-hi.h>
 #include <linux/device.h>
 #include <linux/module.h>
+#include "cxl.h"
 
 /**
  * DOC: cxl core
  * point for cross-device interleave coordination through cxl ports.
  */
 
+/**
+ * cxl_setup_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())
+ */
+void cxl_setup_device_regs(struct device *dev, void __iomem *base,
+                          struct cxl_device_regs *regs)
+{
+       int cap, cap_count;
+       u64 cap_array;
+
+       *regs = (struct cxl_device_regs) { 0 };
+
+       cap_array = readq(base + CXLDEV_CAP_ARRAY_OFFSET);
+       if (FIELD_GET(CXLDEV_CAP_ARRAY_ID_MASK, cap_array) !=
+           CXLDEV_CAP_ARRAY_CAP_ID)
+               return;
+
+       cap_count = FIELD_GET(CXLDEV_CAP_ARRAY_COUNT_MASK, cap_array);
+
+       for (cap = 1; cap <= cap_count; cap++) {
+               void __iomem *register_block;
+               u32 offset;
+               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;
+
+               switch (cap_id) {
+               case CXLDEV_CAP_CAP_ID_DEVICE_STATUS:
+                       dev_dbg(dev, "found Status capability (0x%x)\n", offset);
+                       regs->status = register_block;
+                       break;
+               case CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX:
+                       dev_dbg(dev, "found Mailbox capability (0x%x)\n", offset);
+                       regs->mbox = register_block;
+                       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;
+                       break;
+               default:
+                       dev_dbg(dev, "Unknown cap ID: %d (0x%x)\n", cap_id, offset);
+                       break;
+               }
+       }
+}
+EXPORT_SYMBOL_GPL(cxl_setup_device_regs);
+
 struct bus_type cxl_bus_type = {
        .name = "cxl",
 };
index 1f3434f..d49e0cb 100644 (file)
@@ -66,5 +66,8 @@ struct cxl_regs {
        };
 };
 
+void cxl_setup_device_regs(struct device *dev, void __iomem *base,
+                          struct cxl_device_regs *regs);
+
 extern struct bus_type cxl_bus_type;
 #endif /* __CXL_H__ */
index ddc94c7..c5fdf2c 100644 (file)
@@ -884,53 +884,15 @@ static int cxl_mem_mbox_send_cmd(struct cxl_mem *cxlm, u16 opcode,
 static int cxl_mem_setup_regs(struct cxl_mem *cxlm)
 {
        struct device *dev = &cxlm->pdev->dev;
-       int cap, cap_count;
-       u64 cap_array;
+       struct cxl_regs *regs = &cxlm->regs;
 
-       cap_array = readq(cxlm->base + CXLDEV_CAP_ARRAY_OFFSET);
-       if (FIELD_GET(CXLDEV_CAP_ARRAY_ID_MASK, cap_array) !=
-           CXLDEV_CAP_ARRAY_CAP_ID)
-               return -ENODEV;
-
-       cap_count = FIELD_GET(CXLDEV_CAP_ARRAY_COUNT_MASK, cap_array);
-
-       for (cap = 1; cap <= cap_count; cap++) {
-               void __iomem *register_block;
-               u32 offset;
-               u16 cap_id;
-
-               cap_id = FIELD_GET(CXLDEV_CAP_HDR_CAP_ID_MASK,
-                                  readl(cxlm->base + cap * 0x10));
-               offset = readl(cxlm->base + cap * 0x10 + 0x4);
-               register_block = cxlm->base + offset;
-
-               switch (cap_id) {
-               case CXLDEV_CAP_CAP_ID_DEVICE_STATUS:
-                       dev_dbg(dev, "found Status capability (0x%x)\n", offset);
-                       cxlm->regs.status = register_block;
-                       break;
-               case CXLDEV_CAP_CAP_ID_PRIMARY_MAILBOX:
-                       dev_dbg(dev, "found Mailbox capability (0x%x)\n", offset);
-                       cxlm->regs.mbox = register_block;
-                       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);
-                       cxlm->regs.memdev = register_block;
-                       break;
-               default:
-                       dev_dbg(dev, "Unknown cap ID: %d (0x%x)\n", cap_id, offset);
-                       break;
-               }
-       }
+       cxl_setup_device_regs(dev, cxlm->base, &regs->device_regs);
 
-       if (!cxlm->regs.status || !cxlm->regs.mbox || !cxlm->regs.memdev) {
+       if (!regs->status || !regs->mbox || !regs->memdev) {
                dev_err(dev, "registers not found: %s%s%s\n",
-                       !cxlm->regs.status ? "status " : "",
-                       !cxlm->regs.mbox ? "mbox " : "",
-                       !cxlm->regs.memdev ? "memdev" : "");
+                       !regs->status ? "status " : "",
+                       !regs->mbox ? "mbox " : "",
+                       !regs->memdev ? "memdev" : "");
                return -ENXIO;
        }