Procházet zdrojové kódy

msm: camera: isp: LDAR Dump ISP Extension

Extension of Lets do a reset (LDAR) to include more information
in dump with more dump output enhancements.

CRs-Fixed: 3068971
Change-Id: I6b61bcf546e32c096e45c511faf64514ff391e62
Signed-off-by: Joshua Florez <[email protected]>
Joshua Florez před 3 roky
rodič
revize
d644749f16

+ 357 - 114
drivers/cam_isp/cam_isp_context.c

@@ -22,6 +22,7 @@
 #include "cam_common_util.h"
 #include "cam_req_mgr_debug.h"
 #include "cam_cpas_api.h"
+#include "cam_ife_hw_mgr.h"
 
 static const char isp_dev_name[] = "cam-isp";
 
@@ -39,6 +40,15 @@ static int cam_isp_context_hw_recovery(void *priv, void *data);
 static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
 	struct cam_start_stop_dev_cmd *cmd);
 
+static void __cam_isp_ctx_dump_state_monitor_array(
+	struct cam_isp_context *ctx_isp);
+
+static const char *__cam_isp_hw_evt_val_to_type(
+	uint32_t evt_id);
+
+static const char *__cam_isp_ctx_substate_val_to_type(
+	enum cam_isp_ctx_activated_substate type);
+
 static const char *__cam_isp_evt_val_to_type(
 	uint32_t evt_id)
 {
@@ -101,29 +111,42 @@ static void __cam_isp_ctx_update_event_record(
 	ctx_isp->event_record[event][iterator].timestamp  = cur_time;
 }
 
+static void *cam_isp_ctx_user_dump_events(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	uint64_t                             *addr;
+	struct cam_isp_context_event_record  *record;
+	struct timespec64                     ts;
+
+	record = (struct cam_isp_context_event_record *)dump_struct;
+
+	addr = (uint64_t *)addr_ptr;
+	ts = ktime_to_timespec64(record->timestamp);
+	*addr++ = record->req_id;
+	*addr++ = ts.tv_sec;
+	*addr++ = ts.tv_nsec / NSEC_PER_USEC;
+
+	return addr;
+}
+
 static int __cam_isp_ctx_dump_event_record(
 	struct cam_isp_context *ctx_isp,
-	uintptr_t               cpu_addr,
-	size_t                  buf_len,
-	size_t                 *offset)
+	struct cam_common_hw_dump_args *dump_args)
 {
-	int                                  i, j;
+	int                                  i, j, rc = 0;
 	int                                  index;
 	size_t                               remain_len;
-	uint8_t                             *dst;
 	uint32_t                             oldest_entry, num_entries;
 	uint32_t                             min_len;
-	uint64_t                            *addr, *start;
 	uint64_t                             state_head;
-	struct timespec64                    ts;
-	struct cam_isp_context_dump_header  *hdr;
 	struct cam_isp_context_event_record *record;
 
-	if (!cpu_addr || !buf_len || !offset || !ctx_isp) {
-		CAM_ERR(CAM_ISP, "Invalid args %pK %zu %pK %pK",
-			cpu_addr, buf_len, offset, ctx_isp);
+	if (!dump_args || !ctx_isp) {
+		CAM_ERR(CAM_ISP, "Invalid args %pK %pK",
+			dump_args, ctx_isp);
 		return -EINVAL;
 	}
+
 	for (i = 0; i < CAM_ISP_CTX_EVENT_MAX; i++) {
 		state_head = atomic64_read(&ctx_isp->event_record_head[i]);
 
@@ -140,17 +163,16 @@ static int __cam_isp_ctx_dump_event_record(
 		}
 		index = oldest_entry;
 
-		if (buf_len <= *offset) {
-			CAM_WARN(CAM_ISP,
-				"Dump buffer overshoot len %zu offset %zu",
-				buf_len, *offset);
+		if (dump_args->buf_len <= dump_args->offset) {
+			CAM_WARN(CAM_ISP, "Dump buffer overshoot len %zu offset %zu",
+				dump_args->buf_len, dump_args->offset);
 			return -ENOSPC;
 		}
 
 		min_len = sizeof(struct cam_isp_context_dump_header) +
 			((num_entries * CAM_ISP_CTX_DUMP_EVENT_NUM_WORDS) *
-			sizeof(uint64_t));
-		remain_len = buf_len - *offset;
+				sizeof(uint64_t));
+		remain_len = dump_args->buf_len - dump_args->offset;
 
 		if (remain_len < min_len) {
 			CAM_WARN(CAM_ISP,
@@ -158,29 +180,24 @@ static int __cam_isp_ctx_dump_event_record(
 				remain_len, min_len);
 			return -ENOSPC;
 		}
-		dst = (uint8_t *)cpu_addr + *offset;
-		hdr = (struct cam_isp_context_dump_header *)dst;
-		scnprintf(hdr->tag,
-			CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN, "ISP_EVT_%s:",
-			__cam_isp_evt_val_to_type(i));
-		hdr->word_size = sizeof(uint64_t);
-		addr = (uint64_t *)(dst +
-			sizeof(struct cam_isp_context_dump_header));
-		start = addr;
-		for (j = 0; j <  num_entries; j++) {
-			record  = &ctx_isp->event_record[i][index];
-			ts      = ktime_to_timespec64(record->timestamp);
-			*addr++ = record->req_id;
-			*addr++ = ts.tv_sec;
-			*addr++ = ts.tv_nsec/NSEC_PER_USEC;
+
+		for (j = 0; j < num_entries; j++) {
+			record = &ctx_isp->event_record[i][index];
+
+			rc = cam_common_user_dump_helper(dump_args, cam_isp_ctx_user_dump_events,
+				record, sizeof(uint64_t), "ISP_EVT_%s:",
+				__cam_isp_evt_val_to_type(i));
+			if (rc) {
+				CAM_ERR(CAM_ISP,
+					"CAM_ISP_CONTEXT DUMP_EVENT_RECORD: Dump failed, rc: %d",
+					rc);
+				return rc;
+			}
 			index = (index + 1) %
 				CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES;
 		}
-		hdr->size = hdr->word_size * (addr - start);
-		*offset += hdr->size +
-			sizeof(struct cam_isp_context_dump_header);
 	}
-	return 0;
+	return rc;
 }
 
 static void __cam_isp_ctx_req_mini_dump(struct cam_ctx_request *req,
@@ -483,6 +500,78 @@ static void __cam_isp_ctx_dump_state_monitor_array(
 	}
 }
 
+static void *cam_isp_ctx_user_dump_state_monitor_array_info(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	struct cam_isp_context_state_monitor  *evt = NULL;
+	uint64_t                *addr;
+
+	evt = (struct cam_isp_context_state_monitor *)dump_struct;
+
+	addr = (uint64_t *)addr_ptr;
+
+	*addr++ = evt->evt_time_stamp;
+	*addr++ = evt->frame_id;
+	*addr++ = evt->req_id;
+	return addr;
+}
+
+static int __cam_isp_ctx_user_dump_state_monitor_array(
+	struct cam_isp_context *ctx_isp,
+	struct cam_common_hw_dump_args *dump_args)
+{
+	int                                          i, rc = 0;
+	int                                          index;
+	uint32_t                                     oldest_entry;
+	uint32_t                                     num_entries;
+	uint64_t                                     state_head;
+
+	if (!dump_args || !ctx_isp) {
+		CAM_ERR(CAM_ISP, "Invalid args %pK %pK",
+			dump_args, ctx_isp);
+		return -EINVAL;
+	}
+
+	state_head = 0;
+	state_head = atomic64_read(&ctx_isp->state_monitor_head);
+
+	if (state_head == -1) {
+		return 0;
+	} else if (state_head < CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES) {
+		num_entries = state_head;
+		oldest_entry = 0;
+	} else {
+		num_entries = CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES;
+		div_u64_rem(state_head + 1,
+			CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES, &oldest_entry);
+	}
+	CAM_ERR(CAM_ISP,
+		"Dumping state information for preceding requests");
+
+	index = oldest_entry;
+	__cam_isp_ctx_dump_state_monitor_array(ctx_isp);
+	for (i = 0; i < num_entries; i++) {
+
+		rc = cam_common_user_dump_helper(dump_args,
+			cam_isp_ctx_user_dump_state_monitor_array_info,
+			&ctx_isp->cam_isp_ctx_state_monitor[index],
+			sizeof(uint64_t), "ISP_STATE_MONITOR.%s.%s:",
+			__cam_isp_ctx_substate_val_to_type(
+				ctx_isp->cam_isp_ctx_state_monitor[index].curr_state),
+			__cam_isp_hw_evt_val_to_type(
+				ctx_isp->cam_isp_ctx_state_monitor[index].trigger));
+
+		if (rc) {
+			CAM_ERR(CAM_ISP, "CAM ISP CONTEXT: Event record dump failed, rc: %d", rc);
+			return rc;
+		}
+
+		index = (index + 1) % CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES;
+
+	}
+	return rc;
+}
+
 static int cam_isp_context_info_dump(void *context,
 	enum cam_context_dump_id id)
 {
@@ -4099,41 +4188,70 @@ static int __cam_isp_ctx_apply_default_req_settings(
 	return rc;
 }
 
+static void *cam_isp_ctx_user_dump_req_list(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	struct list_head        *head = NULL;
+	uint64_t                *addr;
+	struct cam_ctx_request  *req, *req_temp;
+
+	head = (struct list_head *)dump_struct;
+
+	addr = (uint64_t *)addr_ptr;
+
+	if (!list_empty(head)) {
+		list_for_each_entry_safe(req, req_temp, head, list) {
+			*addr++ = req->request_id;
+		}
+	}
+
+	return addr;
+}
+
+static void *cam_isp_ctx_user_dump_active_requests(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	uint64_t                *addr;
+	struct cam_ctx_request  *req;
+
+	req = (struct cam_ctx_request *)dump_struct;
+
+	addr = (uint64_t *)addr_ptr;
+	*addr++ = req->request_id;
+	return addr;
+}
+
 static int __cam_isp_ctx_dump_req_info(
 	struct cam_context     *ctx,
 	struct cam_ctx_request *req,
-	uintptr_t               cpu_addr,
-	size_t                  buf_len,
-	size_t                 *offset)
+	struct cam_common_hw_dump_args *dump_args)
 {
-	int                                 i, rc;
-	uint8_t                            *dst;
-	int32_t                            *addr, *start;
+	int                                 i, rc = 0;
 	uint32_t                            min_len;
 	size_t                              remain_len;
 	struct cam_isp_ctx_req             *req_isp;
 	struct cam_isp_context             *ctx_isp;
-	struct cam_isp_context_dump_header *hdr;
+	struct cam_ctx_request             *req_temp;
 
-	if (!req || !ctx || !offset || !cpu_addr || !buf_len) {
-		CAM_ERR(CAM_ISP, "Invalid parameters %pK %pK %pK %zu",
-			req, ctx, offset, buf_len);
+	if (!req || !ctx || !dump_args) {
+		CAM_ERR(CAM_ISP, "Invalid parameters %pK %pK %pK",
+			req, ctx, dump_args);
 		return -EINVAL;
 	}
 	req_isp = (struct cam_isp_ctx_req *)req->req_priv;
 	ctx_isp = (struct cam_isp_context *)ctx->ctx_priv;
 
-	if (buf_len <= *offset) {
+	if (dump_args->buf_len <= dump_args->offset) {
 		CAM_WARN(CAM_ISP, "Dump buffer overshoot len %zu offset %zu",
-			buf_len, *offset);
+			dump_args->buf_len, dump_args->offset);
 		return -ENOSPC;
 	}
 
-	remain_len = buf_len - *offset;
+	remain_len = dump_args->buf_len - dump_args->offset;
 	min_len = sizeof(struct cam_isp_context_dump_header) +
 		(CAM_ISP_CTX_DUMP_REQUEST_NUM_WORDS *
-		 req_isp->num_fence_map_out *
-		sizeof(int32_t));
+			req_isp->num_fence_map_out *
+			sizeof(uint64_t));
 
 	if (remain_len < min_len) {
 		CAM_WARN(CAM_ISP, "Dump buffer exhaust remain %zu min %u",
@@ -4141,24 +4259,133 @@ static int __cam_isp_ctx_dump_req_info(
 		return -ENOSPC;
 	}
 
-	dst = (uint8_t *)cpu_addr + *offset;
-	hdr = (struct cam_isp_context_dump_header *)dst;
-	hdr->word_size = sizeof(int32_t);
-	scnprintf(hdr->tag, CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN,
-		"ISP_OUT_FENCE:");
-	addr = (int32_t *)(dst + sizeof(struct cam_isp_context_dump_header));
-	start = addr;
-	for (i = 0; i < req_isp->num_fence_map_out; i++) {
-		*addr++ = req_isp->fence_map_out[i].resource_handle;
-		*addr++ = req_isp->fence_map_out[i].sync_id;
+	/* Dump pending request list */
+	rc = cam_common_user_dump_helper(dump_args, cam_isp_ctx_user_dump_req_list,
+		&ctx->pending_req_list, sizeof(uint64_t), "ISP_OUT_FENCE_PENDING_REQUESTS:");
+	if (rc) {
+		CAM_ERR(CAM_ISP, "CAM_ISP_CONTEXT: Pending request dump failed, rc: %d",
+			rc);
+		return rc;
+	}
+
+	/* Dump applied request list */
+	rc = cam_common_user_dump_helper(dump_args, cam_isp_ctx_user_dump_req_list,
+		&ctx->wait_req_list, sizeof(uint64_t), "ISP_OUT_FENCE_APPLIED_REQUESTS:");
+	if (rc) {
+		CAM_ERR(CAM_ISP, "CAM_ISP_CONTEXT: Applied request dump failed, rc: %d",
+			rc);
+		return rc;
+	}
+
+	/* Dump active request list */
+	rc = cam_common_user_dump_helper(dump_args, cam_isp_ctx_user_dump_req_list,
+		&ctx->active_req_list, sizeof(uint64_t), "ISP_OUT_FENCE_ACTIVE_REQUESTS:");
+	if (rc) {
+		CAM_ERR(CAM_ISP, "CAM_ISP_CONTEXT: Active request dump failed, rc: %d",
+			rc);
+		return rc;
+	}
+
+	/* Dump active request fences */
+	if (!list_empty(&ctx->active_req_list)) {
+		list_for_each_entry_safe(req, req_temp, &ctx->active_req_list, list) {
+			req_isp = (struct cam_isp_ctx_req *)req->req_priv;
+			for (i = 0; i < req_isp->num_fence_map_out; i++) {
+				rc = cam_common_user_dump_helper(dump_args,
+					cam_isp_ctx_user_dump_active_requests,
+					req, sizeof(uint64_t),
+					"ISP_OUT_FENCE_REQUEST_ACTIVE.%s.%u.%d:",
+					__cam_isp_ife_sfe_resource_handle_id_to_type(
+						req_isp->fence_map_out[i].resource_handle),
+					&(req_isp->fence_map_out[i].image_buf_addr),
+					req_isp->fence_map_out[i].sync_id);
+
+				if (rc) {
+					CAM_ERR(CAM_ISP,
+						"CAM_ISP_CONTEXT DUMP_REQ_INFO: Dump failed, rc: %d",
+						rc);
+					return rc;
+				}
+			}
+		}
 	}
-	hdr->size = hdr->word_size * (addr - start);
-	*offset += hdr->size + sizeof(struct cam_isp_context_dump_header);
-	rc = cam_isp_ctx_dump_req(req_isp, cpu_addr, buf_len,
-		offset, true);
+
 	return rc;
 }
 
+static void *cam_isp_ctx_user_dump_timer(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	struct cam_ctx_request  *req = NULL;
+	struct cam_isp_ctx_req  *req_isp = NULL;
+	uint64_t                *addr;
+	ktime_t                  cur_time;
+
+	req = (struct cam_ctx_request *)dump_struct;
+	req_isp = (struct cam_isp_ctx_req *)req->req_priv;
+	cur_time = ktime_get();
+
+	addr = (uint64_t *)addr_ptr;
+
+	*addr++ = req->request_id;
+	*addr++ = ktime_to_timespec64(
+		req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY]).tv_sec;
+	*addr++ = ktime_to_timespec64(
+		req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY]).tv_nsec / NSEC_PER_USEC;
+	*addr++ = ktime_to_timespec64(cur_time).tv_sec;
+	*addr++ = ktime_to_timespec64(cur_time).tv_nsec / NSEC_PER_USEC;
+	return addr;
+}
+
+static void *cam_isp_ctx_user_dump_stream_info(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	struct cam_context           *ctx = NULL;
+	struct cam_ife_hw_mgr_ctx    *hw_mgr_ctx = NULL;
+	struct cam_isp_hw_mgr_res    *hw_mgr_res = NULL;
+	struct cam_isp_resource_node *hw_res = NULL;
+	int hw_idx[CAM_ISP_HW_SPLIT_MAX] = { -1, -1 };
+	int sfe_hw_idx[CAM_ISP_HW_SPLIT_MAX] = { -1, -1 };
+	int32_t                      *addr;
+	int                           i;
+
+	ctx = (struct cam_context *)dump_struct;
+	hw_mgr_ctx = (struct cam_ife_hw_mgr_ctx *)ctx->ctxt_to_hw_map;
+
+	if (!list_empty(&hw_mgr_ctx->res_list_ife_src)) {
+		hw_mgr_res = list_first_entry(&hw_mgr_ctx->res_list_ife_src,
+			struct cam_isp_hw_mgr_res, 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)
+				hw_idx[i] = hw_res->hw_intf->hw_idx;
+		}
+	}
+
+	if (!list_empty(&hw_mgr_ctx->res_list_sfe_src)) {
+		hw_mgr_res = list_first_entry(&hw_mgr_ctx->res_list_sfe_src,
+			struct cam_isp_hw_mgr_res, 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)
+				sfe_hw_idx[i] = hw_res->hw_intf->hw_idx;
+		}
+	}
+
+	addr = (int32_t *)addr_ptr;
+
+	*addr++ = ctx->ctx_id;
+	*addr++ = ctx->dev_hdl;
+	*addr++ = ctx->link_hdl;
+	*addr++ = hw_idx[CAM_ISP_HW_SPLIT_LEFT];
+	*addr++ = sfe_hw_idx[CAM_ISP_HW_SPLIT_LEFT];
+	*addr++ = hw_mgr_ctx->flags.is_sfe_shdr;
+
+	return addr;
+}
+
 static int __cam_isp_ctx_dump_in_top_state(
 	struct cam_context           *ctx,
 	struct cam_req_mgr_dump_info *dump_info)
@@ -4167,19 +4394,16 @@ static int __cam_isp_ctx_dump_in_top_state(
 	bool                                dump_only_event_record = false;
 	size_t                              buf_len;
 	size_t                              remain_len;
-	uint8_t                            *dst;
 	ktime_t                             cur_time;
 	uint32_t                            min_len;
 	uint64_t                            diff;
-	uint64_t                           *addr, *start;
 	uintptr_t                           cpu_addr;
-	struct timespec64                   ts;
 	struct cam_isp_context             *ctx_isp;
 	struct cam_ctx_request             *req = NULL;
 	struct cam_isp_ctx_req             *req_isp;
 	struct cam_ctx_request             *req_temp;
-	struct cam_hw_dump_args             dump_args;
-	struct cam_isp_context_dump_header *hdr;
+	struct cam_hw_dump_args             ife_dump_args;
+	struct cam_common_hw_dump_args      dump_args;
 
 	spin_lock_bh(&ctx->lock);
 	list_for_each_entry_safe(req, req_temp,
@@ -4198,16 +4422,14 @@ static int __cam_isp_ctx_dump_in_top_state(
 			goto hw_dump;
 		}
 	}
-	spin_unlock_bh(&ctx->lock);
-	return rc;
+	goto end;
 hw_dump:
-	rc  = cam_mem_get_cpu_buf(dump_info->buf_handle,
+	rc = cam_mem_get_cpu_buf(dump_info->buf_handle,
 		&cpu_addr, &buf_len);
 	if (rc) {
 		CAM_ERR(CAM_ISP, "Invalid handle %u rc %d",
 			dump_info->buf_handle, rc);
-		spin_unlock_bh(&ctx->lock);
-		return rc;
+		goto end;
 	}
 	if (buf_len <= dump_info->offset) {
 		spin_unlock_bh(&ctx->lock);
@@ -4238,59 +4460,80 @@ hw_dump:
 			req->request_id);
 		dump_only_event_record = true;
 	}
-	dst = (uint8_t *)cpu_addr + dump_info->offset;
-	hdr = (struct cam_isp_context_dump_header *)dst;
-	scnprintf(hdr->tag, CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN,
-		"ISP_CTX_DUMP:");
-	hdr->word_size = sizeof(uint64_t);
-	addr = (uint64_t *)(dst +
-		sizeof(struct cam_isp_context_dump_header));
-	start = addr;
-	*addr++ = req->request_id;
-	ts      = ktime_to_timespec64(
-		req_isp->event_timestamp[CAM_ISP_CTX_EVENT_APPLY]);
-	*addr++ = ts.tv_sec;
-	*addr++ = ts.tv_nsec/NSEC_PER_USEC;
-	ts      = ktime_to_timespec64(cur_time);
-	*addr++ = ts.tv_sec;
-	*addr++ = ts.tv_nsec/NSEC_PER_USEC;
-	hdr->size = hdr->word_size * (addr - start);
-	dump_info->offset += hdr->size +
-		sizeof(struct cam_isp_context_dump_header);
 
-	rc = __cam_isp_ctx_dump_event_record(ctx_isp, cpu_addr,
-		buf_len, &dump_info->offset);
+	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 = ctx_isp->hw_ctx;
+
+	/* Dump time info */
+	rc = cam_common_user_dump_helper(&dump_args, cam_isp_ctx_user_dump_timer,
+		req, sizeof(uint64_t), "ISP_CTX_DUMP:");
 	if (rc) {
-		CAM_ERR(CAM_ISP, "Dump event fail %lld",
-			req->request_id);
-		spin_unlock_bh(&ctx->lock);
-		return rc;
+		CAM_ERR(CAM_ISP, "Time dump fail %lld, rc: %d",
+			req->request_id, rc);
+		goto end;
+	}
+	dump_info->offset = dump_args.offset;
+
+	/* Dump stream info */
+	ctx->ctxt_to_hw_map = ctx_isp->hw_ctx;
+	rc = cam_common_user_dump_helper(&dump_args, cam_isp_ctx_user_dump_stream_info,
+		ctx, sizeof(int32_t), "ISP_STREAM_INFO:");
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Stream info dump fail %lld, rc: %d",
+			req->request_id, rc);
+		goto end;
+	}
+	dump_info->offset = dump_args.offset;
+
+	/* Dump event record */
+	rc = __cam_isp_ctx_dump_event_record(ctx_isp, &dump_args);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Event record dump fail %lld, rc: %d",
+			req->request_id, rc);
+		goto end;
 	}
