Explorar o código

msm: camera: icp: Support multiple ICP subdevices

Add infrastructure to allow multiple ICP subdevices to co-exist
with each subdevice exposed to UMD individually. All operations
including ioctl on each subdevice are discrete from another's. Add
a new private field in node structure to point to which subdev
the node belongs to. Add a new ICP1 device type and expose the type
associated with ICP1 to userspace for identifying the second ICP.

Each subdevice's unique name is derived from "cam-icp". The name is
then appended with a cell-index if it exists. If there are multiple
nodes in DTSI to be probed, each node must contain cell-index to
differentiate them.

For each subdevice, it is expected to have a unique node in DTSI
with unique compatible string to probe the sd during boottime.

CRs-Fixed: 3336505
Change-Id: I615f9489d5f22b0ec37f98be3fec4c67b06a52d0
Signed-off-by: Sokchetra Eung <[email protected]>
Sokchetra Eung %!s(int64=2) %!d(string=hai) anos
pai
achega
a8b332e9d0

+ 0 - 2
drivers/cam_core/cam_node.c

@@ -708,8 +708,6 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
 		return -EINVAL;
 	}
 
-	memset(node, 0, sizeof(*node));
-
 	strlcpy(node->name, name, sizeof(node->name));
 
 	memcpy(&node->hw_mgr_intf, hw_mgr_intf, sizeof(node->hw_mgr_intf));

+ 4 - 1
drivers/cam_core/cam_node.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2019, 2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_NODE_H_
@@ -20,7 +21,8 @@
  *
  * @name:                  Name for struct cam_node
  * @state:                 Node state:
- *                            0 = uninitialized, 1 = initialized
+ *                         0 = uninitialized, 1 = initialized
+ * @device_idx:            Index to identify which device this node belongs to
  * @list_mutex:            Mutex for the context pool
  * @free_ctx_list:         Free context pool list
  * @ctx_list:              Context list
@@ -33,6 +35,7 @@
 struct cam_node {
 	char                              name[CAM_CTX_DEV_NAME_MAX_LENGTH];
 	uint32_t                          state;
+	uint32_t                          device_idx;
 
 	/* context pool */
 	struct mutex                      list_mutex;

+ 1 - 0
drivers/cam_core/cam_subdev.c

@@ -138,6 +138,7 @@ int cam_subdev_remove(struct cam_subdev *sd)
 	cam_unregister_subdev(sd);
 	cam_node_deinit((struct cam_node *)sd->token);
 	kfree(sd->token);
+	memset(sd, 0, sizeof(struct cam_subdev));
 
 	return 0;
 }

+ 7 - 6
drivers/cam_icp/cam_icp_context.c

@@ -23,8 +23,6 @@
 #include "cam_req_mgr_dev.h"
 #include "cam_icp_hw_mgr_intf.h"
 
-static const char icp_dev_name[] = "cam-icp";
-
 static int cam_icp_context_dump_active_request(void *data, void *args)
 {
 	struct cam_context         *ctx = (struct cam_context *)data;
@@ -506,13 +504,16 @@ static struct cam_ctx_ops
 	},
 };
 
