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

msm: camera: isp: Dump previous acq ctx info on acq failure

In case acquire hw fails, dump the previously acquired
streams to infer the reason for the failure.

CRs-Fixed: 2512474
Change-Id: I3ee2b85e0843ab4a605625950dc60366c0b50713
Signed-off-by: Karthik Anantha Ram <[email protected]>
Karthik Anantha Ram 6 жил өмнө
parent
commit
03e52e70d6

+ 25 - 0
drivers/cam_core/cam_context.c

@@ -493,6 +493,31 @@ int cam_context_handle_stop_dev(struct cam_context *ctx,
 	return rc;
 }
 
+int cam_context_handle_info_dump(void *context,
+	enum cam_context_dump_id id)
+{
+	int rc = 0;
+	struct cam_context *ctx = (struct cam_context *)context;
+
+	if (!ctx || !ctx->state_machine) {
+		CAM_ERR(CAM_CORE, "Context is not ready");
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	if (ctx->state_machine[ctx->state].dumpinfo_ops)
+		rc = ctx->state_machine[ctx->state].dumpinfo_ops(ctx,
+			id);
+	mutex_unlock(&ctx->ctx_mutex);
+
+	if (rc)
+		CAM_WARN(CAM_CORE,
+			"Dump for id %u failed on ctx_id %u name %s state %d",
+			id, ctx->ctx_id, ctx->dev_name, ctx->state);
+
+	return rc;
+}
+
 int cam_context_init(struct cam_context *ctx,
 	const char *dev_name,
 	uint64_t dev_id,

+ 16 - 0
drivers/cam_core/cam_context.h

@@ -138,6 +138,8 @@ struct cam_ctx_crm_ops {
  * @crm_ops:               CRM to context interface function table
  * @irq_ops:               Hardware event handle function
  * @pagefault_ops:         Function to be called on page fault
+ * @dumpinfo_ops:          Function to be invoked for dumping any
+ *                         context info
  *
  */
 struct cam_ctx_ops {
@@ -145,6 +147,7 @@ struct cam_ctx_ops {
 	struct cam_ctx_crm_ops       crm_ops;
 	cam_hw_event_cb_func         irq_ops;
 	cam_hw_pagefault_cb_func     pagefault_ops;
+	cam_ctx_info_dump_cb_func    dumpinfo_ops;
 };
 
 /**
@@ -406,6 +409,19 @@ int cam_context_handle_start_dev(struct cam_context *ctx,
 int cam_context_handle_stop_dev(struct cam_context *ctx,
 		struct cam_start_stop_dev_cmd *cmd);
 
+/**
+ * cam_context_handle_info_dump()
+ *
+ * @brief:        Handle any dump info for the context
+ *
+ * @ctx:          Object pointer for cam_context
+ * @id:           To indicate which info pertaining
+ *                to that ctx needs to be dumped
+ *
+ */
+int cam_context_handle_info_dump(void *context,
+	enum cam_context_dump_id id);
+
 /**
  * cam_context_deinit()
  *

+ 29 - 0
drivers/cam_core/cam_context_utils.c

@@ -1016,3 +1016,32 @@ int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx,
 end:
 	return rc;
 }
+
+int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx)
+{
+	int rc = 0;
+	struct cam_hw_cmd_args cmd_args;
+
+	if (!ctx) {
+		CAM_ERR(CAM_CTXT, "Invalid input params");
+		rc = -EINVAL;
+		goto end;
+	}
+
+	if (!ctx->hw_mgr_intf) {
+		CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+			ctx->dev_name, ctx->ctx_id);
+		rc = -EFAULT;
+		goto end;
+	}
+
+	if (ctx->hw_mgr_intf->hw_cmd) {
+		cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+		cmd_args.cmd_type = CAM_HW_MGR_CMD_DUMP_ACQ_INFO;
+		ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv,
+			&cmd_args);
+	}
+
+end:
+	return rc;
+}

+ 2 - 1
drivers/cam_core/cam_context_utils.h

@@ -1,6 +1,6 @@
 /* SPDX-License-Identifier: GPL-2.0-only */
 /*
- * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
+ * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved.
  */
 
 #ifndef _CAM_CONTEXT_UTILS_H_
@@ -29,5 +29,6 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx,
 int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx,
 	struct cam_packet *packet, unsigned long iova, uint32_t buf_info,
 	bool *mem_found);
+int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx);
 
 #endif /* _CAM_CONTEXT_UTILS_H_ */

+ 16 - 0
drivers/cam_core/cam_hw_mgr_intf.h

@@ -24,6 +24,17 @@
 /* Maximum reg dump cmd buffer entries in a context */
 #define CAM_REG_DUMP_MAX_BUF_ENTRIES        10
 
+/**
+ * enum cam_context_dump_id -
+ *              context dump type
+ *
+ */
+enum cam_context_dump_id {
+	CAM_CTX_DUMP_TYPE_NONE,
+	CAM_CTX_DUMP_ACQ_INFO,
+	CAM_CTX_DUMP_TYPE_MAX,
+};
+
 /* hardware event callback function type */
 typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id,
 	void *evt_data);
@@ -32,6 +43,10 @@ typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id,
 typedef int (*cam_hw_pagefault_cb_func)(void *context, unsigned long iova,
 	uint32_t buf_info);
 
+/* ctx dump callback function type */
+typedef int (*cam_ctx_info_dump_cb_func)(void *context,
+	enum cam_context_dump_id dump_id);
+
 /**
  * struct cam_hw_update_entry - Entry for hardware config
  *
@@ -276,6 +291,7 @@ enum cam_hw_mgr_command {
 	CAM_HW_MGR_CMD_DUMP_PF_INFO,
 	CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH,
 	CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR,
+	CAM_HW_MGR_CMD_DUMP_ACQ_INFO,
 };
 
 /**

+ 12 - 4
drivers/cam_core/cam_node.c

@@ -122,6 +122,16 @@ err:
 	return rc;
 }
 
+static void __cam_node_handle_acquired_hw_dump(
+	struct cam_node *node)
+{
+	int i;
+
+	for (i = 0; i < node->ctx_size; i++)
+		cam_context_handle_info_dump(&(node->ctx_list[i]),
+			CAM_CTX_DUMP_ACQ_INFO);
+}
+
 static int __cam_node_handle_acquire_hw_v1(struct cam_node *node,
 	struct cam_acquire_hw_cmd_v1 *acquire)
 {
@@ -158,6 +168,7 @@ static int __cam_node_handle_acquire_hw_v1(struct cam_node *node,
 	if (rc) {
 		CAM_ERR(CAM_CORE, "Acquire device failed for node %s",
 			node->name);
+		__cam_node_handle_acquired_hw_dump(node);
 		return rc;
 	}
 
@@ -197,6 +208,7 @@ static int __cam_node_handle_acquire_hw_v2(struct cam_node *node,
 	if (rc) {
 		CAM_ERR(CAM_CORE, "Acquire device failed for node %s",
 			node->name);
+		__cam_node_handle_acquired_hw_dump(node);
 		return rc;
 	}
 
@@ -734,7 +746,6 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd)
 					"acquire device failed(rc = %d)", rc);
 				goto acquire_kfree;
 			}
-			CAM_INFO(CAM_CORE, "Acquire HW successful");
 		} else if (api_version == 2) {
 			rc = __cam_node_handle_acquire_hw_v2(node, acquire_ptr);
 			if (rc) {
@@ -742,7 +753,6 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd)
 					"acquire device failed(rc = %d)", rc);
 				goto acquire_kfree;
 			}
-			CAM_INFO(CAM_CORE, "Acquire HW successful");
 		}
 
 		if (copy_to_user((void __user *)cmd->handle, acquire_ptr,
@@ -849,8 +859,6 @@ acquire_kfree:
 					"release device failed(rc = %d)", rc);
 		}
 
-		CAM_INFO(CAM_CORE, "Release HW done(rc = %d)", rc);
-
 release_kfree:
 		kfree(release_ptr);
 		break;

+ 21 - 1
drivers/cam_isp/cam_isp_context.c

@@ -139,6 +139,24 @@ static void __cam_isp_ctx_dump_state_monitor_array(
 	}
 }
 
+static int cam_isp_context_info_dump(void *context,
+	enum cam_context_dump_id id)
+{
+	struct cam_context *ctx = (struct cam_context *)context;
+
+	switch (id) {
+	case CAM_CTX_DUMP_ACQ_INFO: {
+		cam_context_dump_hw_acq_info(ctx);
+		break;
+	}
+	default:
+		CAM_DBG(CAM_ISP, "DUMP id not valid %u", id);
+		break;
+	}
+
+	return 0;
+}
+
 static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp)
 {
 	int i = 0, rc = 0;
@@ -3365,7 +3383,6 @@ end:
 	return rc;
 }
 
-
 static int __cam_isp_ctx_acquire_hw_in_acquired(struct cam_context *ctx,
 	void *args)
 {
@@ -3904,6 +3921,7 @@ static struct cam_ctx_ops
 		},
 		.irq_ops = NULL,
 		.pagefault_ops = cam_isp_context_dump_active_request,
+		.dumpinfo_ops = cam_isp_context_info_dump,
 	},
 	/* Ready */
 	{
@@ -3919,6 +3937,7 @@ static struct cam_ctx_ops
 		},
 		.irq_ops = NULL,
 		.pagefault_ops = cam_isp_context_dump_active_request,
+		.dumpinfo_ops = cam_isp_context_info_dump,
 	},
 	/* Activated */
 	{
@@ -3936,6 +3955,7 @@ static struct cam_ctx_ops
 		},
 		.irq_ops = __cam_isp_ctx_handle_irq_in_activated,
 		.pagefault_ops = cam_isp_context_dump_active_request,
