Эх сурвалжийг харах

msm: camera: icp: Add support for synx testing

Add support to receive synx test cmds, and forward it to ICP FW.
Synx on ICP will process that cmd, and send a response. This
response is returned to the caller. The objective of this
infrastructure is to allow synx test app to validate synx
functionality on ICP without running any actual use-case.

CRs-Fixed: 3448052
Change-Id: I3785264f74c5c698146f4de1a82d25fe141cfc2a
Signed-off-by: Karthik Anantha Ram <[email protected]>
Karthik Anantha Ram 2 жил өмнө
parent
commit
9bf7e70f2d

+ 2 - 0
drivers/cam_core/cam_hw_mgr_intf.h

@@ -651,6 +651,7 @@ struct cam_hw_inject_evt_param {
  * @hw_dump:                   Function pointer for HW dump
  * @hw_recovery:               Function pointer for HW recovery callback
  * @hw_inject_evt:             Function pointer for HW event injection callback
+ * @synx_trigger:              Function pointer for synx test trigger
  *
  */
 struct cam_hw_mgr_intf {
@@ -676,6 +677,7 @@ struct cam_hw_mgr_intf {
 	int (*hw_dump)(void *hw_priv, void *hw_dump_args);
 	int (*hw_recovery)(void *hw_priv, void *hw_recovery_args);
 	void (*hw_inject_evt)(void *hw_priv, void *evt_args);
+	int (*synx_trigger)(void *hw_priv, void *synx_params);
 };
 
 #endif /* _CAM_HW_MGR_INTF_H_ */

+ 35 - 0
drivers/cam_core/cam_node.c

@@ -736,6 +736,26 @@ int cam_node_shutdown(struct cam_node *node)
 	return 0;
 }
 
+static int __cam_node_handle_synx_test(
+	struct cam_node *node, void *params)
+{
+	int i, rc = -EINVAL;
+
+	for (i = 0; i < node->ctx_size; i++) {
+		if (node->ctx_list[i].dev_hdl > 0) {
+			CAM_ERR(CAM_CORE, "Node [%s] has active context [%d]",
+				node->name, i);
+			return -EAGAIN;
+		}
+	}
+
+	if (node->hw_mgr_intf.synx_trigger)
+		rc = node->hw_mgr_intf.synx_trigger(
+			node->hw_mgr_intf.hw_mgr_priv, params);
+
+	return rc;
+}
+
 int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
 	struct cam_context *ctx_list, uint32_t ctx_size, char *name)
 {
@@ -1030,6 +1050,21 @@ release_kfree:
 		}
 		break;
 	}
+	case CAM_SYNX_TEST_TRIGGER: {
+		struct cam_synx_test_params synx_params;
+
+		if (copy_from_user(&synx_params, u64_to_user_ptr(cmd->handle),
+			sizeof(synx_params))) {
+			rc = -EFAULT;
+			break;
+		}
+
+		rc = __cam_node_handle_synx_test(node, &synx_params);
+		if (rc)
+			CAM_ERR(CAM_CORE, "Synx test on %s failed(rc = %d)",
+			    node->name, rc);
+		break;
+	}
 	default:
 		CAM_ERR(CAM_CORE, "Unknown op code %d", cmd->op_code);
 		rc = -EINVAL;

+ 20 - 1
drivers/cam_icp/fw_inc/hfi_session_defs.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
  * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef _CAM_HFI_SESSION_DEFS_H
@@ -595,4 +595,23 @@ struct hfi_msg_ipe_frame_process {
 	uint64_t user_data;
 } __packed;
 
+/**
+ * struct hfi_cmd_synx_test_payload
+ *        Same struct used for cmd and response
+ *
+ * @size: Size of the pkt
+ * @pkt_type: pkt type (cmd/response)
+ * @input_size: Input buffer size
+ * @input_iova: Input buffer address
+ * @output_size: Output buffer size
+ * @output_iova: Output buffer address
+ */
+struct hfi_cmd_synx_test_payload {
+	uint32_t size;
+	uint32_t pkt_type;
+	uint32_t input_size;
+	uint32_t input_iova;
+	uint32_t output_size;
+	uint32_t output_iova;
+} __packed;
 #endif /* _CAM_HFI_SESSION_DEFS_H */

