>From the backport repository.

Signed-off-by: Maarten Lankhorst <[email protected]>
---
 drivers/misc/mei/Kconfig                   |   1 +
 drivers/misc/mei/Makefile                  |   1 +
 drivers/misc/mei/iaf/Kconfig               |  12 +
 drivers/misc/mei/iaf/Makefile              |   7 +
 drivers/misc/mei/iaf/mei_iaf.c             | 292 +++++++++++++++++++++
 drivers/misc/mei/mkhi.h                    |   2 +
 include/drm/intel/i915_mei_iaf_interface.h |  25 ++
 7 files changed, 340 insertions(+)
 create mode 100644 drivers/misc/mei/iaf/Kconfig
 create mode 100644 drivers/misc/mei/iaf/Makefile
 create mode 100644 drivers/misc/mei/iaf/mei_iaf.c
 create mode 100644 include/drm/intel/i915_mei_iaf_interface.h

diff --git a/drivers/misc/mei/Kconfig b/drivers/misc/mei/Kconfig
index 7575fee96cc6a..60b2cfa27ebaa 100644
--- a/drivers/misc/mei/Kconfig
+++ b/drivers/misc/mei/Kconfig
@@ -84,5 +84,6 @@ config INTEL_MEI_VSC
 source "drivers/misc/mei/hdcp/Kconfig"
 source "drivers/misc/mei/pxp/Kconfig"
 source "drivers/misc/mei/gsc_proxy/Kconfig"
+source "drivers/misc/mei/iaf/Kconfig"
 
 endif
diff --git a/drivers/misc/mei/Makefile b/drivers/misc/mei/Makefile
index 6f9fdbf1a4959..8be787f8ecd41 100644
--- a/drivers/misc/mei/Makefile
+++ b/drivers/misc/mei/Makefile
@@ -31,6 +31,7 @@ CFLAGS_mei-trace.o = -I$(src)
 obj-$(CONFIG_INTEL_MEI_HDCP) += hdcp/
 obj-$(CONFIG_INTEL_MEI_PXP) += pxp/
 obj-$(CONFIG_INTEL_MEI_GSC_PROXY) += gsc_proxy/
+obj-$(CONFIG_INTEL_MEI_IAF) += iaf/
 
 obj-$(CONFIG_INTEL_MEI_VSC_HW) += mei-vsc-hw.o
 mei-vsc-hw-y := vsc-tp.o
