]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
pds_fwctl: initial driver framework
authorShannon Nelson <shannon.nelson@amd.com>
Thu, 20 Mar 2025 19:44:10 +0000 (12:44 -0700)
committerJason Gunthorpe <jgg@nvidia.com>
Fri, 21 Mar 2025 23:57:55 +0000 (20:57 -0300)
Initial files for adding a new fwctl driver for the AMD/Pensando PDS
devices.  This sets up a simple auxiliary_bus driver that registers
with fwctl subsystem.  It expects that a pds_core device has set up
the auxiliary_device pds_core.fwctl

Link: https://patch.msgid.link/r/20250320194412.67983-5-shannon.nelson@amd.com
Reviewed-by: Leon Romanovsky <leonro@nvidia.com>
Reviewed-by: Dave Jiang <dave.jiang@intel.com>
Reviewed-by: Jonathan Cameron <Jonathan.Cameron@huawei.com>
Signed-off-by: Shannon Nelson <shannon.nelson@amd.com>
Signed-off-by: Jason Gunthorpe <jgg@nvidia.com>
MAINTAINERS
drivers/fwctl/Kconfig
drivers/fwctl/Makefile
drivers/fwctl/pds/Makefile [new file with mode: 0644]
drivers/fwctl/pds/main.c [new file with mode: 0644]
include/linux/pds/pds_adminq.h
include/uapi/fwctl/fwctl.h
include/uapi/fwctl/pds.h [new file with mode: 0644]

index 3381e41dcf37102145c37a21beb672974d68cbb9..c63fd76a36840ae82593227f8f78330b06fae8d0 100644 (file)
@@ -9576,6 +9576,13 @@ L:       linux-kernel@vger.kernel.org
 S:     Maintained
 F:     drivers/fwctl/mlx5/
 
+FWCTL PDS DRIVER
+M:     Brett Creeley <brett.creeley@amd.com>
+R:     Shannon Nelson <shannon.nelson@amd.com>
+L:     linux-kernel@vger.kernel.org
+S:     Maintained
+F:     drivers/fwctl/pds/
+
 GALAXYCORE GC0308 CAMERA SENSOR DRIVER
 M:     Sebastian Reichel <sre@kernel.org>
 L:     linux-media@vger.kernel.org
index f802cf5d4951e85a61fb69d2b889cf30483b4fe8..b5583b12a011a18fcbcc253bfc6d197d89c1fd8b 100644 (file)
@@ -19,5 +19,15 @@ config FWCTL_MLX5
          This will allow configuration and debug tools to work out of the box on
          mainstream kernel.
 
+         If you don't know what to do here, say N.
+
+config FWCTL_PDS
+       tristate "AMD/Pensando pds fwctl driver"
+       depends on PDS_CORE
+       help
+         The pds_fwctl driver provides an fwctl interface for a user process
+         to access the debug and configuration information of the AMD/Pensando
+         DSC hardware family.
+
          If you don't know what to do here, say N.
 endif
index 1c535f694d7fe4497eb8141e4b69fd539a20c403..c093b5f661d6ce7a40ac363a4464d0ba75ed0777 100644 (file)
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 obj-$(CONFIG_FWCTL) += fwctl.o
 obj-$(CONFIG_FWCTL_MLX5) += mlx5/
+obj-$(CONFIG_FWCTL_PDS) += pds/
 
 fwctl-y += main.o
