Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 2743a0db authored by Lakshmi Narayana Kalavala's avatar Lakshmi Narayana Kalavala
Browse files

msm: camera: icp: Add timeout for hfi commands and fix hardcode values



This patch does the following changes:

1.ICP driver waits indefinitely for the hfi commands, which
can lead to camera hang if firmware does not respond.
Hence using the wait_for_completion_timeout instead
of wait_for_completion.

2. Use the HFI shared memory region information from camera
memory manager instead of hard coded values.

3. Add debugfs entry to enable runtime debug on A5 core.

4. Remove msleep and use readw_poll_timeout for reading
the HFI_REG_ICP_HOST_INIT_RESPONSE status.

Change-Id: Id4987e62feff4ccbd06266a18c669cbb4d90ca2d
Signed-off-by: default avatarLakshmi Narayana Kalavala <lkalaval@codeaurora.org>
parent 6a9b4102
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -44,6 +44,7 @@ struct hfi_mem_info {
	struct hfi_mem msg_q;
	struct hfi_mem dbg_q;
	struct hfi_mem sec_heap;
	struct hfi_mem shmem;
	void __iomem *icp_base;
};

+11 −15
Original line number Diff line number Diff line
@@ -19,6 +19,8 @@
#include <asm/errno.h>
#include <linux/timer.h>
#include <media/cam_icp.h>
#include <linux/iopoll.h>