diff --git a/drivers/misc/mei/iaf/Kconfig b/drivers/misc/mei/iaf/Kconfig
new file mode 100644
index 0000000000000..4d131df6cf79f
--- /dev/null
+++ b/drivers/misc/mei/iaf/Kconfig
@@ -0,0 +1,12 @@
+# SPDX-License-Identifier: GPL-2.0
+# Copyright (c) 2020-2021, Intel Corporation. All rights reserved.
+#
+config INTEL_MEI_IAF
+       tristate "Intel Accelerator Fabric services of ME Interface"
+       depends on m
+       select INTEL_MEI_ME
+       depends on DRM_XE
+       help
+         MEI Support for IAF Services on Intel graphics card.
+
+         Enables the ME FW services required for IAF support.
diff --git a/drivers/misc/mei/iaf/Makefile b/drivers/misc/mei/iaf/Makefile
new file mode 100644
index 0000000000000..1130cbc9c0ccb
--- /dev/null
+++ b/drivers/misc/mei/iaf/Makefile
@@ -0,0 +1,7 @@
+# SPDX-License-Identifier: GPL-2.0
+#
+# Copyright (c) 2020-2021, Intel Corporation. All rights reserved.
+#
+# Makefile - IAF client driver for Intel MEI Bus Driver.
+
+obj-$(CONFIG_INTEL_MEI_IAF) += mei_iaf.o
diff --git a/drivers/misc/mei/iaf/mei_iaf.c b/drivers/misc/mei/iaf/mei_iaf.c
new file mode 100644
index 0000000000000..ad138ffe2b663
--- /dev/null
+++ b/drivers/misc/mei/iaf/mei_iaf.c
@@ -0,0 +1,292 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright © 2020-2021 Intel Corporation
+ */
+
+/**
+ * DOC: MEI_IAF Client Driver
+ *
+ * The IAF (Intel Accelerator Fabric) component driver acts as an interface
+ * between IAF i915 driver and GSC. The only api this interface provides is
+ * the 'commit svn' call.
+ */
+
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/uuid.h>
+#include <linux/mei_cl_bus.h>
+#include <linux/component.h>
+#include <drm/drm_connector.h>
+#include <drm/intel/i915_component.h>
+#include <drm/intel/i915_mei_iaf_interface.h>
+
+#include "../mkhi.h"
+
+#define MCA_ARBSVN_COMMIT_COMMAND_ID 0x1B
+
+enum arbsvn_nvar_usage {
+       ARBSVN_NVAR_USAGE_FW_MIN_VER = 0,
+       ARBSVN_NVAR_USAGE_MAX
+};
+
+struct mca_arbsvn_commit_req {
+       struct mkhi_msg_hdr mkhi_header;
+       u8                  usage_id;
+       u8                  reserved0;
+       u16                 reserved1;
+} __packed;
+
+struct mca_arbsvn_commit_resp {
+       struct mkhi_msg_hdr mkhi_header;
+};
+
+#define MCA_OK               0x0  /* on successful commit */
+#define MCA_INVALID_INPUT    0xb  /* if usage id is invalid */
+/* if disabled in the file or any other error (generic, reading or writing 
file) */
+#define MCA_ARB_SVN_DISABLED 0x20
+/* SVN was not updated, same value */
+#define MCA_ARB_SVN_SAME     0x28
+/* SVN was not updated, older value */
+#define MCA_ARB_SVN_SMALLER  0x29
+
+static int get_error_code(const struct device *dev, u8 result)
+{
+       int ret;
+
+       switch (result) {
+       case MCA_OK:
+               ret = 0;
+               break;
+       case MCA_ARB_SVN_DISABLED:
+               dev_dbg(dev, "Arb Svn disabled (error code 0x%x)\n",
+                       MCA_ARB_SVN_DISABLED);
+               ret = -ENOENT;
+       break;
+       case MCA_INVALID_INPUT:
+               dev_err(dev, "Wrong usage id(error code 0x%x)\n",
+                       MCA_INVALID_INPUT);
+               ret = -EINVAL;
+       break;
+       case MCA_ARB_SVN_SAME:
+               dev_dbg(dev, "SVN was not updated, same value(error code 
0x%x)\n",
+                       MCA_ARB_SVN_SAME);
+               ret = -EACCES;
+       break;
+       case MCA_ARB_SVN_SMALLER:
+               dev_dbg(dev, "SVN was not updated, older value(error code 
0x%x)\n",
+                       MCA_ARB_SVN_SMALLER);
+               ret = -EBADF;
+       break;
+       default:
+               dev_err(dev, "Unknown error code 0x%x\n", result);
+               ret = -EIO;
+       }
+
+       return ret;
+}
+
+static int mei_iaf_check_response(const struct device *dev,
+                                 struct mkhi_msg_hdr *hdr)
+{
+       if (hdr->group_id != MCHI_GROUP_ID) {
+               dev_err(dev, "Mismatch group id: 0x%x instead of 0x%x\n",
+                       hdr->group_id, MCHI_GROUP_ID);
+               return -EINVAL;
+       }
+
+       if (hdr->command != (MCA_ARBSVN_COMMIT_COMMAND_ID | 0x80)) {
+               dev_err(dev, "Mismatch command: 0x%x instead of 0x%x\n",
+                       hdr->command, MCA_ARBSVN_COMMIT_COMMAND_ID | 0x80);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+/**
+ * mei_iaf_commit_svn() - Commits current SVN.
+ * @dev: device corresponding to the mei_cl_device
+ * Return: 0 on Success
+ * *  -EINVAL : Invalid usage id parameter
+ * *  -ENOENT : ARB SVN is disabled in the file or any other error
+ *             (generic, reading or writing file)
+ * *  -EIO    : Unknown I/O error
+ */
+static int mei_iaf_commit_svn(const struct device *dev)
+{
+       struct mei_cl_device *cldev;
+       struct mca_arbsvn_commit_req commit_req = { };
+       struct mca_arbsvn_commit_resp commit_resp = { };
+       int ret;
+
+       dev_dbg(dev, "in %s\n", __func__);
+
+       if (!dev)
+               return -EINVAL;
+
+       cldev = to_mei_cl_device(dev);
+
+       dev_dbg(dev, "after to_mei_cl_device cldev %p\n", cldev);
+
+       ret = mei_cldev_enable(cldev);
+       if (ret < 0) {
+               dev_dbg(dev, "mei_cldev_enable Failed. %d\n", ret);
+               return -EBUSY;
+       }
+
+       dev_dbg(dev, "after mei_cldev_enable, ret=%d\n", ret);
+       commit_req.mkhi_header.group_id = MCHI_GROUP_ID;
+       commit_req.mkhi_header.command = MCA_ARBSVN_COMMIT_COMMAND_ID;
+       commit_req.usage_id = ARBSVN_NVAR_USAGE_FW_MIN_VER;
+
+       ret = mei_cldev_send(cldev, (u8 *)&commit_req, sizeof(commit_req));
+       if (ret < 0) {
+               dev_err(dev, "mei_cldev_send failed. %d\n", ret);
+               goto end;
+       }
+       dev_dbg(dev, "after send, ret=%d\n", ret);
+       print_hex_dump_debug("sent svn commit message: ", DUMP_PREFIX_OFFSET,
+                            16, 1, (u8 *)&commit_req, ret, false);
+
+       ret = mei_cldev_recv(cldev, (u8 *)&commit_resp, sizeof(commit_resp));
+       if (ret < 0) {
+               dev_err(dev, "mei_cldev_recv failed. %d\n", ret);
+               goto end;
+       }
+       dev_dbg(dev, "after recv, ret=%d\n", ret);
+       print_hex_dump_debug("mei_iaf_commit_response ", DUMP_PREFIX_OFFSET,
+                            16, 1, (u8 *)&commit_resp, ret, false);
+
+       ret = mei_iaf_check_response(dev, &commit_resp.mkhi_header);
+       if (ret) {
+               dev_err(dev, "bad result response from the firmware: 0x%x\n",
+                       *(uint32_t *)&commit_resp.mkhi_header);
+               goto end;
+       }
+       dev_dbg(dev, "after check_response\n");
+       ret = get_error_code(dev, commit_resp.mkhi_header.result);
+
+end:
+       dev_dbg(dev, "returning with %d\n", ret);
+       mei_cldev_disable(cldev);
+       return ret;
+}
+
+static const struct i915_iaf_component_ops mei_iaf_ops = {
+       .owner = THIS_MODULE,
+       .commit_svn = mei_iaf_commit_svn,
+};
+
+static int mei_component_master_bind(struct device *dev)
+{
+       int ret;
+
+       dev_dbg(dev, "mei_iaf_ops addr %p\n", &mei_iaf_ops);
+
+       ret = component_bind_all(dev, (void *)&mei_iaf_ops);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static void mei_component_master_unbind(struct device *dev)
+{
+       dev_dbg(dev, "in %s\n", __func__);
+       component_unbind_all(dev, (void *)&mei_iaf_ops);
+}
+
+static const struct component_master_ops mei_component_master_ops = {
+       .bind = mei_component_master_bind,
+       .unbind = mei_component_master_unbind,
+};
+
+/**
+ * mei_iaf_component_match - compare function for matching mei iaf.
+ *
+ *    The function checks if the driver is i915, the subcomponent is IAF
+ *    and the parent of iaf and the grand parent of mei_if are the same
+ *    i915 device.
+ *
+ * @dev: master device
+ * @subcomponent: subcomponent to match (I915_COMPONENT_IAF)
+ * @data: compare data (mei iaf device)
+ *
+ * Return:
+ * * 1 - if components match
+ * * 0 - otherwise
+ */
+static int mei_iaf_component_match(struct device *dev, int subcomponent,
+                                  void *data)
+{
+       struct device *base = data;
+
+       if (subcomponent != I915_COMPONENT_IAF ||
+           !dev->driver || strcmp(dev->driver->name, "iaf"))
+               return 0;
+
+       base = base->parent;
+       if (!base)
+               return 0;
+
+       base = base->parent;
+       dev = dev->parent;
+
+       return (base && dev && dev == base);
+}
+
+static int mei_iaf_probe(struct mei_cl_device *cldev,
+                        const struct mei_cl_device_id *id)
+{
+       struct component_match *master_match;
+       int ret;
+
+       master_match = NULL;
+       component_match_add_typed(&cldev->dev, &master_match,
+                                 mei_iaf_component_match, &cldev->dev);
+       if (IS_ERR_OR_NULL(master_match)) {
+               ret = -ENOMEM;
+               goto err_exit;
+       }
+
+       ret = component_master_add_with_match(&cldev->dev,
+                                             &mei_component_master_ops,
+                                             master_match);
+       if (ret < 0) {
+               dev_err(&cldev->dev, "Master comp add failed %d\n", ret);
+               goto err_exit;
+       }
+
+       return 0;
+
+err_exit:
+       return ret;
+}
+
+static void mei_iaf_remove(struct mei_cl_device *cldev)
+{
+       component_master_del(&cldev->dev, &mei_component_master_ops);
+}
+
+/* fe2af7a6-ef22-4b45-872f-176b0bbc8b43: MCHIF GUID */
+#define MEI_GUID_MCHIF UUID_LE(0xfe2af7a6, 0xef22, 0x4b45, \
+                              0x87, 0x2f, 0x17, 0x6b, 0x0b, 0xbc, 0x8b, 0x43)
+
+static struct mei_cl_device_id mei_iaf_tbl[] = {
+       { .uuid = MEI_GUID_MCHIF, .version = MEI_CL_VERSION_ANY },
+       { }
+};
+MODULE_DEVICE_TABLE(mei, mei_iaf_tbl);
+
+static struct mei_cl_driver mei_iaf_driver = {
+       .id_table = mei_iaf_tbl,
+       .name = KBUILD_MODNAME,
+       .probe = mei_iaf_probe,
+       .remove = mei_iaf_remove,
+};
+
+module_mei_cl_driver(mei_iaf_driver);
+
+MODULE_AUTHOR("Intel Corporation");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("MEI IAF");
diff --git a/drivers/misc/mei/mkhi.h b/drivers/misc/mei/mkhi.h
index 1473ea4896662..63d9f02e7341f 100644
--- a/drivers/misc/mei/mkhi.h
+++ b/drivers/misc/mei/mkhi.h
@@ -16,6 +16,8 @@
 #define MKHI_GEN_GROUP_ID 0xFF
 #define MKHI_GEN_GET_FW_VERSION_CMD 0x2
 
+#define MCHI_GROUP_ID  0xA
+
 #define MKHI_GROUP_ID_GFX              0x30
 #define MKHI_GFX_RESET_WARN_CMD_REQ    0x0
 #define MKHI_GFX_MEMORY_READY_CMD_REQ  0x1
diff --git a/include/drm/intel/i915_mei_iaf_interface.h 
b/include/drm/intel/i915_mei_iaf_interface.h
new file mode 100644
index 0000000000000..dde938dd0ea2c
--- /dev/null
+++ b/include/drm/intel/i915_mei_iaf_interface.h
@@ -0,0 +1,25 @@
+/* SPDX-License-Identifier: (GPL-2.0+) */
+/*
+ * Copyright © 2020-2021 Intel Corporation
+ */
+
+#ifndef _I915_MEI_IAF_INTERFACE_H_
+#define _I915_MEI_IAF_INTERFACE_H_
+
+#include <linux/device.h>
+
+/**
+ * struct i915_iaf_component_ops- ops for IAF services.
+ * @owner: Module providing the ops
+ * @commit_svn: commits current FW SVN
+ */
+struct i915_iaf_component_ops {
+       /**
+        * @owner: mei_iaf module
+        */
+       struct module *owner;
+
+       int (*commit_svn)(const struct device *dev);
+};
+
+#endif /* _I915_MEI_IAF_INTERFACE_H_ */
-- 
2.45.2

Reply via email to