]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
cxl: Add FWCTL support to CXL
authorDave Jiang <dave.jiang@intel.com>
Fri, 7 Mar 2025 20:55:31 +0000 (13:55 -0700)
committerJason Gunthorpe <jgg@nvidia.com>
Mon, 17 Mar 2025 17:41:36 +0000 (14:41 -0300)
Add fwctl support code to allow sending of CXL feature commands from
userspace through as ioctls via FWCTL. Provide initial setup bits. The
CXL PCI probe function will call devm_cxl_setup_fwctl() after the
cxl_memdev has been enumerated in order to setup FWCTL char device under
the cxl_memdev like the existing memdev char device for issuing CXL raw
mailbox commands from userspace via ioctls.

Link: https://patch.msgid.link/r/20250307205648.1021626-2-dave.jiang@intel.com
Signed-off-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Li Ming <ming.li@zohomail.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
drivers/cxl/Kconfig
drivers/cxl/core/features.c
drivers/cxl/pci.c
include/cxl/features.h
include/uapi/fwctl/fwctl.h
tools/testing/cxl/test/mem.c

index ad2e796e4ac63fd4529f8daf3caf9474addb416f..8ac1e9d70eeb1f71d84e280c2838446050d4cdd1 100644 (file)
@@ -7,6 +7,7 @@ menuconfig CXL_BUS
        select PCI_DOE
        select FIRMWARE_TABLE
        select NUMA_KEEP_MEMINFO if NUMA_MEMBLKS
+       select FWCTL if CXL_FEATURES
        help
          CXL is a bus that is electrically compatible with PCI Express, but
          layers three protocols on that signalling (CXL.io, CXL.cache, and
index 048ba4fc3538e7dc5c08e59f5d71384dd931caa0..7dac74fd76edefb6ae71d7b3ec180f3fe53872b6 100644 (file)
@@ -1,5 +1,6 @@
 // SPDX-License-Identifier: GPL-2.0-only
 /* Copyright(c) 2024-2025 Intel Corporation. All rights reserved. */
+#include <linux/fwctl.h>
 #include <linux/device.h>
 #include <cxl/mailbox.h>
 #include <cxl/features.h>
@@ -331,3 +332,74 @@ int cxl_set_feature(struct cxl_mailbox *cxl_mbox,
                }
        } while (true);
 }
+
+/* FWCTL support */
+
+static inline struct cxl_memdev *fwctl_to_memdev(struct fwctl_device *fwctl_dev)
+{
+       return to_cxl_memdev(fwctl_dev->dev.parent);
+}
+
+static int cxlctl_open_uctx(struct fwctl_uctx *uctx)
+{
+       return 0;
+}
+
+static void cxlctl_close_uctx(struct fwctl_uctx *uctx)
+{
+}
+
+static void *cxlctl_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
+                          void *in, size_t in_len, size_t *out_len)
+{
+       /* Place holder */
+       return ERR_PTR(-EOPNOTSUPP);
+}
+
+static const struct fwctl_ops cxlctl_ops = {
+       .device_type = FWCTL_DEVICE_TYPE_CXL,
+       .uctx_size = sizeof(struct fwctl_uctx),
+       .open_uctx = cxlctl_open_uctx,
+       .close_uctx = cxlctl_close_uctx,
+       .fw_rpc = cxlctl_fw_rpc,
+};
+
+DEFINE_FREE(free_fwctl_dev, struct fwctl_device *, if (_T) fwctl_put(_T))
+
+static void free_memdev_fwctl(void *_fwctl_dev)
+{
+       struct fwctl_device *fwctl_dev = _fwctl_dev;
+
+       fwctl_unregister(fwctl_dev);
+       fwctl_put(fwctl_dev);
+}
+
+int devm_cxl_setup_fwctl(struct cxl_memdev *cxlmd)
+{
+       struct cxl_dev_state *cxlds = cxlmd->cxlds;
+       struct cxl_features_state *cxlfs;
+       int rc;
+
+       cxlfs = to_cxlfs(cxlds);
+       if (!cxlfs)
+               return -ENODEV;
+
+       /* No need to setup FWCTL if there are no user allowed features found */
+       if (!cxlfs->entries->num_user_features)
+               return -ENODEV;
+
+       struct fwctl_device *fwctl_dev __free(free_fwctl_dev) =
+               _fwctl_alloc_device(&cxlmd->dev, &cxlctl_ops, sizeof(*fwctl_dev));
+       if (!fwctl_dev)
+               return -ENOMEM;
+
+       rc = fwctl_register(fwctl_dev);
+       if (rc)
+               return rc;
+
+       return devm_add_action_or_reset(&cxlmd->dev, free_memdev_fwctl,
+                                       no_free_ptr(fwctl_dev));
+}
+EXPORT_SYMBOL_NS_GPL(devm_cxl_setup_fwctl, "CXL");
+
+MODULE_IMPORT_NS("FWCTL");
index 3e666ec515808756e709018bcd9f80bb6357e3f6..993fa60fe453a2fb5918a6536398911058884631 100644 (file)
@@ -1013,6 +1013,10 @@ static int cxl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        if (rc)
                return rc;
 