+		.dumpinfo_ops = cam_isp_context_info_dump,
 	},
 };
 

+ 221 - 5
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -471,6 +471,206 @@ static int cam_ife_hw_mgr_free_hw_res(
 	return 0;
 }
 
+static const char *cam_ife_hw_mgr_get_res_state(
+	uint32_t res_state)
+{
+	switch (res_state) {
+	case CAM_ISP_RESOURCE_STATE_UNAVAILABLE:
+		return "UNAVAILABLE";
+	case CAM_ISP_RESOURCE_STATE_AVAILABLE:
+		return "AVAILABLE";
+	case CAM_ISP_RESOURCE_STATE_RESERVED:
+		return "RESERVED";
+	case CAM_ISP_RESOURCE_STATE_INIT_HW:
+		return "HW INIT DONE";
+	case CAM_ISP_RESOURCE_STATE_STREAMING:
+		return "STREAMING";
+	default:
+		return "INVALID STATE";
+	}
+}
+
+static const char *cam_ife_hw_mgr_get_csid_res_id(
+	uint32_t res_id)
+{
+	switch (res_id) {
+	case CAM_IFE_PIX_PATH_RES_RDI_0:
+		return "RDI_0";
+	case CAM_IFE_PIX_PATH_RES_RDI_1:
+		return "RDI_1";
+	case CAM_IFE_PIX_PATH_RES_RDI_2:
+		return "RDI_2";
+	case CAM_IFE_PIX_PATH_RES_RDI_3:
+		return "RDI_3";
+	case CAM_IFE_PIX_PATH_RES_IPP:
+		return "IPP";
+	case CAM_IFE_PIX_PATH_RES_PPP:
+		return "PPP";
+	default:
+		return "INVALID";
+	}
+}
+
+static const char *cam_ife_hw_mgr_get_src_res_id(
+	uint32_t res_id)
+{
+	switch (res_id) {
+	case CAM_ISP_HW_VFE_IN_CAMIF:
+		return "CAMIF";
+	case CAM_ISP_HW_VFE_IN_TESTGEN:
+		return "TESTGEN";
+	case CAM_ISP_HW_VFE_IN_RD:
+		return "BUS_RD";
+	case CAM_ISP_HW_VFE_IN_RDI0:
+		return "RDI_0";
+	case CAM_ISP_HW_VFE_IN_RDI1:
+		return "RDI_1";
+	case CAM_ISP_HW_VFE_IN_RDI2:
+		return "RDI_2";
+	case CAM_ISP_HW_VFE_IN_RDI3:
+		return "RDI_3";
+	case CAM_ISP_HW_VFE_IN_PDLIB:
+		return "PDLIB";
+	case CAM_ISP_HW_VFE_IN_LCR:
+		return "LCR";
+	default:
+		return "INVALID";
+	}
+}
+
+static void cam_ife_hw_mgr_dump_src_acq_info(
+	struct cam_ife_hw_mgr_ctx    *hwr_mgr_ctx,
+	uint32_t num_pix_port, uint32_t num_rdi_port)
+{
+	struct cam_ife_hw_mgr_res    *hw_mgr_res = NULL;
+	struct cam_ife_hw_mgr_res    *hw_mgr_res_temp = NULL;
+	struct cam_isp_resource_node *hw_res = NULL;
+	int i = 0;
+
+	CAM_INFO(CAM_ISP,
+		"Acquired HW for ctx: %u with pix_port: %u rdi_port: %u",
+		hwr_mgr_ctx->ctx_index, num_pix_port, num_rdi_port);
+	list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
+		&hwr_mgr_ctx->res_list_ife_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			hw_res = hw_mgr_res->hw_res[i];
+			if (hw_res && hw_res->hw_intf)
+				CAM_INFO(CAM_ISP,
+					"IFE src split_id: %d res_id: %s hw_idx: %u state: %s",
+					i,
+					cam_ife_hw_mgr_get_src_res_id(
+					hw_res->res_id),
+					hw_res->hw_intf->hw_idx,
+					cam_ife_hw_mgr_get_res_state
+					(hw_res->res_state));
+		}
+	}
+}
+
+static void cam_ife_hw_mgr_dump_acq_data(
+	struct cam_ife_hw_mgr_ctx    *hwr_mgr_ctx)
+{
+	struct cam_ife_hw_mgr_res    *hw_mgr_res = NULL;
+	struct cam_ife_hw_mgr_res    *hw_mgr_res_temp = NULL;
+	struct cam_isp_resource_node *hw_res = NULL;
+	struct timespec64            *ts = NULL;
+	uint64_t ms, tmp;
+	int i = 0, j = 0;
+
+	ts = &hwr_mgr_ctx->ts;
+	tmp = ts->tv_sec;
+	ms = (ts->tv_nsec) / 1000000;
+
+	CAM_INFO(CAM_ISP,
+		"**** %llu:%llu:%llu.%llu ctx_idx: %u rdi_only: %s is_dual: %s acquired ****",
+		(tmp / 3600) % 24, (tmp / 60) % 60, tmp % 60, ms,
+		hwr_mgr_ctx->ctx_index,
+		(hwr_mgr_ctx->is_rdi_only_context ? "true" : "false"),
+		(hwr_mgr_ctx->is_dual ? "true" : "false"));
+
+	/* Iterate over CID resources */
+	list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
+		&hwr_mgr_ctx->res_list_ife_cid, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			hw_res = hw_mgr_res->hw_res[i];
+			if (hw_res && hw_res->hw_intf) {
+				CAM_INFO(CAM_ISP,
+					"CID split_id: %d res_id: %u hw_idx: %u state: %s",
+					i, hw_res->res_id,
+					hw_res->hw_intf->hw_idx,
+					cam_ife_hw_mgr_get_res_state
+					(hw_res->res_state));
+			}
+		}
+	}
+
+	/* Iterate over CSID resources */
+	list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
+		&hwr_mgr_ctx->res_list_ife_csid, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			hw_res = hw_mgr_res->hw_res[i];
+			if (hw_res && hw_res->hw_intf)
+				CAM_INFO(CAM_ISP,
+					"CSID split_id: %d res_id: %s hw_idx: %u state: %s",
+					i,
+					cam_ife_hw_mgr_get_csid_res_id(
+					hw_res->res_id),
+					hw_res->hw_intf->hw_idx,
+					cam_ife_hw_mgr_get_res_state
+					(hw_res->res_state));
+		}
+	}
+
+	/* Iterate over IFE IN resources */
+	list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
+		&hwr_mgr_ctx->res_list_ife_src, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			hw_res = hw_mgr_res->hw_res[i];
+			if (hw_res && hw_res->hw_intf)
+				CAM_INFO(CAM_ISP,
+					"IFE src split_id: %d res_id: %s hw_idx: %u state: %s",
+					i,
+					cam_ife_hw_mgr_get_src_res_id(
+					hw_res->res_id),
+					hw_res->hw_intf->hw_idx,
+					cam_ife_hw_mgr_get_res_state
+					(hw_res->res_state));
+		}
+	}
+
+	/* Iterate over IFE RD resources */
+	list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp,
+		&hwr_mgr_ctx->res_list_ife_in_rd, list) {
+		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
+			hw_res = hw_mgr_res->hw_res[i];
+			if (hw_res && hw_res->hw_intf)
+				CAM_INFO(CAM_ISP,
+					"IFE src_rd split_id: %d res_id: %s hw_idx: %u state: %s",
+					i,
+					cam_ife_hw_mgr_get_src_res_id(
+					hw_res->res_id),
+					hw_res->hw_intf->hw_idx,
+					cam_ife_hw_mgr_get_res_state
+					(hw_res->res_state));
+		}
+	}
+
+	/* Iterate over IFE OUT resources */
+	for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) {
+		for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) {
+			hw_mgr_res = &hwr_mgr_ctx->res_list_ife_out[i];
+			hw_res = hw_mgr_res->hw_res[j];
+			if (hw_res && hw_res->hw_intf)
+				CAM_INFO(CAM_ISP,
+					"IFE out split_id: %d res_id: 0x%x hw_idx: %u state: %s",
+					i, hw_res->res_id,
+					hw_res->hw_intf->hw_idx,
+					cam_ife_hw_mgr_get_res_state
+					(hw_res->res_state));
+		}
+	}
+}
+
 static int cam_ife_mgr_csid_stop_hw(
 	struct cam_ife_hw_mgr_ctx *ctx, struct list_head  *stop_list,
 		uint32_t  base_idx, uint32_t stop_cmd)
