Browse Source

msm: camera: cpas: Dump cpas vote info when CRM dump request

Dump cpas vote info when CRM dump request, just like
cam_req_mgr_dump_state_monitor_info.

CRs-Fixed: 3441303
Change-Id: Ic5c2e671a27593ef1c25fa650c2148dd88c9968f
Signed-off-by: mingpan <[email protected]>
mingpan 2 years ago
parent
commit
400dfd20c5

+ 232 - 0
drivers/cam_cpas/cam_cpas_hw.c

@@ -17,6 +17,8 @@
 #include "cam_req_mgr_dev.h"
 #include "cam_smmu_api.h"
 #include "cam_compat.h"
+#include "cam_mem_mgr_api.h"
+#include "cam_req_mgr_interface.h"
 
 #define CAM_CPAS_LOG_BUF_LEN      512
 #define CAM_CPAS_APPLY_TYPE_START  1
@@ -3099,6 +3101,7 @@ static void cam_cpas_update_monitor_array(struct cam_hw_info *cpas_hw,
 	CAM_CPAS_INC_MONITOR_HEAD(&cpas_core->monitor_head, &iterator);
 
 	entry = &cpas_core->monitor_entries[iterator];
+	entry->cpas_hw = cpas_hw;
 
 	CAM_GET_TIMESTAMP(entry->timestamp);
 	strlcpy(entry->identifier_string, identifier_string,
@@ -3390,6 +3393,222 @@ static void cam_cpas_dump_monitor_array(
 	}
 }
 
+static void *cam_cpas_user_dump_state_monitor_array_info(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	uint64_t *addr;
+	struct cam_common_hw_dump_header *hdr;
+	struct cam_cpas_monitor *monitor = (struct cam_cpas_monitor *)dump_struct;
+	struct cam_cpas_axi_port_debug_info *axi_info = NULL;
+	struct cam_cpas_cesta_vcd_reg_debug_info *vcd_reg_debug_info = NULL;
+	struct cam_hw_info *cpas_hw = (struct cam_hw_info *) monitor->cpas_hw;
+	struct cam_cpas_private_soc *soc_private =
+		(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
+	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+	struct cam_cpas_tree_node *niu_node;
+	uint8_t *dst;
+	uint32_t num_vcds = CAM_CPAS_MAX_CESTA_VCD_NUM, camnoc_idx, i;
+
+	addr = (uint64_t *)addr_ptr;
+
+	*addr++ = monitor->timestamp.tv_sec;
+	*addr++ = monitor->timestamp.tv_nsec / NSEC_PER_USEC;
+
+	*addr++ = monitor->identifier_value;
+	*addr++ = monitor->applied_camnoc_clk.sw_client,
+	*addr++ = monitor->applied_camnoc_clk.hw_client[0].high,
+	*addr++ = monitor->applied_camnoc_clk.hw_client[0].low,
+	*addr++ = monitor->applied_camnoc_clk.hw_client[1].high,
+	*addr++ = monitor->applied_camnoc_clk.hw_client[1].low,
+	*addr++ = monitor->applied_camnoc_clk.hw_client[2].high,
+	*addr++ = monitor->applied_camnoc_clk.hw_client[2].low,
+	*addr++ = monitor->applied_ahb_level;
+	*addr++ = cpas_core->num_valid_camnoc;
+	*addr++ = soc_private->smart_qos_info->num_rt_wr_nius;
+	*addr++ = num_vcds;
+	*addr++ = cpas_core->num_axi_ports;
+
+	*addr++ = monitor->fe_ddr;
+	*addr++ = monitor->be_ddr;
+	*addr++ = monitor->fe_mnoc;
+	*addr++ = monitor->be_mnoc;
+	*addr++ = monitor->be_shub;
+
+	for (i = 0; i < cpas_core->num_axi_ports; i++) {
+		axi_info = &monitor->axi_info[i];
+		dst = (uint8_t *)addr;
+		hdr = (struct cam_common_hw_dump_header *)dst;
+
+		if (axi_info->applied_bw.vote_type == CAM_CPAS_VOTE_TYPE_DRV) {
+			scnprintf(hdr->tag, CAM_COMMON_HW_DUMP_TAG_MAX_LEN, "%s.%s.%s:",
+				axi_info->axi_port_name, "DRV",
+				CAM_BOOL_TO_YESNO(axi_info->is_drv_started));
+			addr = (uint64_t *)(dst + sizeof(struct cam_common_hw_dump_header));
+			*addr++ = axi_info->applied_bw.drv_vote.high.ab;
+			*addr++ = axi_info->applied_bw.drv_vote.high.ib;
+			*addr++ = axi_info->applied_bw.drv_vote.low.ab;
+			*addr++ = axi_info->applied_bw.drv_vote.low.ib;
+		} else {
+			scnprintf(hdr->tag, CAM_COMMON_HW_DUMP_TAG_MAX_LEN, "%s.%s.%s:",
+				axi_info->axi_port_name, "HLOS",
+				CAM_BOOL_TO_YESNO(axi_info->is_drv_started));
+			addr = (uint64_t *)(dst + sizeof(struct cam_common_hw_dump_header));
+			*addr++ = axi_info->applied_bw.hlos_vote.ab;
+			*addr++ = axi_info->applied_bw.hlos_vote.ib;
+		}
+	}
+
+	for (camnoc_idx = 0; camnoc_idx < cpas_core->num_valid_camnoc; camnoc_idx++) {
+		*addr++ = monitor->num_camnoc_lvl_regs[camnoc_idx];
+		for (i = 0; i < monitor->num_camnoc_lvl_regs[camnoc_idx]; i++) {
+			dst = (uint8_t *)addr;
+			hdr = (struct cam_common_hw_dump_header *)dst;
+			scnprintf(hdr->tag, CAM_COMMON_HW_DUMP_TAG_MAX_LEN, "%s:[%d %d].",
+				monitor->camnoc_port_name[camnoc_idx][i],
+				monitor->camnoc_fill_level[camnoc_idx][i] & 0x7FF,
+				(monitor->camnoc_fill_level[camnoc_idx][i] & 0x7F0000) >> 16);
+			addr = (uint64_t *)(dst + sizeof(struct cam_common_hw_dump_header));
+		}
+	}
+
+	for (i = 0; i < soc_private->smart_qos_info->num_rt_wr_nius; i++) {
+		niu_node = soc_private->smart_qos_info->rt_wr_niu_node[i];
+		dst = (uint8_t *)addr;
+		hdr = (struct cam_common_hw_dump_header *)dst;
+		scnprintf(hdr->tag, CAM_COMMON_HW_DUMP_TAG_MAX_LEN, "%s:", niu_node->node_name);
+		addr = (uint64_t *)(dst + sizeof(struct cam_common_hw_dump_header));
+		*addr++ = monitor->rt_wr_niu_pri_lut_high[i];
+		*addr++ = monitor->rt_wr_niu_pri_lut_low[i];
+	}
+
+	vcd_reg_debug_info = &monitor->vcd_reg_debug_info;
+
+	for (i = 0; i < num_vcds; i++) {
+		*addr++ = vcd_reg_debug_info->vcd_curr_lvl_debug_info[i].index;
+		*addr++ = vcd_reg_debug_info->vcd_curr_lvl_debug_info[i].reg_value;
+	}
+
+	return addr;
+}
+
+/**
+ * cam_cpas_dump_state_monitor_array_info()
+ *
+ * @brief     : dump the state monitor array info, dump from monitor_head
+ *              to save state information in time order.
+ * @cpas_hw   : hardware information
+ * @dump_info : dump payload
+ */
+static int cam_cpas_dump_state_monitor_array_info(
+	struct cam_hw_info *cpas_hw,
+	struct cam_req_mgr_dump_info *dump_info)
+{
+	int                             rc = 0;
+	int                             i, j;
+	struct cam_common_hw_dump_args  dump_args;
+	size_t                          buf_len;
+	size_t                          remain_len;
+	uint32_t                        min_len = 0, camnoc_idx;
+	uintptr_t                       cpu_addr;
+	struct cam_cpas *cpas_core = (struct cam_cpas *) cpas_hw->core_info;
+	int64_t                         state_head = 0;
+	uint32_t                        index, num_entries, oldest_entry;
+	struct cam_cpas_private_soc *soc_private =
+		(struct cam_cpas_private_soc *) cpas_hw->soc_info.soc_private;
+	struct cam_cpas_monitor         *entry;
+	uint32_t monitor_idx, camnoc_lvl_regs_num;
+
+	state_head = atomic64_read(&cpas_core->monitor_head);
+	if (state_head == -1) {
+		CAM_WARN(CAM_CPAS, "No valid entries in cpas monitor array");
+		return 0;
+	} else if (state_head < CAM_CPAS_MONITOR_MAX_ENTRIES) {
+		num_entries = state_head;
+		oldest_entry = 0;
+	} else {
+		num_entries = CAM_CPAS_MONITOR_MAX_ENTRIES;
+		div_u64_rem(state_head + 1,
+			CAM_CPAS_MONITOR_MAX_ENTRIES, &oldest_entry);
+	}
+
+	monitor_idx = index = oldest_entry;
+
+	rc = cam_mem_get_cpu_buf(dump_info->buf_handle, &cpu_addr, &buf_len);
+	if (rc) {
+		CAM_ERR(CAM_CPAS, "Invalid handle %u rc %d",
+			dump_info->buf_handle, rc);
+		return rc;
+	}
+
+	if (buf_len <= dump_info->offset) {
+		CAM_WARN(CAM_CPAS, "Dump buffer overshoot len %zu offset %zu",
+			buf_len, dump_info->offset);
+		return -ENOSPC;
+	}
+
+	remain_len = buf_len - dump_info->offset;
+	for (i = 0; i < num_entries; i++) {
+		min_len += sizeof(struct cam_common_hw_dump_header) +
+			CAM_CPAS_DUMP_NUM_WORDS_COMM * sizeof(uint64_t);
+		entry = &cpas_core->monitor_entries[monitor_idx];
+		for (j = 0; j < cpas_core->num_axi_ports; j++) {
+			if (entry->axi_info[j].applied_bw.vote_type ==
+				CAM_CPAS_VOTE_TYPE_DRV) {
+				min_len += sizeof(struct cam_common_hw_dump_header) +
+					CAM_CPAS_DUMP_NUM_WORDS_VOTE_TYEP_DRV * sizeof(uint64_t);
+			} else {
+				min_len += sizeof(struct cam_common_hw_dump_header) +
+					CAM_CPAS_DUMP_NUM_WORDS_VOTE_TYEP_HLOS * sizeof(uint64_t);
+			}
+		}
+
+		for (camnoc_idx = 0; camnoc_idx < cpas_core->num_valid_camnoc; camnoc_idx++) {
+			min_len += sizeof(uint64_t);
+			camnoc_lvl_regs_num = entry->num_camnoc_lvl_regs[camnoc_idx];
+			for (j = 0; j < entry->num_camnoc_lvl_regs[camnoc_idx]; j++)
+				min_len += sizeof(struct cam_common_hw_dump_header);
+		}
+
+		for (j = 0; j < soc_private->smart_qos_info->num_rt_wr_nius; j++)
+			min_len += sizeof(struct cam_common_hw_dump_header) +
+				CAM_CPAS_DUMP_NUM_WORDS_RT_WR_NIUS * sizeof(uint64_t);
+
+		for (j = 0; j < CAM_CPAS_MAX_CESTA_VCD_NUM; j++)
+			min_len += CAM_CPAS_DUMP_NUM_WORDS_VCD_CURR_LVL * sizeof(uint64_t);
+
+		monitor_idx = (monitor_idx + 1) % CAM_CPAS_MONITOR_MAX_ENTRIES;
+	}
+
+	if (remain_len < min_len) {
+		CAM_WARN(CAM_CPAS, "Dump buffer exhaust remain %zu min %u",
+			remain_len, min_len);
+		return -ENOSPC;
+	}
+
+	dump_args.req_id = dump_info->req_id;
+	dump_args.cpu_addr = cpu_addr;
+	dump_args.buf_len = buf_len;
+	dump_args.offset = dump_info->offset;
+	dump_args.ctxt_to_hw_map = NULL;
+	for (i = 0; i < num_entries; i++) {
+		rc = cam_common_user_dump_helper(&dump_args,
+			cam_cpas_user_dump_state_monitor_array_info,
+			&cpas_core->monitor_entries[index],
+			sizeof(uint64_t), "CPAS_MONITOR.%d.%s:", index,
+			&cpas_core->monitor_entries[index].identifier_string);
+		if (rc) {
+			CAM_ERR(CAM_CPAS, "Dump state info failed, rc: %d", rc);
+			return rc;
+		}
+
+		index = (index + 1) % CAM_CPAS_MONITOR_MAX_ENTRIES;
+	}
+
+	dump_info->offset = dump_args.offset;
+
+	return rc;
+}
+
 static int cam_cpas_log_event(struct cam_hw_info *cpas_hw,
 	const char *identifier_string, int32_t identifier_value)
 {
@@ -4110,6 +4329,19 @@ static int cam_cpas_hw_process_cmd(void *hw_priv,
 		rc = cam_cpas_hw_enable_domain_id_clks(hw_priv, *enable);
 		break;
 	}
+	case CAM_CPAS_HW_CMD_DUMP_STATE_MONITOR_INFO: {
+		struct cam_req_mgr_dump_info *info;
+
+		if (sizeof(struct cam_req_mgr_dump_info) != arg_size) {
+			CAM_ERR(CAM_CPAS, "cmd_type %d, size mismatch %d",
+				cmd_type, arg_size);
+			break;
+		}
+
+		info = (struct cam_req_mgr_dump_info *)cmd_args;
+		rc = cam_cpas_dump_state_monitor_array_info(hw_priv, info);
+		break;
+	}
 
 	default:
 		CAM_ERR(CAM_CPAS, "CPAS HW command not valid =%d", cmd_type);

+ 7 - 0
drivers/cam_cpas/cam_cpas_hw.h

@@ -60,6 +60,12 @@
 	CAM_CPAS_MONITOR_MAX_ENTRIES, (ret))
 #define CAM_CPAS_MAX_CESTA_VCD_NUM 9
 
+#define CAM_CPAS_DUMP_NUM_WORDS_COMM              20
+#define CAM_CPAS_DUMP_NUM_WORDS_VOTE_TYEP_DRV     4
+#define CAM_CPAS_DUMP_NUM_WORDS_VOTE_TYEP_HLOS    2
+#define CAM_CPAS_DUMP_NUM_WORDS_RT_WR_NIUS        2
+#define CAM_CPAS_DUMP_NUM_WORDS_VCD_CURR_LVL      2
+
 /**
  * enum cam_camnoc_domain_type - Enum for different camnoc domains
  * @CAM_CAMNOC_HW_COMBINED: refer to legacy camnoc info that combines RT/NRT HW
@@ -344,6 +350,7 @@ struct cam_cpas_monitor {
 	uint32_t            rt_wr_niu_pri_lut_low[CAM_CPAS_MAX_RT_WR_NIU_NODES];
 	uint32_t            rt_wr_niu_pri_lut_high[CAM_CPAS_MAX_RT_WR_NIU_NODES];
 	struct cam_cpas_cesta_vcd_reg_debug_info vcd_reg_debug_info;
+	struct cam_hw_info  *cpas_hw;
 };
 
 /**

+ 1 - 0
drivers/cam_cpas/cam_cpas_hw_intf.h

@@ -72,6 +72,7 @@ enum cam_cpas_hw_cmd_process {
 	CAM_CPAS_HW_CMD_CSID_INPUT_CORE_INFO_UPDATE,
 	CAM_CPAS_HW_CMD_CSID_PROCESS_RESUME,
 	CAM_CPAS_HW_CMD_ENABLE_DISABLE_DOMAIN_ID_CLK,
+	CAM_CPAS_HW_CMD_DUMP_STATE_MONITOR_INFO,
 	CAM_CPAS_HW_CMD_INVALID,
 };
 

+ 21 - 0
drivers/cam_cpas/cam_cpas_intf.c

@@ -22,6 +22,7 @@
 #include "cam_cpas_soc.h"
 #include "camera_main.h"
 #include <linux/soc/qcom/llcc-qcom.h>
+#include "cam_req_mgr_interface.h"
 
 #define CAM_CPAS_DEV_NAME    "cam-cpas"
 #define CAM_CPAS_INTF_INITIALIZED() (g_cpas_intf && g_cpas_intf->probe_done)
@@ -1001,6 +1002,26 @@ int cam_cpas_enable_clks_for_domain_id(bool enable)
 }
 EXPORT_SYMBOL(cam_cpas_enable_clks_for_domain_id);
 
+int cam_cpas_dump_state_monitor_info(struct cam_req_mgr_dump_info *info)
+{
+	int rc = 0;
+
+	if (!CAM_CPAS_INTF_INITIALIZED()) {
+		CAM_ERR(CAM_CPAS, "cpas intf not initialized");
+		return -ENODEV;
+	}
+
+	if (g_cpas_intf->hw_intf->hw_ops.process_cmd) {
+		rc = g_cpas_intf->hw_intf->hw_ops.process_cmd(
+			g_cpas_intf->hw_intf->hw_priv,
+			CAM_CPAS_HW_CMD_DUMP_STATE_MONITOR_INFO, info,
+			sizeof(*info));
+	}
+
+	return rc;
+}
+EXPORT_SYMBOL(cam_cpas_dump_state_monitor_info);
+
 int cam_cpas_subdev_cmd(struct cam_cpas_intf *cpas_intf,
 	struct cam_control *cmd)
 {

+ 10 - 0
drivers/cam_cpas/include/cam_cpas_api.h

@@ -12,6 +12,7 @@
 
 #include <media/cam_cpas.h>
 #include "cam_soc_util.h"
+#include "cam_req_mgr_interface.h"
 
 #define CAM_HW_IDENTIFIER_LENGTH 128
 
@@ -1010,4 +1011,13 @@ int cam_cpas_enable_clks_for_domain_id(bool enable);
  */
 bool cam_cpas_is_notif_staling_supported(void);
 
+/**
+ * cam_cpas_dump_state_monitor_info()
+ *
+ * @brief: API to dump the state monitor info of cpas.
+ * @info:  Dump information.
+ * @return 0 on success
+ */
+int cam_cpas_dump_state_monitor_info(struct cam_req_mgr_dump_info *info);
+
 #endif /* _CAM_CPAS_API_H_ */

+ 6 - 0
drivers/cam_req_mgr/cam_req_mgr_core.c

@@ -19,6 +19,7 @@
 #include "cam_req_mgr_debug.h"
 #include "cam_common_util.h"
 #include "cam_mem_mgr.h"
+#include "cam_cpas_api.h"
 
 static struct cam_req_mgr_core_device *g_crm_core_dev;
 static struct cam_req_mgr_core_link g_links[MAXIMUM_LINKS_PER_SESSION];
@@ -5650,6 +5651,11 @@ int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req)
 			"Fail to dump state monitor req %llu rc %d",
 			info.req_id, rc);
 
+	info.buf_handle = dump_req->buf_handle;
+	rc = cam_cpas_dump_state_monitor_info(&info);
+	if (rc)
+		CAM_ERR(CAM_CRM, "Fail to dump cpas vote info, rc %d", rc);
+
 	for (i = 0; i < link->num_devs; i++) {
 		device = &link->l_dev[i];
 		info.link_hdl = dump_req->link_hdl;