+	dump_info->offset = dump_args.offset;
 	if (dump_only_event_record) {
-		spin_unlock_bh(&ctx->lock);
-		return rc;
+		goto end;
 	}
-	rc = __cam_isp_ctx_dump_req_info(ctx, req, cpu_addr,
-		buf_len, &dump_info->offset);
+
+	/* Dump state monitor array */
+	rc = __cam_isp_ctx_user_dump_state_monitor_array(ctx_isp, &dump_args);
 	if (rc) {
-		CAM_ERR(CAM_ISP, "Dump Req info fail %lld",
-			req->request_id);
-		spin_unlock_bh(&ctx->lock);
-		return rc;
+		CAM_ERR(CAM_ISP, "Dump event fail %lld, rc: %d",
+			req->request_id, rc);
+		goto end;
+	}
+
+	/* Dump request info */
+	rc = __cam_isp_ctx_dump_req_info(ctx, req, &dump_args);
+	if (rc) {
+		CAM_ERR(CAM_ISP, "Dump Req info fail %lld, rc: %d",
+			req->request_id, rc);
+		goto end;
 	}
 	spin_unlock_bh(&ctx->lock);
 
+	/* Dump CSID, VFE, and SFE info */
+	dump_info->offset = dump_args.offset;
 	if (ctx->hw_mgr_intf->hw_dump) {
-		dump_args.offset = dump_info->offset;
-		dump_args.request_id = dump_info->req_id;
-		dump_args.buf_handle = dump_info->buf_handle;
-		dump_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
+		ife_dump_args.offset = dump_args.offset;
+		ife_dump_args.request_id = dump_info->req_id;
+		ife_dump_args.buf_handle = dump_info->buf_handle;
+		ife_dump_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
 		rc = ctx->hw_mgr_intf->hw_dump(
 			ctx->hw_mgr_intf->hw_mgr_priv,
-			&dump_args);
-		dump_info->offset = dump_args.offset;
+			&ife_dump_args);
+		dump_info->offset = ife_dump_args.offset;
 	}
 	return rc;