-int cam_icp_context_init(struct cam_icp_context *ctx,
-	struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id, int img_iommu_hdl)
+int cam_icp_context_init(struct cam_icp_context *ctx, struct cam_hw_mgr_intf *hw_intf,
+	uint32_t ctx_id, int img_iommu_hdl, const char *icp_dev_name)
 {
 	int rc;
 
-	if ((!ctx) || (!ctx->base) || (!hw_intf)) {
-		CAM_ERR(CAM_ICP, "Invalid params: %pK %pK", ctx, hw_intf);
+	if ((!ctx) || (!ctx->base) || (!hw_intf) || (!icp_dev_name)) {
+		CAM_ERR(CAM_ICP,
+			"Invalid params: ctx: %s hw intf: %s dev name: %s",
+			CAM_IS_NULL_TO_STR(ctx), CAM_IS_NULL_TO_STR(hw_intf),
+			CAM_IS_NULL_TO_STR(icp_dev_name));
 		rc = -EINVAL;
 		goto err;
 	}

+ 4 - 2
drivers/cam_icp/cam_icp_context.h

@@ -1,6 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_ICP_CONTEXT_H_
@@ -30,10 +31,11 @@ struct cam_icp_context {
  * @hw_intf: Pointer to ICP hardware interface
  * @ctx_id: ID for this context
  * @img_iommu_hdl: IOMMU HDL for image buffers
- *
+ * @icp_dev_name: name of the icp subdevice
  */
 int cam_icp_context_init(struct cam_icp_context *ctx,
-	struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id, int img_iommu_hdl);
+	struct cam_hw_mgr_intf *hw_intf, uint32_t ctx_id,
+	int img_iommu_hdl, const char *icp_dev_name);
 
 /**
  * cam_icp_context_deinit() - ICP context deinit

+ 180 - 69
drivers/cam_icp/cam_icp_subdev.c

@@ -34,7 +34,11 @@
 #include "cam_common_util.h"
 #include "cam_context_utils.h"
 
-#define CAM_ICP_DEV_NAME        "cam-icp"
+
+#define CAM_ICP_IS_DEV_IDX_INVALID(dev_idx)                   \
+({                                                            \
+	((dev_idx) < 0) || ((dev_idx) >= CAM_ICP_SUBDEV_MAX); \
+})
 
 struct cam_icp_subdev {
 	struct cam_subdev sd;
@@ -46,21 +50,33 @@ struct cam_icp_subdev {
 	int32_t reserved;
 };
 
-static struct cam_icp_subdev g_icp_dev;
+static DEFINE_MUTEX(g_dev_lock);
+static struct cam_icp_subdev *g_icp_dev[CAM_ICP_SUBDEV_MAX];
+
+static char cam_icp_subdev_name_arr[CAM_ICP_SUBDEV_MAX][CAM_ICP_SUBDEV_NAME_LEN] = {
+	"cam-icp0",
+	"cam-icp1",
+};
 
 static const struct of_device_id cam_icp_dt_match[] = {
 	{.compatible = "qcom,cam-icp"},
+	{.compatible = "qcom,cam-icp0"},
+	{.compatible = "qcom,cam-icp1"},
 	{}
 };
 
 static int cam_icp_dev_evt_inject_cb(void *inject_args)
 {
 	struct cam_common_inject_evt_param *inject_params = inject_args;
+	struct cam_icp_subdev *icp_dev;
 	int i;
 
+	/* Event Injection currently supported for only a single instance of ICP */
+	icp_dev = g_icp_dev[0];
+
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
-		if (g_icp_dev.ctx[i].dev_hdl == inject_params->dev_hdl) {
-			cam_context_add_evt_inject(&g_icp_dev.ctx[i],
+		if (icp_dev->ctx[i].dev_hdl == inject_params->dev_hdl) {
+			cam_context_add_evt_inject(&icp_dev->ctx[i],
 				&inject_params->evt_params);
 			return 0;
 		}
@@ -106,7 +122,7 @@ static void cam_icp_dev_mini_dump_cb(void *priv, void *args)
 	struct cam_context *ctx = NULL;
 
 	if (!priv || !args) {
-		CAM_ERR(CAM_ICP, "Invalid param priv: %pK args %pK", priv, args);
+		CAM_ERR(CAM_ICP, "Invalid params: priv: %pK args %pK", priv, args);
 		return;
 	}
 
@@ -119,32 +135,45 @@ static int cam_icp_subdev_open(struct v4l2_subdev *sd,
 {
 	struct cam_hw_mgr_intf *hw_mgr_intf = NULL;
 	struct cam_node *node = v4l2_get_subdevdata(sd);
+	struct cam_icp_subdev *icp_dev = NULL;
 	int rc = 0;
 
-	cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK);
+	if (!node) {
+		CAM_ERR(CAM_ICP, "Invalid params: Node is NULL");
+		return -EINVAL;
+	}
 
-	mutex_lock(&g_icp_dev.icp_lock);
-	if (g_icp_dev.open_cnt >= 1) {
-		CAM_ERR(CAM_ICP, "ICP subdev is already opened");
-		rc = -EALREADY;
-		goto end;
+	cam_req_mgr_rwsem_read_op(CAM_SUBDEV_LOCK);
+	CAM_DBG(CAM_ICP, "Enter device open for %s[%u]",
+		sd->name, node->device_idx);
+
+	if (CAM_ICP_IS_DEV_IDX_INVALID(node->device_idx)) {
+		CAM_ERR(CAM_ICP, "Invalid device idx: %u for device: %s",
+			node->device_idx, sd->name);
+		cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK);
+		return -ENODEV;
 	}
+	icp_dev = g_icp_dev[node->device_idx];
 
-	if (!node) {
-		CAM_ERR(CAM_ICP, "Invalid args");
-		rc = -EINVAL;
+	mutex_lock(&icp_dev->icp_lock);
+	if (icp_dev->open_cnt >= 1) {
+		CAM_ERR(CAM_ICP, "device[%s] is already opened, open count: %u",
+			sd->name, icp_dev->open_cnt);
+		rc = -EALREADY;
 		goto end;
 	}
 
 	hw_mgr_intf = &node->hw_mgr_intf;
 	rc = hw_mgr_intf->hw_open(hw_mgr_intf->hw_mgr_priv, NULL);
 	if (rc < 0) {
-		CAM_ERR(CAM_ICP, "FW download failed");
+		CAM_ERR(CAM_ICP, "FW download failed for device [%s]", sd->name);
 		goto end;
 	}
-	g_icp_dev.open_cnt++;
+
+	icp_dev->open_cnt++;
+
 end:
-	mutex_unlock(&g_icp_dev.icp_lock);
+	mutex_unlock(&icp_dev->icp_lock);
 	cam_req_mgr_rwsem_read_op(CAM_SUBDEV_UNLOCK);
 	return rc;
 }
@@ -155,34 +184,48 @@ static int cam_icp_subdev_close_internal(struct v4l2_subdev *sd,
 	int rc = 0;
 	struct cam_hw_mgr_intf *hw_mgr_intf = NULL;
 	struct cam_node *node = v4l2_get_subdevdata(sd);
+	struct cam_icp_subdev *icp_dev = NULL;
 
-	mutex_lock(&g_icp_dev.icp_lock);
-	if (g_icp_dev.open_cnt <= 0) {
-		CAM_DBG(CAM_ICP, "ICP subdev is already closed");
-		goto end;
-	}
-	g_icp_dev.open_cnt--;
 	if (!node) {
-		CAM_ERR(CAM_ICP, "Invalid args");
+		CAM_ERR(CAM_ICP, "device[%s] Invalid params: node is NULL",
+			sd->name);
 		rc = -EINVAL;
 		goto end;
 	}
 
+	if (CAM_ICP_IS_DEV_IDX_INVALID(node->device_idx)) {
+		CAM_ERR(CAM_ICP, "Invalid device idx: %u for device: %s",
+			node->device_idx, node->name);
+		return -ENODEV;
+	}
+	icp_dev = g_icp_dev[node->device_idx];
+
+	mutex_lock(&icp_dev->icp_lock);
+	if (icp_dev->open_cnt <= 0) {
+		CAM_DBG(CAM_ICP, "device[%s] is already closed",
+			sd->name);
+		goto end;
+	}
+
+	icp_dev->open_cnt--;
+
 	hw_mgr_intf = &node->hw_mgr_intf;
 	if (!hw_mgr_intf) {
-		CAM_ERR(CAM_ICP, "hw_mgr_intf is not initialized");
+		CAM_ERR(CAM_ICP, "device[%s] hw_mgr_intf is not initialized",
+			sd->name);
 		rc = -EINVAL;
 		goto end;
 	}
 
 	rc = cam_node_shutdown(node);
 	if (rc < 0) {
-		CAM_ERR(CAM_ICP, "HW close failed");
+		CAM_ERR(CAM_ICP, "device[%s] HW close failed",
+			sd->name);
 		goto end;
 	}
 
 end:
-	mutex_unlock(&g_icp_dev.icp_lock);
+	mutex_unlock(&icp_dev->icp_lock);
 	return rc;
 }
 
@@ -192,7 +235,9 @@ static int cam_icp_subdev_close(struct v4l2_subdev *sd,
 	bool crm_active = cam_req_mgr_is_open();
 
 	if (crm_active) {
-		CAM_DBG(CAM_ICP, "CRM is ACTIVE, close should be from CRM");
+		CAM_DBG(CAM_ICP,
+			"CRM is ACTIVE, close should be from CRM for device[%s]",
+			sd->name);
 		return 0;
 	}
 
@@ -204,94 +249,144 @@ const struct v4l2_subdev_internal_ops cam_icp_subdev_internal_ops = {
 	.close = cam_icp_subdev_close,
 };
 
+static inline int cam_icp_subdev_clean_up(uint32_t device_idx)
+{
+	struct cam_icp_subdev *icp_subdev;
+
+	icp_subdev = g_icp_dev[device_idx];
+	icp_subdev->node = NULL;
+	icp_subdev->open_cnt = 0;
+
+	return 0;
+}
+
 static int cam_icp_component_bind(struct device *dev,
 	struct device *master_dev, void *data)
 {
 	int rc = 0, i = 0;
 	struct cam_node *node;
-	struct cam_hw_mgr_intf *hw_mgr_intf;
+	struct cam_hw_mgr_intf hw_mgr_intf;
 	int iommu_hdl = -1;
 	struct platform_device *pdev = to_platform_device(dev);
+	struct cam_icp_subdev *icp_dev;
+	char *subdev_name;
+	uint32_t device_idx;
 
 	if (!pdev) {
-		CAM_ERR(CAM_ICP, "pdev is NULL");
+		CAM_ERR(CAM_ICP, "Invalid params: pdev is %s",
+			CAM_IS_NULL_TO_STR(pdev));
+		return -EINVAL;
+	}
+
+	rc = of_property_read_u32(dev->of_node, "cell-index", &device_idx);
+	if (rc)
+		device_idx = 0;
+
+	if (CAM_ICP_IS_DEV_IDX_INVALID(device_idx)) {
+		CAM_ERR(CAM_ICP, "Invalid device idx: %u exceeds subdev max: %u",
+			device_idx, CAM_ICP_SUBDEV_MAX);
 		return -EINVAL;
 	}
 
-	g_icp_dev.sd.pdev = pdev;
-	g_icp_dev.sd.internal_ops = &cam_icp_subdev_internal_ops;
-	g_icp_dev.sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY;
-	rc = cam_subdev_probe(&g_icp_dev.sd, pdev, CAM_ICP_DEV_NAME,
+	/*
+	 * For targets where only one subdevice exists, cell-index property is not listed
+	 * in the DT node, so the default name and device index are "cam-icp" and 0 respectively
+	 */
+	if (rc)
+		subdev_name = "cam-icp";
+	else
+		subdev_name = cam_icp_subdev_name_arr[device_idx];
+
+	icp_dev = kzalloc(sizeof(struct cam_icp_subdev), GFP_KERNEL);
+	if (!icp_dev) {
+		CAM_ERR(CAM_ICP,
+			"Unable to allocate memory for icp device:%s size:%llu",
+			pdev->name, sizeof(struct cam_icp_subdev));
+		return -ENOMEM;
+	}
+
+	mutex_lock(&g_dev_lock);
+	if (g_icp_dev[device_idx]) {
+		CAM_ERR(CAM_ICP,
+			"Invalid device index: %u for pdev: %s, ICP device for this idx is already bound",
+			device_idx, pdev->name);
+		rc = -EBADSLT;
+		mutex_unlock(&g_dev_lock);
+		goto probe_fail;
+	}
+	g_icp_dev[device_idx] = icp_dev;
+	mutex_unlock(&g_dev_lock);
+
+	icp_dev->sd.internal_ops = &cam_icp_subdev_internal_ops;
+	icp_dev->sd.close_seq_prior = CAM_SD_CLOSE_MEDIUM_PRIORITY;
+	rc = cam_subdev_probe(&icp_dev->sd, pdev, subdev_name,
 		CAM_ICP_DEVICE_TYPE);
 	if (rc) {
-		CAM_ERR(CAM_ICP, "ICP cam_subdev_probe failed");
+		CAM_ERR(CAM_ICP, "device[%s] probe failed", subdev_name);
 		goto probe_fail;
 	}
 
-	node = (struct cam_node *) g_icp_dev.sd.token;
-
-	hw_mgr_intf = kzalloc(sizeof(*hw_mgr_intf), GFP_KERNEL);
-	if (!hw_mgr_intf) {
-		rc = -ENOMEM;
-		CAM_ERR(CAM_ICP, "Memory allocation fail");
-		goto hw_alloc_fail;
-	}
+	node = (struct cam_node *) icp_dev->sd.token;
+	node->sd_handler = cam_icp_subdev_close_internal;
+	node->device_idx = device_idx;
+	mutex_init(&icp_dev->icp_lock);
 
-	rc = cam_icp_hw_mgr_init(pdev->dev.of_node, (uint64_t *)hw_mgr_intf,
+	rc = cam_icp_hw_mgr_init(pdev->dev.of_node, (uint64_t *)(&hw_mgr_intf),
 		&iommu_hdl, cam_icp_dev_mini_dump_cb);
 	if (rc) {
-		CAM_ERR(CAM_ICP, "ICP HW manager init failed: %d", rc);
+		CAM_ERR(CAM_ICP, "device[%s] HW manager init failed: %d", subdev_name, rc);
 		goto hw_init_fail;
 	}
 
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
-		g_icp_dev.ctx_icp[i].base = &g_icp_dev.ctx[i];
-		rc = cam_icp_context_init(&g_icp_dev.ctx_icp[i],
-					hw_mgr_intf, i, iommu_hdl);
+		icp_dev->ctx_icp[i].base = &icp_dev->ctx[i];
+		rc = cam_icp_context_init(&icp_dev->ctx_icp[i],
+			&node->hw_mgr_intf, i, iommu_hdl, subdev_name);
 		if (rc) {
-			CAM_ERR(CAM_ICP, "ICP context init failed");
+			CAM_ERR(CAM_ICP, "device[%s] context init failed", subdev_name);
 			goto ctx_fail;
 		}
 	}
 
-	rc = cam_node_init(node, hw_mgr_intf, g_icp_dev.ctx,
-				CAM_ICP_CTX_MAX, CAM_ICP_DEV_NAME);
+	rc = cam_node_init(node, &hw_mgr_intf, icp_dev->ctx,
+		CAM_ICP_CTX_MAX, subdev_name);
 	if (rc) {
-		CAM_ERR(CAM_ICP, "ICP node init failed");
+		CAM_ERR(CAM_ICP, "device[%s] node init failed", subdev_name);
 		goto ctx_fail;
 	}
 
 	cam_common_register_evt_inject_cb(cam_icp_dev_evt_inject_cb,
 		CAM_COMMON_EVT_INJECT_HW_ICP);
 
-	node->sd_handler = cam_icp_subdev_close_internal;
 	cam_smmu_set_client_page_fault_handler(iommu_hdl,
 		cam_icp_dev_iommu_fault_handler, node);
 
-	g_icp_dev.open_cnt = 0;
-	mutex_init(&g_icp_dev.icp_lock);
+	icp_dev->open_cnt = 0;
 
-	CAM_DBG(CAM_ICP, "Component bound successfully");
+	CAM_DBG(CAM_ICP, "device[%s] id: %u component bound successfully",
+		subdev_name, device_idx);
 
 	return rc;
 
 ctx_fail:
 	for (--i; i >= 0; i--)
-		cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]);
+		cam_icp_context_deinit(&icp_dev->ctx_icp[i]);
+	cam_icp_hw_mgr_deinit();
 hw_init_fail:
-	kfree(hw_mgr_intf);
-hw_alloc_fail:
-	cam_subdev_remove(&g_icp_dev.sd);
+	cam_subdev_remove(&icp_dev->sd);
 probe_fail:
+	cam_icp_subdev_clean_up(device_idx);
 	return rc;
 }
 
 static void cam_icp_component_unbind(struct device *dev,
 	struct device *master_dev, void *data)
 {
-	int i;
-	struct v4l2_subdev *sd;
+	int i, rc;
 	struct platform_device *pdev = to_platform_device(dev);
+	struct v4l2_subdev *sd;
+	struct cam_icp_subdev *icp_dev;
+	uint32_t device_idx;
 
 	if (!pdev) {
 		CAM_ERR(CAM_ICP, "pdev is NULL");
@@ -300,17 +395,33 @@ static void cam_icp_component_unbind(struct device *dev,
 
 	sd = platform_get_drvdata(pdev);
 	if (!sd) {
-		CAM_ERR(CAM_ICP, "V4l2 subdev is NULL");
+		CAM_ERR(CAM_ICP,
+			"V4l2 subdev is NULL for pdev: %s", pdev->name);
 		return;
 	}
 
+	rc = of_property_read_u32(dev->of_node, "cell-index", &device_idx);
+	if (rc)
+		device_idx = 0;
+
+	if (CAM_ICP_IS_DEV_IDX_INVALID(device_idx)) {
+		CAM_ERR(CAM_ICP, "Invalid device idx: %u exceeds subdev max: %u",
+			device_idx, CAM_ICP_SUBDEV_MAX);
+		return;
+	}
+
+	icp_dev = g_icp_dev[device_idx];
+
 	for (i = 0; i < CAM_ICP_CTX_MAX; i++)
-		cam_icp_context_deinit(&g_icp_dev.ctx_icp[i]);
+		cam_icp_context_deinit(&icp_dev->ctx_icp[i]);
 
 	cam_icp_hw_mgr_deinit();
-	cam_node_deinit(g_icp_dev.node);
-	cam_subdev_remove(&g_icp_dev.sd);
-	mutex_destroy(&g_icp_dev.icp_lock);
+	cam_node_deinit(icp_dev->node);
+	cam_subdev_remove(&icp_dev->sd);
+	mutex_destroy(&icp_dev->icp_lock);
+	cam_icp_subdev_clean_up(device_idx);
+
+	CAM_DBG(CAM_ICP, "device[%s] component unbinded successfully", pdev->name);
 }
 
 const static struct component_ops cam_icp_component_ops = {
@@ -322,10 +433,10 @@ static int cam_icp_probe(struct platform_device *pdev)
 {
 	int rc = 0;
 
-	CAM_DBG(CAM_ICP, "Adding ICP component");
+	CAM_DBG(CAM_ICP, "%s Adding ICP component", pdev->name);
 	rc = component_add(&pdev->dev, &cam_icp_component_ops);
 	if (rc)
-		CAM_ERR(CAM_ICP, "failed to add component rc: %d", rc);
+		CAM_ERR(CAM_ICP, "%s failed to add component rc: %d", pdev->name, rc);
 
 	return rc;
 }

+ 10 - 0
drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h

@@ -12,6 +12,10 @@
 #include <media/cam_defs.h>
 #include "cam_cpas_api.h"
 
+
+#define CAM_ICP_SUBDEV_NAME_LEN  32
+#define CAM_ICP_SUBDEV_NAME      "cam-icp"
+
 #define ICP_CLK_TURBO_HZ         600000000
 #define ICP_CLK_SVS_HZ           400000000
 
@@ -33,6 +37,12 @@
 #define CAM_ICP_DUMP_TAG_MAX_LEN 64
 #define CAM_ICP_DUMP_NUM_WORDS   5
 
+enum cam_icp_subdev_id {
+	CAM_ICP0_SUBDEV,
+	CAM_ICP1_SUBDEV,
+	CAM_ICP_SUBDEV_MAX
+};
+
 enum cam_icp_hw_event_type {
 	CAM_ICP_EVT_ID_BUF_DONE,
 	CAM_ICP_EVT_ID_ERROR,