diff --git a/drivers/fwctl/pds/Makefile b/drivers/fwctl/pds/Makefile
new file mode 100644 (file)
index 0000000..cc2317c
--- /dev/null
@@ -0,0 +1,4 @@
+# SPDX-License-Identifier: GPL-2.0
+obj-$(CONFIG_FWCTL_PDS) += pds_fwctl.o
+
+pds_fwctl-y += main.o
diff --git a/drivers/fwctl/pds/main.c b/drivers/fwctl/pds/main.c
new file mode 100644 (file)
index 0000000..7542a42
--- /dev/null
@@ -0,0 +1,168 @@
+// SPDX-License-Identifier: GPL-2.0
+/* Copyright(c) Advanced Micro Devices, Inc */
+
+#include <linux/module.h>
+#include <linux/auxiliary_bus.h>
+#include <linux/pci.h>
+#include <linux/vmalloc.h>
+
+#include <uapi/fwctl/fwctl.h>
+#include <uapi/fwctl/pds.h>
+#include <linux/fwctl.h>
+
+#include <linux/pds/pds_common.h>
+#include <linux/pds/pds_core_if.h>
+#include <linux/pds/pds_adminq.h>
+#include <linux/pds/pds_auxbus.h>
+
+struct pdsfc_uctx {
+       struct fwctl_uctx uctx;
+       u32 uctx_caps;
+};
+
+struct pdsfc_dev {
+       struct fwctl_device fwctl;
+       struct pds_auxiliary_dev *padev;
+       u32 caps;
+       struct pds_fwctl_ident ident;
+};
+
+static int pdsfc_open_uctx(struct fwctl_uctx *uctx)
+{
+       struct pdsfc_dev *pdsfc = container_of(uctx->fwctl, struct pdsfc_dev, fwctl);
+       struct pdsfc_uctx *pdsfc_uctx = container_of(uctx, struct pdsfc_uctx, uctx);
+
+       pdsfc_uctx->uctx_caps = pdsfc->caps;
+
+       return 0;
+}
+
+static void pdsfc_close_uctx(struct fwctl_uctx *uctx)
+{
+}
+
+static void *pdsfc_info(struct fwctl_uctx *uctx, size_t *length)
+{
+       struct pdsfc_uctx *pdsfc_uctx = container_of(uctx, struct pdsfc_uctx, uctx);
+       struct fwctl_info_pds *info;
+
+       info = kzalloc(sizeof(*info), GFP_KERNEL);
+       if (!info)
+               return ERR_PTR(-ENOMEM);
+
+       info->uctx_caps = pdsfc_uctx->uctx_caps;
+
+       return info;
+}
+
+static int pdsfc_identify(struct pdsfc_dev *pdsfc)
+{
+       struct device *dev = &pdsfc->fwctl.dev;
+       union pds_core_adminq_comp comp = {0};
+       union pds_core_adminq_cmd cmd;
+       struct pds_fwctl_ident *ident;
+       dma_addr_t ident_pa;
+       int err;
+
+       ident = dma_alloc_coherent(dev->parent, sizeof(*ident), &ident_pa, GFP_KERNEL);
+       if (!ident) {
+               dev_err(dev, "Failed to map ident buffer\n");
+               return -ENOMEM;
+       }
+
+       cmd = (union pds_core_adminq_cmd) {
+               .fwctl_ident = {
+                       .opcode = PDS_FWCTL_CMD_IDENT,
+                       .version = 0,
+                       .len = cpu_to_le32(sizeof(*ident)),
+                       .ident_pa = cpu_to_le64(ident_pa),
+               }
+       };
+
+       err = pds_client_adminq_cmd(pdsfc->padev, &cmd, sizeof(cmd), &comp, 0);
+       if (err)
+               dev_err(dev, "Failed to send adminq cmd opcode: %u err: %d\n",
+                       cmd.fwctl_ident.opcode, err);
+       else
+               pdsfc->ident = *ident;
+
+       dma_free_coherent(dev->parent, sizeof(*ident), ident, ident_pa);
+
+       return err;
+}
+
+static void *pdsfc_fw_rpc(struct fwctl_uctx *uctx, enum fwctl_rpc_scope scope,
+                         void *in, size_t in_len, size_t *out_len)
+{
+       return NULL;
+}
+
+static const struct fwctl_ops pdsfc_ops = {
+       .device_type = FWCTL_DEVICE_TYPE_PDS,
+       .uctx_size = sizeof(struct pdsfc_uctx),
+       .open_uctx = pdsfc_open_uctx,
+       .close_uctx = pdsfc_close_uctx,
+       .info = pdsfc_info,
+       .fw_rpc = pdsfc_fw_rpc,
+};
+
+static int pdsfc_probe(struct auxiliary_device *adev,
+                      const struct auxiliary_device_id *id)
+{
+       struct pds_auxiliary_dev *padev =
+                       container_of(adev, struct pds_auxiliary_dev, aux_dev);
+       struct device *dev = &adev->dev;
+       struct pdsfc_dev *pdsfc;
+       int err;
+
+       pdsfc = fwctl_alloc_device(&padev->vf_pdev->dev, &pdsfc_ops,
+                                  struct pdsfc_dev, fwctl);
+       if (!pdsfc)
+               return dev_err_probe(dev, -ENOMEM, "Failed to allocate fwctl device struct\n");
+       pdsfc->padev = padev;
+
+       err = pdsfc_identify(pdsfc);
+       if (err) {
+               fwctl_put(&pdsfc->fwctl);
+               return dev_err_probe(dev, err, "Failed to identify device\n");
+       }
+
+       err = fwctl_register(&pdsfc->fwctl);
+       if (err) {
+               fwctl_put(&pdsfc->fwctl);
+               return dev_err_probe(dev, err, "Failed to register device\n");
+       }
+
+       auxiliary_set_drvdata(adev, pdsfc);
+
+       return 0;
+}
+
+static void pdsfc_remove(struct auxiliary_device *adev)
+{
+       struct pdsfc_dev *pdsfc = auxiliary_get_drvdata(adev);
+
+       fwctl_unregister(&pdsfc->fwctl);
+       fwctl_put(&pdsfc->fwctl);
+}
+
+static const struct auxiliary_device_id pdsfc_id_table[] = {
+       {.name = PDS_CORE_DRV_NAME "." PDS_DEV_TYPE_FWCTL_STR },
+       {}
+};
+MODULE_DEVICE_TABLE(auxiliary, pdsfc_id_table);
+
+static struct auxiliary_driver pdsfc_driver = {
+       .name = "pds_fwctl",
+       .probe = pdsfc_probe,
+       .remove = pdsfc_remove,
+       .id_table = pdsfc_id_table,
+};
+
+module_auxiliary_driver(pdsfc_driver);
+
+MODULE_IMPORT_NS("FWCTL");
+MODULE_DESCRIPTION("pds fwctl driver");
+MODULE_AUTHOR("Shannon Nelson <shannon.nelson@amd.com>");
+MODULE_AUTHOR("Brett Creeley <brett.creeley@amd.com>");
+MODULE_LICENSE("GPL");
index 4b4e9a98b37b17b8cc44381a2d23a38b2b88d3f5..22c6d77b3dcb5cf389e1517f2949994e9ec4e4fb 100644 (file)
@@ -1179,6 +1179,84 @@ struct pds_lm_host_vf_status_cmd {
        u8     status;
 };
 