+       rc = devm_cxl_setup_fwctl(cxlmd);
+       if (rc)
+               dev_dbg(&pdev->dev, "No CXL FWCTL setup\n");
+
        pmu_count = cxl_count_regblock(pdev, CXL_REGLOC_RBI_PMU);
        if (pmu_count < 0)
                return pmu_count;
index d2cde46b0fec8aebd2f1d88aeb3670b8abd845fc..596c85ee269959eff4196f18bbb21d4779c4858d 100644 (file)
@@ -4,6 +4,7 @@
 #define __CXL_FEATURES_H__
 
 #include <linux/uuid.h>
+#include <linux/fwctl.h>
 
 /* Feature UUIDs used by the kernel */
 #define CXL_FEAT_PATROL_SCRUB_UUID                                             \
@@ -173,9 +174,11 @@ struct cxl_features_state {
 };
 
 struct cxl_mailbox;
+struct cxl_memdev;
 #ifdef CONFIG_CXL_FEATURES
 inline struct cxl_features_state *to_cxlfs(struct cxl_dev_state *cxlds);
 int devm_cxl_setup_features(struct cxl_dev_state *cxlds);
+int devm_cxl_setup_fwctl(struct cxl_memdev *cxlmd);
 #else
 static inline struct cxl_features_state *to_cxlfs(struct cxl_dev_state *cxlds)
 {
@@ -186,6 +189,11 @@ static inline int devm_cxl_setup_features(struct cxl_dev_state *cxlds)
 {
        return -EOPNOTSUPP;
 }
+
+static inline int devm_cxl_setup_fwctl(struct cxl_memdev *cxlmd)
+{
+       return -EOPNOTSUPP;
+}
 #endif
 
 #endif
index 584a5ea8ecee1171f066c3ccb50a1c7def9d72a4..c2d5abc5a7261b9822fe827fdc325dabdce59437 100644 (file)
@@ -43,6 +43,7 @@ enum {
 enum fwctl_device_type {
        FWCTL_DEVICE_TYPE_ERROR = 0,
        FWCTL_DEVICE_TYPE_MLX5 = 1,
+       FWCTL_DEVICE_TYPE_CXL = 2,
 };
 
 /**
index 4809a90ff9b66987b955e0bd252e49564542a6af..848db399102c10223eecee8ac8cf901df2e5dd3b 100644 (file)
@@ -1646,6 +1646,10 @@ static int cxl_mock_mem_probe(struct platform_device *pdev)
        if (rc)
                return rc;
 
+       rc = devm_cxl_setup_fwctl(cxlmd);
+       if (rc)
+               dev_dbg(dev, "No CXL FWCTL setup\n");
+
        cxl_mem_get_event_records(mds, CXLDEV_EVENT_STATUS_ALL);
 
        return 0;