+
+end:
+	spin_unlock_bh(&ctx->lock);
+	return rc;
 }
 
 static int __cam_isp_ctx_flush_req_in_flushed_state(

+ 2 - 2
drivers/cam_isp/cam_isp_context.h

@@ -50,10 +50,10 @@
 #define CAM_ISP_CTX_DUMP_REQUEST_NUM_WORDS  2
 
 /* Maximum entries in event record */
-#define CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES   20
+#define CAM_ISP_CTX_EVENT_RECORD_MAX_ENTRIES   8
 
 /* Maximum length of tag while dumping */
-#define CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN 32
+#define CAM_ISP_CONTEXT_DUMP_TAG_MAX_LEN 64
 
 /* AEB error count threshold */
 #define CAM_ISP_CONTEXT_AEB_ERROR_CNT_MAX 3

+ 59 - 75
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c

@@ -11757,12 +11757,20 @@ static int cam_ife_mgr_dump(void *hw_mgr_priv, void *args)
 {
 	struct cam_isp_hw_dump_args isp_hw_dump_args;
 	struct cam_hw_dump_args *dump_args = (struct cam_hw_dump_args *)args;
-	struct cam_isp_hw_mgr_res            *hw_mgr_res;
 	struct cam_hw_intf                   *hw_intf;
 	struct cam_ife_hw_mgr_ctx *ife_ctx = (struct cam_ife_hw_mgr_ctx *)
 						dump_args->ctxt_to_hw_map;
 	int i;
 	int rc = 0;
+	uint32_t hw_idx = 0;
+
+	if (!ife_ctx) {
+		CAM_ERR(CAM_ISP, "ISP CTX null");
+		return -EINVAL;
+	} else if (!ife_ctx->num_base) {
+		CAM_ERR(CAM_ISP, "ISP CTX num_base null");
+		return -EINVAL;
+	}
 
 	/* for some targets, information about the IFE registers to be dumped
 	 * is already submitted with the hw manager. In this case, we
@@ -11770,7 +11778,7 @@ static int cam_ife_mgr_dump(void *hw_mgr_priv, void *args)
 	 */
 	if (ife_ctx->num_reg_dump_buf) {
 		cam_ife_mgr_user_dump_hw(ife_ctx, dump_args);
-		goto end;
+		return rc;
 	}
 
 	rc  = cam_mem_get_cpu_buf(dump_args->buf_handle,
@@ -11779,90 +11787,66 @@ static int cam_ife_mgr_dump(void *hw_mgr_priv, void *args)
 	if (rc) {
 		CAM_ERR(CAM_ISP, "Invalid handle %u rc %d",
 			dump_args->buf_handle, rc);
-		return rc;
+		return -EINVAL;
 	}
 
 	isp_hw_dump_args.offset = dump_args->offset;
 	isp_hw_dump_args.req_id = dump_args->request_id;
 
-	list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_csid, list) {
-		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
-			if (!hw_mgr_res->hw_res[i])
-				continue;
-			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
-			switch (hw_mgr_res->hw_res[i]->res_id) {
-			case CAM_IFE_PIX_PATH_RES_RDI_0:
-			case CAM_IFE_PIX_PATH_RES_RDI_1:
-			case CAM_IFE_PIX_PATH_RES_RDI_2:
-			case CAM_IFE_PIX_PATH_RES_RDI_3:
-				if (ife_ctx->flags.is_rdi_only_context &&
-					hw_intf->hw_ops.process_cmd) {
-					rc = hw_intf->hw_ops.process_cmd(
-						hw_intf->hw_priv,
-						CAM_ISP_HW_CMD_DUMP_HW,
-						&isp_hw_dump_args,
-						sizeof(struct
-						    cam_isp_hw_dump_args));
-				}
-				break;
-			case CAM_IFE_PIX_PATH_RES_IPP:
-				if (hw_intf->hw_ops.process_cmd) {
-					rc = hw_intf->hw_ops.process_cmd(
-						hw_intf->hw_priv,
-						CAM_ISP_HW_CMD_DUMP_HW,
-						&isp_hw_dump_args,
-						sizeof(struct
-						    cam_isp_hw_dump_args));
-				}
-				break;
-			default:
-				CAM_DBG(CAM_ISP, "not a valid res %d",
-				hw_mgr_res->res_id);
-				break;
-			}
-		}
+	if (isp_hw_dump_args.buf_len <= isp_hw_dump_args.offset) {
+		CAM_ERR(CAM_ISP,
+			"Dump offset overshoot offset %zu buf_len %zu",
+			isp_hw_dump_args.offset, isp_hw_dump_args.buf_len);
+		return -EINVAL;
 	}
 
-	list_for_each_entry(hw_mgr_res, &ife_ctx->res_list_ife_src, list) {
-		for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) {
-			if (!hw_mgr_res->hw_res[i])
-				continue;
-			hw_intf = hw_mgr_res->hw_res[i]->hw_intf;
-			switch (hw_mgr_res->res_id) {
-			case CAM_ISP_HW_VFE_IN_RDI0:
-			case CAM_ISP_HW_VFE_IN_RDI1:
-			case CAM_ISP_HW_VFE_IN_RDI2:
-			case CAM_ISP_HW_VFE_IN_RDI3:
-				if (ife_ctx->flags.is_rdi_only_context &&
-					hw_intf->hw_ops.process_cmd) {
-					rc = hw_intf->hw_ops.process_cmd(
-						hw_intf->hw_priv,
-						CAM_ISP_HW_CMD_DUMP_HW,
-						&isp_hw_dump_args,
-						sizeof(struct
-						    cam_isp_hw_dump_args));
-				}
-				break;
-			case CAM_ISP_HW_VFE_IN_CAMIF:
-				if (hw_intf->hw_ops.process_cmd) {
-					rc = hw_intf->hw_ops.process_cmd(
-						hw_intf->hw_priv,
-						CAM_ISP_HW_CMD_DUMP_HW,
-						&isp_hw_dump_args,
-						sizeof(struct
-						    cam_isp_hw_dump_args));
-				}
-				break;
-			default:
-				CAM_DBG(CAM_ISP, "not a valid res %d",
-					hw_mgr_res->res_id);
-				break;
+	for (i = 0; i < ife_ctx->num_base; i++) {
+		hw_idx = ife_ctx->base[i].idx;
+
+		switch (ife_ctx->base[i].hw_type) {
+		case CAM_ISP_HW_TYPE_CSID:
+			hw_intf = ife_ctx->hw_mgr->csid_devices[hw_idx];
+			if (!hw_intf) {
+				CAM_ERR(CAM_ISP, "hw_intf null, returning rc...");
+				return -EINVAL;
+			}
+			rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
+				CAM_ISP_HW_USER_DUMP, &isp_hw_dump_args,
+				sizeof(struct cam_isp_hw_dump_args));
+			if (rc)
+				return rc;
+			break;
+		case CAM_ISP_HW_TYPE_VFE:
+			hw_intf = ife_ctx->hw_mgr->ife_devices[hw_idx]->hw_intf;
+			if (!hw_intf || !hw_intf->hw_priv) {
+				CAM_ERR(CAM_ISP, "hw_intf null, returning rc...");
+				return -EINVAL;
+			}
+			rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
+				CAM_ISP_HW_USER_DUMP, &isp_hw_dump_args,
+				sizeof(struct cam_isp_hw_dump_args));
+			if (rc)
+				return rc;
+			break;
+		case CAM_ISP_HW_TYPE_SFE:
+			hw_intf = ife_ctx->hw_mgr->sfe_devices[hw_idx]->hw_intf;
+			if (!hw_intf || !hw_intf->hw_priv) {
+				CAM_ERR(CAM_ISP, "hw_intf null, returning rc...");
+				return -EINVAL;
 			}
+			rc = hw_intf->hw_ops.process_cmd(hw_intf->hw_priv,
+				CAM_ISP_HW_USER_DUMP, &isp_hw_dump_args,
+				sizeof(struct cam_isp_hw_dump_args));
+			if (rc)
+				return rc;
+			break;
+		default:
+			break;
 		}
+
 	}
+
 	dump_args->offset = isp_hw_dump_args.offset;
-end:
-	CAM_DBG(CAM_ISP, "offset %u", dump_args->offset);
 	return rc;
 }
 

+ 105 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/ife_csid_hw/cam_ife_csid_hw_ver2.c

@@ -5001,7 +5001,7 @@ static int cam_ife_csid_ver2_mini_dump(
 	}
 
 	md  = (struct cam_ife_csid_ver2_mini_dump_data *)
-		    ((uint8_t *)md_args->start_addr);
+		((uint8_t *)md_args->start_addr);
 	md->clk_rate = csid_hw->clk_rate;
 	md->hw_state = csid_hw->hw_info->hw_state;
 
@@ -5026,6 +5026,107 @@ static int cam_ife_csid_ver2_mini_dump(
 	return 0;
 }
 
+static void *cam_ife_csid_ver2_user_dump_info(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	struct cam_isp_resource_node       *res = NULL;
+	struct cam_hw_info                 *hw_info = NULL;
+	struct cam_ife_csid_ver2_hw        *csid_hw = NULL;
+	struct cam_ife_csid_ver2_reg_info  *csid_reg = NULL;
+	struct cam_hw_soc_info             *soc_info = NULL;
+	uint32_t                           *addr;
+	uint32_t                            frame = 0;
+	uint32_t                            val0 = 0, val1 = 0, val2 = 0;
+
+	res = (struct cam_isp_resource_node *)dump_struct;
+	hw_info = (struct cam_hw_info *)res->hw_intf->hw_priv;
+	csid_hw = (struct cam_ife_csid_ver2_hw *)hw_info->core_info;
+	csid_reg = csid_hw->core_info->csid_reg;
+	soc_info = &csid_hw->hw_info->soc_info;
+
+	frame = cam_io_r_mb(soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base +
+	csid_reg->path_reg[res->res_id]->format_measure0_addr);
+
+	val0 = cam_io_r_mb(soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base +
+		csid_reg->path_reg[res->res_id]->debug_camif_0_addr);
+	val1 = cam_io_r_mb(soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base +
+		csid_reg->path_reg[res->res_id]->debug_camif_1_addr);
+	val2 = cam_io_r_mb(soc_info->reg_map[CAM_IFE_CSID_CLC_MEM_BASE_ID].mem_base +
+		csid_reg->path_reg[res->res_id]->debug_halt_status_addr);
+
+	addr = (uint32_t *)addr_ptr;
+
+	*addr++ = ((frame >> csid_reg->cmn_reg->format_measure_height_shift_val) &
+		csid_reg->cmn_reg->format_measure_height_mask_val);
+	*addr++ = frame & csid_reg->cmn_reg->format_measure_width_mask_val;
+	*addr++ = val0;
+	*addr++ = val1;
+	*addr++ = val2;
+
+	return addr;
+}
+
+static int cam_ife_csid_ver2_user_dump(
+	struct cam_ife_csid_ver2_hw  *csid_hw,
+	void *cmd_args)
+{
+	uint32_t                                    i = 0;
+	struct cam_ife_csid_ver2_path_cfg          *path_cfg;
+	struct cam_isp_resource_node               *res;
+	struct cam_isp_hw_dump_args                *dump_args;
+	struct cam_ife_csid_ver2_reg_info          *csid_reg;
+	struct cam_hw_soc_info                     *soc_info;
+	int                                         rc = 0;
+
+	if (!csid_hw || !cmd_args) {
+		CAM_ERR(CAM_ISP, "Invalid bus private data");
+		return -EINVAL;
+	} else if (csid_hw->hw_info->hw_state == CAM_HW_STATE_POWER_DOWN) {
+		CAM_WARN(CAM_ISP,
+			"CSID:%u powered down",
+			csid_hw->hw_intf->hw_idx);
+		return -EINVAL;
+	}
+
+	dump_args = (struct cam_isp_hw_dump_args *)cmd_args;
+	csid_reg = (struct cam_ife_csid_ver2_reg_info *)csid_hw->core_info->csid_reg;
+	soc_info = &csid_hw->hw_info->soc_info;
+
+	rc = cam_common_user_dump_helper(dump_args, cam_common_user_dump_clock,
+		csid_hw->hw_info, sizeof(uint64_t), "CLK_RATE_PRINT:");
+
+	if (rc) {
+		CAM_ERR(CAM_ISP, "CSID VER2: Clock dump failed, rc: %d", rc);
+		return rc;
+	}
+
+	/* Loop through CSID items */
+	for (i = 0; i < CAM_IFE_PIX_PATH_RES_MAX; i++) {
+		res = &csid_hw->path_res[i];
+
+		if (res->res_state < CAM_ISP_RESOURCE_STATE_RESERVED) {
+			CAM_DBG(CAM_ISP,
+				"CSID VER2: path inactive res ID: %d, continuing",
+				res->res_id);
+			continue;
+		}
+
+		path_cfg = (struct cam_ife_csid_ver2_path_cfg *)res->res_priv;
+		if (!path_cfg)
+			continue;
+
+		rc = cam_common_user_dump_helper(dump_args, cam_ife_csid_ver2_user_dump_info,
+			res, sizeof(uint32_t), "CSID2_PATH.%s:", res->res_name);
+
+		if (rc) {
+			CAM_ERR(CAM_ISP, "CSID VER2: Info dump failed, rc:%d", rc);
+			return rc;
+		}
+
+	}
+	return 0;
+}
+
 static int cam_ife_csid_ver2_dual_sync_cfg(
 	struct cam_ife_csid_ver2_hw  *csid_hw,
 	void *cmd_args)
@@ -5216,6 +5317,9 @@ static int cam_ife_csid_ver2_process_cmd(void *hw_priv,
 	case CAM_ISP_HW_CSID_MINI_DUMP:
 		rc  = cam_ife_csid_ver2_mini_dump(csid_hw, cmd_args);
 		break;
+	case CAM_ISP_HW_USER_DUMP:
+		rc = cam_ife_csid_ver2_user_dump(csid_hw, cmd_args);
+		break;
 	case CAM_IFE_CSID_PROGRAM_OFFLINE_CMD:
 		rc = cam_ife_csid_ver2_program_offline_go_cmd(
 			csid_hw, cmd_args, arg_size);

+ 2 - 1
drivers/cam_isp/isp_hw_mgr/isp_hw/include/cam_isp_hw.h

@@ -16,7 +16,7 @@
 #include "cam_hw_mgr_intf.h"
 
 /* Maximum length of tag while dumping */
-#define CAM_ISP_HW_DUMP_TAG_MAX_LEN 32
+#define CAM_ISP_HW_DUMP_TAG_MAX_LEN 64
 /* Max isp hw pid values number */
 #define CAM_ISP_HW_MAX_PID_VAL      4
 /* Maximum number of output ports that map to an architecture specific input path */
@@ -203,6 +203,7 @@ enum cam_isp_hw_cmd_type {
 	CAM_ISP_HW_CMD_INIT_CONFIG_UPDATE,
 	CAM_ISP_HW_CSID_MINI_DUMP,
 	CAM_ISP_HW_BUS_MINI_DUMP,
+	CAM_ISP_HW_USER_DUMP,
 	CAM_ISP_HW_CMD_RDI_LCR_CFG,
 	CAM_ISP_HW_CMD_MAX,
 };

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/cam_sfe_core.c

@@ -411,6 +411,7 @@ int cam_sfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_QUERY_BUS_CAP:
 	case CAM_ISP_HW_SFE_SYS_CACHE_WM_CONFIG:
 	case CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG:
+	case CAM_ISP_HW_USER_DUMP:
 		rc = core_info->sfe_bus_wr->hw_ops.process_cmd(
 			core_info->sfe_bus_wr->bus_priv, cmd_type,
 			cmd_args, arg_size);

+ 109 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/sfe_hw/sfe_bus/cam_sfe_bus_wr.c

@@ -2064,6 +2064,109 @@ static int cam_sfe_bus_wr_print_dimensions(
 	return 0;
 }
 
+static void *cam_sfe_bus_wr_user_dump_info(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	struct cam_sfe_bus_wr_wm_resource_data  *wm = NULL;
+	uint32_t                                  *addr;
+	uint32_t                                   addr_status0;
+	uint32_t                                   addr_status1;
+	uint32_t                                   addr_status2;
+	uint32_t                                   addr_status3;
+
+	wm = (struct cam_sfe_bus_wr_wm_resource_data *)dump_struct;
+
+	addr_status0 = cam_io_r_mb(wm->common_data->mem_base +
+		wm->hw_regs->addr_status_0);
+	addr_status1 = cam_io_r_mb(wm->common_data->mem_base +
+		wm->hw_regs->addr_status_1);
+	addr_status2 = cam_io_r_mb(wm->common_data->mem_base +
+		wm->hw_regs->addr_status_2);
+	addr_status3 = cam_io_r_mb(wm->common_data->mem_base +
+		wm->hw_regs->addr_status_3);
+
+	addr = (uint32_t *)addr_ptr;
+
+	*addr++ = wm->common_data->hw_intf->hw_idx;
+	*addr++ = wm->index;
+	*addr++ = addr_status0;
+	*addr++ = addr_status1;
+	*addr++ = addr_status2;
+	*addr++ = addr_status3;
+
+	return addr;
+}
+
+static int cam_sfe_bus_wr_user_dump(
+	struct cam_sfe_bus_wr_priv *bus_priv,
+	void *cmd_args)
+{
+	struct cam_isp_resource_node              *rsrc_node = NULL;
+	struct cam_sfe_bus_wr_out_data            *rsrc_data = NULL;
+	struct cam_sfe_bus_wr_wm_resource_data    *wm = NULL;
+	struct cam_hw_info                        *hw_info = NULL;
+	struct cam_isp_hw_dump_args               *dump_args;
+	uint32_t                                   i, j = 0;
+	int                                        rc = 0;
+
+
+	if (!bus_priv || !cmd_args) {
+		CAM_ERR(CAM_ISP, "Invalid bus private data");
+		return -EINVAL;
+	}
+
+	hw_info = (struct cam_hw_info *)bus_priv->common_data.hw_intf->hw_priv;
+	dump_args = (struct cam_isp_hw_dump_args *)cmd_args;
+
+	if (hw_info->hw_state == CAM_HW_STATE_POWER_DOWN) {
+		CAM_WARN(CAM_ISP,
+			"SFE BUS powered down, continuing");
+		return -EINVAL;
+	}
+
+	rc = cam_common_user_dump_helper(dump_args, cam_common_user_dump_clock,
+		hw_info, sizeof(uint64_t), "CLK_RATE_PRINT:");
+
+	if (rc) {
+		CAM_ERR(CAM_ISP, "SFE BUS WR: Clock dump failed, rc:%d", rc);
+		return rc;
+	}
+
+	for (i = 0; i < bus_priv->num_out; i++) {
+		rsrc_node = &bus_priv->sfe_out[i];
+		if (!rsrc_node)
+			continue;
+
+		if (rsrc_node->res_state < CAM_ISP_RESOURCE_STATE_RESERVED) {
+			CAM_DBG(CAM_ISP,
+				"SFE BUS WR: path inactive res ID: %d, continuing",
+				rsrc_node->res_id);
+			continue;
+		}
+
+		rsrc_data = rsrc_node->res_priv;
+		if (!rsrc_data)
+			continue;
+		for (j = 0; j < rsrc_data->num_wm; j++) {
+
+			wm = rsrc_data->wm_res[j].res_priv;
+			if (!wm)
+				continue;
+
+			rc = cam_common_user_dump_helper(dump_args, cam_sfe_bus_wr_user_dump_info,
+				wm, sizeof(uint32_t), "SFE_BUS_CLIENT.%s.%d:",
+				rsrc_data->wm_res[j].res_name,
+				rsrc_data->common_data->core_index);
+
+			if (rc) {
+				CAM_ERR(CAM_ISP, "SFE BUS WR: Info dump failed, rc:%d", rc);
+				return rc;
+			}
+		}
+	}
+	return 0;
+}
+
 static int cam_sfe_bus_wr_handle_bus_irq(uint32_t    evt_id,
 	struct cam_irq_th_payload                 *th_payload)
 {
@@ -3185,6 +3288,12 @@ static int cam_sfe_bus_wr_process_cmd(
 		rc = cam_sfe_bus_wr_print_dimensions(
 			sfe_out_res_id, (struct cam_sfe_bus_wr_priv  *)priv);
 		break;
+		}
+	case CAM_ISP_HW_USER_DUMP: {
+		bus_priv = (struct cam_sfe_bus_wr_priv  *) priv;
+
+		rc = cam_sfe_bus_wr_user_dump(bus_priv, cmd_args);
+		break;
 	}
 	case CAM_ISP_HW_CMD_WM_CONFIG_UPDATE:
 		rc = cam_sfe_bus_wr_update_wm_config(cmd_args);

+ 1 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/cam_vfe_core.c

@@ -538,6 +538,7 @@ int cam_vfe_process_cmd(void *hw_priv, uint32_t cmd_type,
 	case CAM_ISP_HW_CMD_WM_BW_LIMIT_CONFIG:
 	case CAM_ISP_HW_BUS_MINI_DUMP:
 	case CAM_ISP_HW_CMD_BUF_UPDATE:
+	case CAM_ISP_HW_USER_DUMP:
 		rc = core_info->vfe_bus->hw_ops.process_cmd(
 			core_info->vfe_bus->bus_priv, cmd_type, cmd_args,
 			arg_size);

+ 108 - 0
drivers/cam_isp/isp_hw_mgr/isp_hw/vfe_hw/vfe_bus/cam_vfe_bus_ver3.c

@@ -2725,6 +2725,109 @@ end:
 	return 0;
 }
 
+static void *cam_vfe_bus_ver3_user_dump_info(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	struct cam_vfe_bus_ver3_wm_resource_data  *wm = NULL;
+	uint32_t                                  *addr;
+	uint32_t                                   addr_status0;
+	uint32_t                                   addr_status1;
+	uint32_t                                   addr_status2;
+	uint32_t                                   addr_status3;
+
+	wm = (struct cam_vfe_bus_ver3_wm_resource_data *)dump_struct;
+
+	addr_status0 = cam_io_r_mb(wm->common_data->mem_base +
+		wm->hw_regs->addr_status_0);
+	addr_status1 = cam_io_r_mb(wm->common_data->mem_base +
+		wm->hw_regs->addr_status_1);
+	addr_status2 = cam_io_r_mb(wm->common_data->mem_base +
+		wm->hw_regs->addr_status_2);
+	addr_status3 = cam_io_r_mb(wm->common_data->mem_base +
+		wm->hw_regs->addr_status_3);
+
+	addr = (uint32_t *)addr_ptr;
+
+	*addr++ = wm->common_data->hw_intf->hw_idx;
+	*addr++ = wm->index;
+	*addr++ = addr_status0;
+	*addr++ = addr_status1;
+	*addr++ = addr_status2;
+	*addr++ = addr_status3;
+
+	return addr;
+}
+
+static int cam_vfe_bus_ver3_user_dump(
+	struct cam_vfe_bus_ver3_priv *bus_priv,
+	void *cmd_args)
+{
+	struct cam_isp_resource_node              *rsrc_node = NULL;
+	struct cam_vfe_bus_ver3_vfe_out_data      *rsrc_data = NULL;
+	struct cam_vfe_bus_ver3_wm_resource_data  *wm = NULL;
+	struct cam_hw_info                        *hw_info = NULL;
+	struct cam_isp_hw_dump_args               *dump_args;
+	uint32_t                                   i, j = 0;
+	int                                        rc = 0;
+
+
+	if (!bus_priv || !cmd_args) {
+		CAM_ERR(CAM_ISP, "Bus private data NULL");
+		return -EINVAL;
+	}
+
+	hw_info = (struct cam_hw_info *)bus_priv->common_data.hw_intf->hw_priv;
+	dump_args = (struct cam_isp_hw_dump_args *)cmd_args;
+
+	if (hw_info->hw_state == CAM_HW_STATE_POWER_DOWN) {
+		CAM_WARN(CAM_ISP,
+			"VFE BUS powered down");
+		return -EINVAL;
+	}
+
+	rc = cam_common_user_dump_helper(dump_args, cam_common_user_dump_clock,
+		hw_info, sizeof(uint64_t), "CLK_RATE_PRINT:");
+
+	if (rc) {
+		CAM_ERR(CAM_ISP, "VFE BUS VER3: Clock dump failed, rc: %d", rc);
+		return rc;
+	}
+
+	for (i = 0; i < bus_priv->num_out; i++) {
+		rsrc_node = &bus_priv->vfe_out[i];
+		if (!rsrc_node)
+			continue;
+
+		if (rsrc_node->res_state < CAM_ISP_RESOURCE_STATE_RESERVED) {
+			CAM_DBG(CAM_ISP,
+				"VFE BUS VER3: path inactive res ID: %d, continuing",
+				rsrc_node->res_id);
+			continue;
+		}
+
+		rsrc_data = rsrc_node->res_priv;
+		if (!rsrc_data)
+			continue;
+		for (j = 0; j < rsrc_data->num_wm; j++) {
+
+			wm = rsrc_data->wm_res[j].res_priv;
+			if (!wm)
+				continue;
+
+			rc = cam_common_user_dump_helper(dump_args, cam_vfe_bus_ver3_user_dump_info,
+				wm, sizeof(uint32_t), "VFE_BUS_CLIENT.%s.%d:",
+				rsrc_data->wm_res[j].res_name,
+				rsrc_data->common_data->core_index);
+
+			if (rc) {
+				CAM_ERR(CAM_ISP, "VFE BUS VER3: Info dump failed, rc: %d", rc);
+				return rc;
+			}
+		}
+	}
+	return 0;
+}
+
 static int cam_vfe_bus_ver3_print_dimensions(
 	uint32_t                                   res_id,
 	struct cam_vfe_bus_ver3_priv              *bus_priv)
@@ -4216,7 +4319,12 @@ static int cam_vfe_bus_ver3_process_cmd(
 		rc = cam_vfe_bus_ver3_mini_dump(bus_priv, cmd_args);
 		break;
 		}
+	case CAM_ISP_HW_USER_DUMP: {
+		bus_priv = (struct cam_vfe_bus_ver3_priv  *) priv;
 
+		rc = cam_vfe_bus_ver3_user_dump(bus_priv, cmd_args);
+		break;
+	}
 	case CAM_ISP_HW_CMD_UBWC_UPDATE_V2:
 		rc = cam_vfe_bus_ver3_update_ubwc_config_v2(cmd_args);
 		break;

+ 78 - 0
drivers/cam_utils/cam_common_util.c

@@ -14,6 +14,7 @@
 #include "cam_common_util.h"
 #include "cam_debug_util.h"
 #include "cam_presil_hw_access.h"
+#include "cam_hw.h"
 #if IS_REACHABLE(CONFIG_QCOM_VA_MINIDUMP)
 #include <soc/qcom/minidump.h>
 static  struct cam_common_mini_dump_dev_info g_minidump_dev_info;
@@ -258,3 +259,80 @@ end:
 	return rc;
 }
 #endif
+
+void *cam_common_user_dump_clock(
+	void *dump_struct, uint8_t *addr_ptr)
+{
+	struct cam_hw_info  *hw_info = NULL;
+	uint64_t            *addr = NULL;
+
+	hw_info = (struct cam_hw_info *)dump_struct;
+
+	if (!hw_info || !addr_ptr) {
+		CAM_ERR(CAM_ISP, "HW info or address pointer NULL");
+		return addr;
+	}
+
+	addr = (uint64_t *)addr_ptr;
+	*addr++ = hw_info->soc_info.applied_src_clk_rate;
+	return addr;
+}
+
+int cam_common_user_dump_helper(
+	void *cmd_args,
+	void *(*func)(void *dump_struct, uint8_t *addr_ptr),
+	void *dump_struct,
+	size_t size,
+	const char *tag, ...)
+{
+
+	uint8_t                                   *dst;
+	uint8_t                                   *addr, *start;
+	void                                      *returned_ptr;
+	struct cam_common_hw_dump_args            *dump_args;
+	struct cam_common_hw_dump_header          *hdr;
+	va_list                                    args;
+	void*(*func_ptr)(void *dump_struct, uint8_t *addr_ptr);
+
+	dump_args = (struct cam_common_hw_dump_args *)cmd_args;
+	if (!dump_args->cpu_addr || !dump_args->buf_len) {
+		CAM_ERR(CAM_UTIL,
+			"Invalid params %pK %zu",
+			(void *)dump_args->cpu_addr,
+			dump_args->buf_len);
+		return -EINVAL;
+	}
+	if (dump_args->buf_len <= dump_args->offset) {
+		CAM_WARN(CAM_UTIL,
+			"Dump offset overshoot offset %zu buf_len %zu",
+			dump_args->offset, dump_args->buf_len);
+		return -ENOSPC;
+	}
+
+	dst = (uint8_t *)dump_args->cpu_addr + dump_args->offset;
+	hdr = (struct cam_common_hw_dump_header *)dst;
+
+	va_start(args, tag);
+	vscnprintf(hdr->tag, CAM_COMMON_HW_DUMP_TAG_MAX_LEN, tag, args);
+	va_end(args);
+
+	hdr->word_size = size;
+
+	addr = (uint8_t *)(dst + sizeof(struct cam_common_hw_dump_header));
+	start = addr;
+
+	func_ptr = func;
+	returned_ptr = func_ptr(dump_struct, addr);
+
+	if (IS_ERR(returned_ptr))
+		return PTR_ERR(returned_ptr);
+
+	addr = (uint8_t *)returned_ptr;
+	hdr->size = addr - start;
+	CAM_DBG(CAM_UTIL, "hdr size: %d, word size: %d, addr: %x, start: %x",
+		hdr->size, hdr->word_size, addr, start);
+	dump_args->offset += hdr->size +
+		sizeof(struct cam_common_hw_dump_header);
+
+	return 0;
+}

+ 67 - 0
drivers/cam_utils/cam_common_util.h

@@ -17,6 +17,8 @@
 #define CAM_COMMON_MINI_DUMP_DEV_NAME_LEN 16
 #define CAM_COMMON_MINI_DUMP_SIZE         10 * 1024 * 1024
 
+#define CAM_COMMON_HW_DUMP_TAG_MAX_LEN 64
+
 #define PTR_TO_U64(ptr) ((uint64_t)(uintptr_t)ptr)
 #define U64_TO_PTR(ptr) ((void *)(uintptr_t)ptr)
 
@@ -76,6 +78,38 @@ struct cam_common_mini_dump_data {
 	unsigned long  size[CAM_COMMON_MINI_DUMP_DEV_NUM];
 };
 
+/**
+ * struct cam_common_hw_dump_args
+ * @req_id         : request id
+ * @cpu_addr       : address where dumping will start from
+ * @buf_len        : length of buffer where data is being dumped to
+ * @offset         : buffer offset from cpu_addr after each item dump
+ * @ctxt_to_hw_map : context to hw map
+ * @is_dump_all    : flag to indicate if all information or just bw/clk rate
+ * @
+ */
+struct cam_common_hw_dump_args {
+	uint64_t                req_id;
+	uintptr_t               cpu_addr;
+	size_t                  buf_len;
+	size_t                  offset;
+	void                   *ctxt_to_hw_map;
+	bool                    is_dump_all;
+};
+
+/**
+ * struct cam_common_hw_dump_header
+ * @tag        : string used by the parser to call parse functions
+ * @size       : size of the header in the buffer
+ * @word_size  : word size of the header
+ * @
+ */
+struct cam_common_hw_dump_header {
+	uint8_t   tag[CAM_COMMON_HW_DUMP_TAG_MAX_LEN];
+	uint64_t  size;
+	uint32_t  word_size;
+};
+
 /**
  * cam_common_util_get_string_index()
  *
@@ -191,4 +225,37 @@ static inline int cam_common_register_mini_dump_cb(
 	return 0;
 }
 #endif
+
+/**
+ * cam_common_user_dump_clock()
+ *
+ * @brief                  Handles clock rate dump
+ *
+ * @dump_struct:           Struct holding dump info
+ * @addr_ptr:              Pointer to buffer address pointer
+ */
+void *cam_common_user_dump_clock(
+	void     *dump_struct,
+	uint8_t  *addr_ptr);
+
+/**
+ * cam_common_user_dump_helper()
+ *
+ * @brief                  Handles buffer addressing and dumping for user dump
+ *
+ * @cmd_args:              Holds cam_common_hw_dump_args pointer
+ * @func:                  Function pointer for dump function
+ * @dump_struct:           Struct holding dump info
+ * @size:                  Size_t value used for header word size
+ * @tag:                   Tag for header, used by parser
+ * @...:                   Variadic arguments, appended to tag if given
+ */
+int cam_common_user_dump_helper(
+	void        *cmd_args,
+	void        *(*func)(void *, uint8_t *),
+	void        *dump_struct,
+	size_t       size,
+	const char  *tag,
+	...);
+
 #endif /* _CAM_COMMON_UTIL_H_ */