[RFC PATCH 3/8] mei: Add IAF mei component

Maarten Lankhorst dev at lankhorst.se
Fri Jun 13 13:45:22 UTC 2025


>From the backport repository.

Signed-off-by: Maarten Lankhorst <dev at lankhorst.se>
---
 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



More information about the dri-devel mailing list