#include "cam_io_util.h"
#include "hfi_reg.h"
#include "hfi_sys_defs.h"
@@ -460,8 +462,10 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
	}

	cam_io_w((uint32_t)hfi_mem->qtbl.iova, icp_base + HFI_REG_QTBL_PTR);
	cam_io_w((uint32_t)0x7400000, icp_base + HFI_REG_SHARED_MEM_PTR);
	cam_io_w((uint32_t)0x6400000, icp_base + HFI_REG_SHARED_MEM_SIZE);
	cam_io_w((uint32_t)hfi_mem->shmem.iova,
		icp_base + HFI_REG_SHARED_MEM_PTR);
	cam_io_w((uint32_t)hfi_mem->shmem.len,
		icp_base + HFI_REG_SHARED_MEM_SIZE);
	cam_io_w((uint32_t)hfi_mem->sec_heap.iova,
		icp_base + HFI_REG_UNCACHED_HEAP_PTR);
	cam_io_w((uint32_t)hfi_mem->sec_heap.len,
@@ -472,25 +476,17 @@ int cam_hfi_init(uint8_t event_driven_mode, struct hfi_mem_info *hfi_mem,
	hw_version = cam_io_r(icp_base + HFI_REG_A5_HW_VERSION);
	pr_debug("hw version : %u[%x]\n", hw_version, hw_version);

	do {
		msleep(500);
		status = cam_io_r(icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE);
	} while (status != ICP_INIT_RESP_SUCCESS);

	if (status == ICP_INIT_RESP_SUCCESS) {
		g_hfi->hfi_state = FW_RESP_DONE;
		rc = 0;
	} else {
		rc = -ENODEV;
		pr_err("FW initialization failed");
	rc = readw_poll_timeout((icp_base + HFI_REG_ICP_HOST_INIT_RESPONSE),
		status, status != ICP_INIT_RESP_SUCCESS, 15, 200);
	if (rc) {
		pr_err("timed out , status = %u\n", status);
		goto regions_fail;
	}

	fw_version = cam_io_r(icp_base + HFI_REG_FW_VERSION);
	g_hfi->hfi_state = FW_START_SENT;

	pr_debug("fw version : %u[%x]\n", fw_version, fw_version);
	pr_debug("hfi init is successful\n");
	HFI_DBG("fw version : %u[%x]\n", fw_version, fw_version);
	cam_io_w((uint32_t)INTR_ENABLE, icp_base + HFI_REG_A5_CSR_A2HOSTINTEN);

	return rc;
+75 −8
Original line number Diff line number Diff line
@@ -26,6 +26,8 @@
#include <linux/debugfs.h>
#include <media/cam_defs.h>
#include <media/cam_icp.h>
#include <linux/debugfs.h>

#include "cam_sync_api.h"
#include "cam_packet_util.h"
#include "cam_hw.h"
@@ -55,6 +57,23 @@

static struct cam_icp_hw_mgr icp_hw_mgr;

static int cam_icp_hw_mgr_create_debugfs_entry(void)
{
	icp_hw_mgr.dentry = debugfs_create_dir("camera_icp", NULL);
	if (!icp_hw_mgr.dentry)
		return -ENOMEM;

	if (!debugfs_create_bool("a5_debug",
		0644,
		icp_hw_mgr.dentry,
		&icp_hw_mgr.a5_debug)) {
		debugfs_remove_recursive(icp_hw_mgr.dentry);
		return -ENOMEM;
	}

	return 0;
}

static int cam_icp_stop_cpas(struct cam_icp_hw_mgr *hw_mgr_priv)
{
	struct cam_hw_intf *a5_dev_intf = NULL;
@@ -568,7 +587,12 @@ static int cam_icp_allocate_hfi_mem(void)
	uint64_t kvaddr;
	size_t len;

	pr_err("Allocating FW for iommu handle: %x\n", icp_hw_mgr.iommu_hdl);
	rc = cam_smmu_get_region_info(icp_hw_mgr.iommu_hdl,
		CAM_MEM_MGR_REGION_SHARED,
		&icp_hw_mgr.hfi_mem.shmem);
	if (rc)
		return -ENOMEM;

	rc = cam_smmu_alloc_firmware(icp_hw_mgr.iommu_hdl,
		&iova, &kvaddr, &len);
	if (rc < 0) {
@@ -764,7 +788,7 @@ static int cam_icp_mgr_destroy_handle(
			msecs_to_jiffies((timeout)));
	if (!rem_jiffies) {
		rc = -ETIMEDOUT;
		pr_err("timeout/err in iconfig command: %d\n", rc);
		pr_err("FW response timeout: %d\n", rc);
	}

	return rc;
@@ -870,6 +894,7 @@ static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args)

	cam_icp_free_hfi_mem();
	hw_mgr->fw_download = false;
	debugfs_remove_recursive(icp_hw_mgr.dentry);
	mutex_unlock(&hw_mgr->hw_mgr_mutex);

	return 0;
@@ -886,6 +911,8 @@ static int cam_icp_mgr_download_fw(void *hw_mgr_priv, void *download_fw_args)
	struct cam_icp_a5_set_irq_cb irq_cb;
	struct cam_icp_a5_set_fw_buf_info fw_buf_info;
	struct hfi_mem_info hfi_mem;
	unsigned long rem_jiffies;
	int timeout = 5000;
	int rc = 0;

	if (!hw_mgr) {
@@ -1014,9 +1041,12 @@ static int cam_icp_mgr_download_fw(void *hw_mgr_priv, void *download_fw_args)
	hfi_mem.sec_heap.iova = icp_hw_mgr.hfi_mem.sec_heap.iova;
	hfi_mem.sec_heap.len = icp_hw_mgr.hfi_mem.sec_heap.len;

	hfi_mem.shmem.iova = icp_hw_mgr.hfi_mem.shmem.iova_start;
	hfi_mem.shmem.len = icp_hw_mgr.hfi_mem.shmem.iova_len;

	rc = cam_hfi_init(0, &hfi_mem,
		a5_dev->soc_info.reg_map[A5_SIERRA_BASE].mem_base,
		false);
		hw_mgr->a5_debug);
	if (rc < 0) {
		pr_err("hfi_init is failed\n");
		goto set_irq_failed;
@@ -1033,7 +1063,13 @@ static int cam_icp_mgr_download_fw(void *hw_mgr_priv, void *download_fw_args)
		NULL, 0);

	ICP_DBG("Wait for INIT DONE Message\n");
	wait_for_completion(&hw_mgr->a5_complete);
	rem_jiffies = wait_for_completion_timeout(&icp_hw_mgr.a5_complete,
			msecs_to_jiffies((timeout)));
	if (!rem_jiffies) {
		rc = -ETIMEDOUT;
		pr_err("FW response timed out %d\n", rc);
		goto set_irq_failed;
	}

	ICP_DBG("Done Waiting for INIT DONE Message\n");

@@ -1041,6 +1077,10 @@ static int cam_icp_mgr_download_fw(void *hw_mgr_priv, void *download_fw_args)
		a5_dev_intf->hw_priv,
		CAM_ICP_A5_CMD_POWER_COLLAPSE,
		NULL, 0);
	if (rc) {
		pr_err("icp power collapse failed\n");
		goto set_irq_failed;
	}

	hw_mgr->fw_download = true;

@@ -1428,6 +1468,8 @@ static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data,
	int rc = 0;
	struct hfi_cmd_work_data *task_data;
	struct hfi_cmd_ipebps_async ioconfig_cmd;
	unsigned long rem_jiffies;
	int timeout = 5000;

	ioconfig_cmd.size = sizeof(struct hfi_cmd_ipebps_async);
	ioconfig_cmd.pkt_type = HFI_CMD_IPEBPS_ASYNC_COMMAND_INDIRECT;
@@ -1451,7 +1493,13 @@ static int cam_icp_mgr_send_config_io(struct cam_icp_hw_ctx_data *ctx_data,
	task->process_cb = cam_icp_mgr_process_cmd;
	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
	ICP_DBG("fw_hdl = %x ctx_data = %pK\n", ctx_data->fw_handle, ctx_data);
	wait_for_completion(&ctx_data->wait_complete);

	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
			msecs_to_jiffies((timeout)));
	if (!rem_jiffies) {
		rc = -ETIMEDOUT;
		pr_err("FW response timed out %d\n", rc);
	}

	return rc;
}
@@ -1462,6 +1510,8 @@ static int cam_icp_mgr_create_handle(uint32_t dev_type,
{
	struct hfi_cmd_create_handle create_handle;
	struct hfi_cmd_work_data *task_data;
	unsigned long rem_jiffies;
	int timeout = 5000;
	int rc = 0;

	create_handle.size = sizeof(struct hfi_cmd_create_handle);
@@ -1479,7 +1529,13 @@ static int cam_icp_mgr_create_handle(uint32_t dev_type,
	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
	task->process_cb = cam_icp_mgr_process_cmd;
	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
	wait_for_completion(&ctx_data->wait_complete);

	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
			msecs_to_jiffies((timeout)));
	if (!rem_jiffies) {
		rc = -ETIMEDOUT;
		pr_err("FW response timed out %d\n", rc);
	}

	return rc;
}
@@ -1489,6 +1545,8 @@ static int cam_icp_mgr_send_ping(struct cam_icp_hw_ctx_data *ctx_data,
{
	struct hfi_cmd_ping_pkt ping_pkt;
	struct hfi_cmd_work_data *task_data;
	unsigned long rem_jiffies;
	int timeout = 5000;
	int rc = 0;

	ping_pkt.size = sizeof(struct hfi_cmd_ping_pkt);
@@ -1505,7 +1563,14 @@ static int cam_icp_mgr_send_ping(struct cam_icp_hw_ctx_data *ctx_data,
	task_data->type = ICP_WORKQ_TASK_CMD_TYPE;
	task->process_cb = cam_icp_mgr_process_cmd;
	cam_req_mgr_workq_enqueue_task(task, &icp_hw_mgr, CRM_TASK_PRIORITY_0);
	wait_for_completion(&ctx_data->wait_complete);

	rem_jiffies = wait_for_completion_timeout(&ctx_data->wait_complete,
			msecs_to_jiffies((timeout)));
	if (!rem_jiffies) {
		rc = -ETIMEDOUT;
		pr_err("FW response timed out %d\n", rc);
	}


	return rc;
}
@@ -1929,6 +1994,9 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl)
	if (!icp_hw_mgr.msg_work_data)
		goto msg_work_data_failed;

	rc = cam_icp_hw_mgr_create_debugfs_entry();
	if (rc)
		goto msg_work_data_failed;

	for (i = 0; i < ICP_WORKQ_NUM_TASK; i++)
		icp_hw_mgr.msg_work->task.pool[i].payload =
@@ -1940,7 +2008,6 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl)

	init_completion(&icp_hw_mgr.a5_complete);

	pr_err("Exit\n");
	return rc;

msg_work_data_failed:
+5 −0
Original line number Diff line number Diff line
@@ -23,6 +23,8 @@
#include "hfi_session_defs.h"
#include "cam_req_mgr_workq.h"
#include "cam_mem_mgr.h"
#include "cam_smmu_api.h"


#define CAM_ICP_ROLE_PARENT     1
#define CAM_ICP_ROLE_CHILD      2
@@ -56,6 +58,7 @@ struct icp_hfi_mem_info {
	struct cam_mem_mgr_memory_desc dbg_q;
	struct cam_mem_mgr_memory_desc sec_heap;
	struct cam_mem_mgr_memory_desc fw_buf;
	struct cam_smmu_region_info shmem;
};

/**
@@ -176,6 +179,8 @@ struct cam_icp_hw_mgr {
	struct hfi_cmd_work_data *cmd_work_data;
	struct hfi_msg_work_data *msg_work_data;
	uint32_t ctxt_cnt;
	struct dentry *dentry;
	bool a5_debug;
};

#endif /* CAM_ICP_HW_MGR_H */