@@ -2400,8 +2600,11 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 
 		if (rc) {
 			CAM_ERR(CAM_ISP, "can not acquire resource");
+			cam_ife_hw_mgr_dump_src_acq_info(ife_ctx,
+				total_pix_port, total_rdi_port);
 			goto free_mem;
 		}
+
 		kfree(in_port->data);
 		kfree(in_port);
 		in_port = NULL;
@@ -2426,9 +2629,13 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 	acquire_args->valid_acquired_hw =
 		acquire_hw_info->num_inputs;
 
-	cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx);
+	getnstimeofday64(&ife_ctx->ts);
+	CAM_INFO(CAM_ISP,
+		"Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u",
+		total_pix_port, total_rdi_port,
+		ife_ctx->is_dual, ife_ctx->ctx_index);
 
-	CAM_DBG(CAM_ISP, "Exit...(success)");
+	cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx);
 
 	return 0;
 free_mem:
@@ -2661,9 +2868,12 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args)
 	acquire_args->ctxt_to_hw_map = ife_ctx;
 	ife_ctx->ctx_in_use = 1;
 
-	cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx);
+	CAM_INFO(CAM_ISP,
+		"Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u",
+		total_pix_port, total_rdi_port,
+		ife_ctx->is_dual, ife_ctx->ctx_index);
 