+ 4 - 1
drivers/cam_icp/fw_inc/hfi_sys_defs.h

@@ -122,6 +122,7 @@
 #define HFI_CMD_DBG_COMMON_START \
 		(HFI_DOMAIN_BASE_DBG + HFI_CMD_START_OFFSET + 0x0)
 #define HFI_CMD_DBG_TEST_START  (HFI_CMD_DBG_COMMON_START + 0x800)
+#define HFI_CMD_DBG_SYNX_TEST   (HFI_CMD_DBG_TEST_START + 0x1)
 #define HFI_CMD_DBG_END         (HFI_CMD_DBG_COMMON_START + 0xFFF)
 
 /* System level messages */
@@ -192,8 +193,10 @@
 
 /* ICP core level Debug test message range */
 #define HFI_MSG_DBG_COMMON_START \
-		(HFI_DOMAIN_BASE_DBG + 0x0)
+		(HFI_DOMAIN_BASE_DBG + HFI_MSG_START_OFFSET + 0x0)
+
 #define HFI_MSG_DBG_TEST_START  (HFI_MSG_DBG_COMMON_START + 0x800)
+#define HFI_MSG_DBG_SYNX_TEST   (HFI_MSG_DBG_TEST_START + 0x1)
 #define HFI_MSG_DBG_END         (HFI_MSG_DBG_COMMON_START + 0xFFF)
 
 /* System  level property base offset */

+ 137 - 1
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c