+enum pds_fwctl_cmd_opcode {
+       PDS_FWCTL_CMD_IDENT = 70,
+};
+
+/**
+ * struct pds_fwctl_cmd - Firmware control command structure
+ * @opcode: Opcode
+ * @rsvd:   Reserved
+ * @ep:     Endpoint identifier
+ * @op:     Operation identifier
+ */
+struct pds_fwctl_cmd {
+       u8     opcode;
+       u8     rsvd[3];
+       __le32 ep;
+       __le32 op;
+} __packed;
+
+/**
+ * struct pds_fwctl_comp - Firmware control completion structure
+ * @status:     Status of the firmware control operation
+ * @rsvd:       Reserved
+ * @comp_index: Completion index in little-endian format
+ * @rsvd2:      Reserved
+ * @color:      Color bit indicating the state of the completion
+ */
+struct pds_fwctl_comp {
+       u8     status;
+       u8     rsvd;
+       __le16 comp_index;
+       u8     rsvd2[11];
+       u8     color;
+} __packed;
+
+/**
+ * struct pds_fwctl_ident_cmd - Firmware control identification command structure
+ * @opcode:   Operation code for the command
+ * @rsvd:     Reserved
+ * @version:  Interface version
+ * @rsvd2:    Reserved
+ * @len:      Length of the identification data
+ * @ident_pa: Physical address of the identification data
+ */
+struct pds_fwctl_ident_cmd {
+       u8     opcode;
+       u8     rsvd;
+       u8     version;
+       u8     rsvd2;
+       __le32 len;
+       __le64 ident_pa;
+} __packed;
+
+/* future feature bits here
+ * enum pds_fwctl_features {
+ * };
+ * (compilers don't like empty enums)
+ */
+
+/**
+ * struct pds_fwctl_ident - Firmware control identification structure
+ * @features:    Supported features (enum pds_fwctl_features)
+ * @version:     Interface version
+ * @rsvd:        Reserved
+ * @max_req_sz:  Maximum request size
+ * @max_resp_sz: Maximum response size
+ * @max_req_sg_elems:  Maximum number of request SGs
+ * @max_resp_sg_elems: Maximum number of response SGs
+ */
+struct pds_fwctl_ident {
+       __le64 features;
+       u8     version;
+       u8     rsvd[3];
+       __le32 max_req_sz;
+       __le32 max_resp_sz;
+       u8     max_req_sg_elems;
+       u8     max_resp_sg_elems;
+} __packed;
+
 union pds_core_adminq_cmd {
        u8     opcode;
        u8     bytes[64];
@@ -1216,6 +1294,9 @@ union pds_core_adminq_cmd {
        struct pds_lm_dirty_enable_cmd    lm_dirty_enable;
        struct pds_lm_dirty_disable_cmd   lm_dirty_disable;
        struct pds_lm_dirty_seq_ack_cmd   lm_dirty_seq_ack;
+
+       struct pds_fwctl_cmd              fwctl;
+       struct pds_fwctl_ident_cmd        fwctl_ident;
 };
 
 union pds_core_adminq_comp {
@@ -1243,6 +1324,8 @@ union pds_core_adminq_comp {
 
        struct pds_lm_state_size_comp     lm_state_size;
        struct pds_lm_dirty_status_comp   lm_dirty_status;
+
+       struct pds_fwctl_comp             fwctl;
 };
 
 #ifndef __CHECKER__
index c2d5abc5a7261b9822fe827fdc325dabdce59437..716ac0eee42d9441011fb2ad007568a2684f0ee0 100644 (file)
@@ -44,6 +44,7 @@ enum fwctl_device_type {
        FWCTL_DEVICE_TYPE_ERROR = 0,
        FWCTL_DEVICE_TYPE_MLX5 = 1,
        FWCTL_DEVICE_TYPE_CXL = 2,
+       FWCTL_DEVICE_TYPE_PDS = 4,
 };
 
 /**
diff --git a/include/uapi/fwctl/pds.h b/include/uapi/fwctl/pds.h
new file mode 100644 (file)
index 0000000..749bfb6
--- /dev/null
@@ -0,0 +1,32 @@
+/* SPDX-License-Identifier: GPL-2.0 WITH Linux-syscall-note */
+/* Copyright(c) Advanced Micro Devices, Inc */
+
+/*
+ * fwctl interface info for pds_fwctl
+ */
+
+#ifndef _UAPI_FWCTL_PDS_H_
+#define _UAPI_FWCTL_PDS_H_
+
+#include <linux/types.h>
+
+/**
+ * struct fwctl_info_pds
+ * @uctx_caps:  bitmap of firmware capabilities
+ *
+ * Return basic information about the FW interface available.
+ */
+struct fwctl_info_pds {
+       __u32 uctx_caps;
+};
+
+/**
+ * enum pds_fwctl_capabilities
+ * @PDS_FWCTL_QUERY_CAP: firmware can be queried for information
+ * @PDS_FWCTL_SEND_CAP:  firmware can be sent commands
+ */
+enum pds_fwctl_capabilities {
+       PDS_FWCTL_QUERY_CAP = 0,
+       PDS_FWCTL_SEND_CAP,
+};
+#endif /* _UAPI_FWCTL_PDS_H_ */