-	CAM_DBG(CAM_ISP, "Exit...(success)");
+	cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx);
 
 	return 0;
 free_res:
@@ -3722,8 +3932,11 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv,
 		ctx->eof_cnt[i] = 0;
 		ctx->epoch_cnt[i] = 0;
 	}
-	CAM_DBG(CAM_ISP, "Exit...ctx id:%d",
+
+	CAM_INFO(CAM_ISP, "Release HW success ctx id: %u",
 		ctx->ctx_index);
+
+	memset(&ctx->ts, 0, sizeof(struct timespec64));
 	cam_ife_hw_mgr_put_ctx(&hw_mgr->free_ctx_list, &ctx);
 	return rc;
 }
@@ -5494,6 +5707,9 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 			return rc;
 		}
 
+		break;
+	case CAM_HW_MGR_CMD_DUMP_ACQ_INFO:
+		cam_ife_hw_mgr_dump_acq_data(ctx);
 		break;
 	default:
 		CAM_ERR(CAM_ISP, "Invalid cmd");

+ 3 - 0
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h

@@ -7,6 +7,7 @@
 #define _CAM_IFE_HW_MGR_H_
 
 #include <linux/completion.h>
+#include <linux/time.h>
 #include "cam_isp_hw_mgr.h"
 #include "cam_vfe_hw_intf.h"
 #include "cam_ife_csid_hw_intf.h"
@@ -132,6 +133,7 @@ struct cam_ife_hw_mgr_debug {
  * @init_done               indicate whether init hw is done
  * @is_fe_enable            indicate whether fetch engine\read path is enabled
  * @is_dual                 indicate whether context is in dual VFE mode
+ * @ts                      captured timestamp when the ctx is acquired
  */
 struct cam_ife_hw_mgr_ctx {
 	struct list_head                list;
@@ -175,6 +177,7 @@ struct cam_ife_hw_mgr_ctx {
 	bool                            init_done;
 	bool                            is_fe_enable;
 	bool                            is_dual;
+	struct timespec64               ts;
 };
 
 /**