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 <quic_kartanan@quicinc.com>
This commit is contained in:
Karthik Anantha Ram
2023-03-28 13:29:40 -07:00
committed by Camera Software Integration
parent c5af31b5fd
commit 9bf7e70f2d
6 changed files with 273 additions and 4 deletions

View File

@@ -651,6 +651,7 @@ struct cam_hw_inject_evt_param {
* @hw_dump: Function pointer for HW dump * @hw_dump: Function pointer for HW dump
* @hw_recovery: Function pointer for HW recovery callback * @hw_recovery: Function pointer for HW recovery callback
* @hw_inject_evt: Function pointer for HW event injection callback * @hw_inject_evt: Function pointer for HW event injection callback
* @synx_trigger: Function pointer for synx test trigger
* *
*/ */
struct cam_hw_mgr_intf { 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_dump)(void *hw_priv, void *hw_dump_args);
int (*hw_recovery)(void *hw_priv, void *hw_recovery_args); int (*hw_recovery)(void *hw_priv, void *hw_recovery_args);
void (*hw_inject_evt)(void *hw_priv, void *evt_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_ */ #endif /* _CAM_HW_MGR_INTF_H_ */

View File

@@ -736,6 +736,26 @@ int cam_node_shutdown(struct cam_node *node)
return 0; 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, 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) struct cam_context *ctx_list, uint32_t ctx_size, char *name)
{ {
@@ -1030,6 +1050,21 @@ release_kfree:
} }
break; 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: default:
CAM_ERR(CAM_CORE, "Unknown op code %d", cmd->op_code); CAM_ERR(CAM_CORE, "Unknown op code %d", cmd->op_code);
rc = -EINVAL; rc = -EINVAL;

View File

@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
/* /*
* Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. * 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 #ifndef _CAM_HFI_SESSION_DEFS_H
@@ -595,4 +595,23 @@ struct hfi_msg_ipe_frame_process {
uint64_t user_data; uint64_t user_data;
} __packed; } __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 */ #endif /* _CAM_HFI_SESSION_DEFS_H */

View File

@@ -122,6 +122,7 @@
#define HFI_CMD_DBG_COMMON_START \ #define HFI_CMD_DBG_COMMON_START \
(HFI_DOMAIN_BASE_DBG + HFI_CMD_START_OFFSET + 0x0) (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_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) #define HFI_CMD_DBG_END (HFI_CMD_DBG_COMMON_START + 0xFFF)
/* System level messages */ /* System level messages */
@@ -192,8 +193,10 @@
/* ICP core level Debug test message range */ /* ICP core level Debug test message range */
#define HFI_MSG_DBG_COMMON_START \ #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_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) #define HFI_MSG_DBG_END (HFI_MSG_DBG_COMMON_START + 0xFFF)
/* System level property base offset */ /* System level property base offset */

View File

@@ -3070,6 +3070,11 @@ static int cam_icp_process_msg_pkt_type(
break; 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: default:
CAM_ERR(CAM_ICP, "[%s] invalid msg : %u", CAM_ERR(CAM_ICP, "[%s] invalid msg : %u",
hw_mgr->hw_mgr_name, msg_ptr[ICP_PACKET_TYPE]); 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; bool send_freq_info = true;
CAM_DBG(CAM_PERF, "[%s] ENTER", hw_mgr->hw_mgr_name); CAM_DBG(CAM_PERF, "[%s] ENTER", hw_mgr->hw_mgr_name);
if (!icp_dev_intf) { if (!icp_dev_intf) {
CAM_ERR(CAM_ICP, "[%s] ICP device interface is NULL", hw_mgr->hw_mgr_name); CAM_ERR(CAM_ICP, "[%s] ICP device interface is NULL", hw_mgr->hw_mgr_name);
return -EINVAL; return -EINVAL;
@@ -6600,6 +6604,137 @@ static int cam_icp_mgr_hw_dump(void *hw_priv, void *hw_dump_args)
return rc; 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) static int cam_icp_mgr_hw_flush(void *hw_priv, void *hw_flush_args)
{ {
struct cam_hw_flush_args *flush_args = 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_intf->hw_inject_evt = cam_icp_mgr_inject_evt;
hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE; hw_mgr->secure_mode = CAM_SECURE_MODE_NON_SECURE;
hw_mgr->mini_dump_cb = mini_dump_cb; 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); mutex_init(&hw_mgr->hw_mgr_mutex);
spin_lock_init(&hw_mgr->hw_mgr_lock); spin_lock_init(&hw_mgr->hw_mgr_lock);

View File

@@ -1,7 +1,7 @@
/* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */ /* SPDX-License-Identifier: GPL-2.0-only WITH Linux-syscall-note */
/* /*
* Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * 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__ #ifndef __UAPI_CAM_DEFS_H__
@@ -30,6 +30,7 @@
#define CAM_RELEASE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x2) #define CAM_RELEASE_HW (CAM_COMMON_OPCODE_BASE_v2 + 0x2)
#define CAM_DUMP_REQ (CAM_COMMON_OPCODE_BASE_v2 + 0x3) #define CAM_DUMP_REQ (CAM_COMMON_OPCODE_BASE_v2 + 0x3)
#define CAM_QUERY_CAP_V3 (CAM_COMMON_OPCODE_BASE_v2 + 0x4) #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_EXT_OPCODE_BASE 0x200
#define CAM_CONFIG_DEV_EXTERNAL (CAM_EXT_OPCODE_BASE + 0x1) #define CAM_CONFIG_DEV_EXTERNAL (CAM_EXT_OPCODE_BASE + 0x1)
@@ -258,6 +259,10 @@ struct cam_iommu_handle {
/* constants */ /* constants */
#define CAM_PACKET_MAX_PLANES 3 #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 * struct cam_plane_cfg - Plane configuration info
* *
@@ -907,4 +912,73 @@ struct cam_dump_req_cmd {
__s32 dev_handle; __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__ */ #endif /* __UAPI_CAM_DEFS_H__ */