@@ -3070,6 +3070,11 @@ static int cam_icp_process_msg_pkt_type(
 
 		break;
 
+	case HFI_MSG_DBG_SYNX_TEST:
+		CAM_DBG(CAM_ICP, "received DBG_SYNX_TEST");
+		size_processed = sizeof(struct hfi_cmd_synx_test_payload);
+		complete(&hw_mgr->icp_complete);
+		break;
 	default:
 		CAM_ERR(CAM_ICP, "[%s] invalid msg : %u",
 			hw_mgr->hw_mgr_name, msg_ptr[ICP_PACKET_TYPE]);
@@ -3969,7 +3974,6 @@ static int cam_icp_mgr_icp_power_collapse(struct cam_icp_hw_mgr *hw_mgr)
 	bool send_freq_info = true;
 
 	CAM_DBG(CAM_PERF, "[%s] ENTER", hw_mgr->hw_mgr_name);
-
 	if (!icp_dev_intf) {
 		CAM_ERR(CAM_ICP, "[%s] ICP device interface is NULL", hw_mgr->hw_mgr_name);
 		return -EINVAL;
@@ -6600,6 +6604,137 @@ static int cam_icp_mgr_hw_dump(void *hw_priv, void *hw_dump_args)
 	return rc;
 }
 
+static int cam_icp_mgr_synx_core_control(
+	struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_synx_core_control *synx_core_ctrl)
+{
+	int rc;
+
+	if (synx_core_ctrl->core_control) {
+		rc = cam_icp_mgr_icp_resume(hw_mgr);
+		if (!rc)
+			/* Set FW log level for synx */
+			if (hw_mgr->icp_debug_type)
+				hfi_set_debug_level(hw_mgr->hfi_handle,
+					hw_mgr->icp_debug_type, hw_mgr->icp_dbg_lvl);
+	} else {
+		rc = cam_icp_mgr_icp_power_collapse(hw_mgr);
+	}
+
+	if (rc)
+		CAM_ERR(CAM_ICP, "[%s] Failed to process core control resume: %s",
+			hw_mgr->hw_mgr_name, CAM_BOOL_TO_YESNO(synx_core_ctrl->core_control));
+
+	CAM_INFO(CAM_ICP, "Synx test core control: %s done rc: %d",
+		CAM_BOOL_TO_YESNO(synx_core_ctrl->core_control), rc);
+	return rc;
+}
+
+static int cam_icp_mgr_synx_send_test_cmd(
+	struct cam_icp_hw_mgr *hw_mgr,
+	struct cam_synx_test_cmd *synx_test_params)
+{
+	int rc = 0;
+	size_t size;
+	dma_addr_t iova;
+	struct hfi_cmd_synx_test_payload synx_test_cmd;
+	unsigned long rem_jiffies;
+	int timeout = 5000;
+
+	if (!hw_mgr->icp_resumed) {
+		rc = cam_icp_mgr_icp_resume(hw_mgr);
+		if (rc) {
+			CAM_ERR(CAM_ICP, "Failed to resume ICP rc: %d", rc);
+			goto end;
+		}
+
+		/* Set FW log level for synx */
+		if (hw_mgr->icp_debug_type)
+			hfi_set_debug_level(hw_mgr->hfi_handle,
+				hw_mgr->icp_debug_type, hw_mgr->icp_dbg_lvl);
+	}
+
+	synx_test_cmd.pkt_type = HFI_CMD_DBG_SYNX_TEST;
+	synx_test_cmd.size = sizeof(synx_test_cmd);
+
+	rc = cam_mem_get_io_buf(synx_test_params->ip_mem_hdl, hw_mgr->iommu_hdl,
+		&iova, &size, NULL);
+	if (rc) {
+		CAM_ERR(CAM_ICP, "Failed to get buf for hdl: %d rc: %d",
+			synx_test_params->ip_mem_hdl, rc);
+		goto end;
+	}
+
+	synx_test_cmd.input_iova = (uint32_t)iova;
+	synx_test_cmd.input_size = (uint32_t)size;
+
+	rc = cam_mem_get_io_buf(synx_test_params->op_mem_hdl, hw_mgr->iommu_hdl,
+		&iova, &size, NULL);
+	if (rc) {
+		CAM_ERR(CAM_ICP, "Failed to get buf for hdl: %d rc: %d",
+			synx_test_params->ip_mem_hdl, rc);
+		goto end;
+	}
+
+	synx_test_cmd.output_iova = (uint32_t)iova;
+	synx_test_cmd.output_size = (uint32_t)size;
+
+	CAM_DBG(CAM_ICP,
+		"Input (hdl: 0x%x iova: 0x%x size: 0x%x) output (hdl: 0x%x iova: 0x%x size: 0x%x)",
+		synx_test_params->ip_mem_hdl, synx_test_cmd.input_iova, synx_test_cmd.input_size,
+		synx_test_params->op_mem_hdl, synx_test_cmd.output_iova, synx_test_cmd.output_size);
+
+	reinit_completion(&hw_mgr->icp_complete);
+	rc = hfi_write_cmd(hw_mgr->hfi_handle, &synx_test_cmd);
+	if (rc)
+		goto end;
+
+	rem_jiffies = CAM_COMMON_WAIT_FOR_COMPLETION_TIMEOUT_ERRMSG(
+			&hw_mgr->icp_complete, msecs_to_jiffies(timeout), CAM_ICP,
+			"FW response timeout for synx test cmd");
+	if (!rem_jiffies) {
+		rc = -ETIMEDOUT;
+		goto end;
+	}
+
+	CAM_INFO(CAM_ICP, "Synx test cmd done rc: %d", rc);
+
+end:
+	return rc;
+}
+
+static int cam_icp_mgr_service_synx_test_cmds(void *hw_priv, void *synx_args)
+{
+	int rc;
+	struct cam_icp_hw_mgr *hw_mgr = hw_priv;
+	struct cam_synx_test_params *synx_params;
+
+	if ((!hw_priv) || (!synx_args)) {
+		CAM_ERR(CAM_ICP, "Input params are Null:");
+		return -EINVAL;
+	}
+
+	synx_params = (struct cam_synx_test_params *)synx_args;
+	mutex_lock(&hw_mgr->hw_mgr_mutex);
+	switch (synx_params->cmd_type) {
+	case CAM_SYNX_TEST_CMD_TYPE_CORE_CTRL: {
+		rc = cam_icp_mgr_synx_core_control(hw_mgr, &synx_params->u.core_ctrl);
+	}
+		break;
+	case CAM_SYNX_TEST_CMD_TYPE_SYNX_CMD: {
+		rc = cam_icp_mgr_synx_send_test_cmd(hw_mgr, &synx_params->u.test_cmd);
+	}
+		break;
+	default:
+		rc = -EINVAL;
+		goto end;
+	}
+
+end:
+	mutex_unlock(&hw_mgr->hw_mgr_mutex);
+	return rc;
+}
+
 static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args)
 {
 	struct cam_hw_flush_args *flush_args = hw_flush_args;
@@ -8007,6 +8142,7 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 	hw_mgr_intf->hw_inject_evt = cam_icp_mgr_inject_evt;
 	hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
 	hw_mgr->mini_dump_cb = mini_dump_cb;
+	hw_mgr_intf->synx_trigger = cam_icp_mgr_service_synx_test_cmds;
 
 	mutex_init(&hw_mgr->hw_mgr_mutex);
 	spin_lock_init(&hw_mgr->hw_mgr_lock);

+ 75 - 1
include/uapi/camera/media/cam_defs.h

@@ -1,7 +1,7 @@
 /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
 /*
  * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved.
- * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved.
+ * Copyright (c) 2022-2023 Qualcomm Innovation Center, Inc. All rights reserved.
  */
 
 #ifndef __UAPI_CAM_DEFS_H__
@@ -30,6 +30,7 @@
 #define CAM_RELEASE_HW                      (CAM_COMMON_OPCODE_BASE_v2 + 0x2)
 #define CAM_DUMP_REQ                        (CAM_COMMON_OPCODE_BASE_v2 + 0x3)
 #define CAM_QUERY_CAP_V3                    (CAM_COMMON_OPCODE_BASE_v2 + 0x4)
+#define CAM_SYNX_TEST_TRIGGER               (CAM_COMMON_OPCODE_BASE_v2 + 0x5)
 
 #define CAM_EXT_OPCODE_BASE                     0x200
 #define CAM_CONFIG_DEV_EXTERNAL                 (CAM_EXT_OPCODE_BASE + 0x1)
@@ -258,6 +259,10 @@ struct cam_iommu_handle {
 /* constants */
 #define CAM_PACKET_MAX_PLANES                   3
 
+/* synx test cmd types */
+#define CAM_SYNX_TEST_CMD_TYPE_CORE_CTRL       1
+#define CAM_SYNX_TEST_CMD_TYPE_SYNX_CMD        2
+
 /**
  * struct cam_plane_cfg - Plane configuration info
  *
@@ -907,4 +912,73 @@ struct cam_dump_req_cmd {
 	__s32           dev_handle;
 };
 
+/**
+ * struct cam_synx_test_cmd - Synx test cmds
+ *
+ * @version: Struct version
+ * @ip_mem_hdl: Input buf mem handle
+ *              corresponds to synx test inputs to the
+ *              fencing core
+ * @op_mem_hdl: Output buf mem handle
+ *              corresponds to synx output generated by
+ *              the fencing core
+ * @num_valid_params: Num valid params
+ * @valid_param_mask: Valid param mask
+ * @params: additional params
+ */
+struct cam_synx_test_cmd {
+	__u32 version;
+	__s32 ip_mem_hdl;
+	__s32 op_mem_hdl;
+	__u32 num_valid_params;
+	__u32 valid_param_mask;
+	__u32 params[5];
+};
+
+/**
+ * struct cam_synx_core_control - Synx core ctrl
+ *
+ * @version: Struct version
+ * @core_control: Set for resume, unset for collapse
+ * @num_valid_params: Num valid params
+ * @valid_param_mask: Valid param mask
+ * @params: additional params
+ */
+struct cam_synx_core_control {
+	__u32 version;
+	__u32 core_control;
+	__u32 num_valid_params;
+	__u32 valid_param_mask;
+	__u32 params[4];
+};
+
+
+/**
+ * struct cam_synx_test_params - Synx test params
+ *
+ * A test sequence could include creating and signaling
+ * synx handle between ICP <-> APPs. These test params
+ * would be cmds such as session initialize, synx create,
+ * synx async wait, synx signal and so on
+ *
+ * @version: Struct version
+ * @cmd_type: Type of test cmd - core control/synx cmd/...
+ * @num_valid_params: Num valid params
+ * @valid_param_mask: Valid param mask
+ * @params: additional params
+ * @test_cmd: Synx test cmd forwarded to the core
+ * @core_ctrl: Synx test cmd to control fencing core
+ */
+struct cam_synx_test_params {
+	__u32 version;
+	__u32 cmd_type;
+	__u32 num_valid_params;
+	__u32 valid_param_mask;
+	__u32 params[4];
+	union {
+		struct cam_synx_test_cmd test_cmd;
+		struct cam_synx_core_control core_ctrl;
+	} u;
+} __attribute__((__packed__));
+
 #endif /* __UAPI_CAM_DEFS_H__ */