Răsfoiți Sursa

msm: camera: common: Add Minidump changes for NRT devices

Based on targets, in case of device crash, in place
of complete memory dump, mini dump can be extracted.
This commit adds changes in context utils for NRT devices
and in ICP, JPEG drivers.

CRs-Fixed: 2993116
Change-Id: I7c4af2cdf44713f741d3d772316080124e8a9a7f
Signed-off-by: Gaurav Jindal <[email protected]>
Gaurav Jindal 4 ani în urmă
părinte
comite
2f5933b075

+ 21 - 0
drivers/cam_core/cam_context.c

@@ -341,6 +341,27 @@ int cam_context_handle_crm_dump_req(struct cam_context *ctx,
 	return rc;
 }
 
+int cam_context_mini_dump_from_hw(struct cam_context *ctx,
+	void  *args)
+{
+	int rc = 0;
+
+	if (!ctx->state_machine) {
+		CAM_ERR(CAM_CORE, "Context [id %d name:%s] is not ready", ctx->ctx_id,
+			ctx->dev_name);
+		return -EINVAL;
+	}
+
+	if ((ctx->state >= CAM_CTX_AVAILABLE) && (ctx->state < CAM_CTX_STATE_MAX)) {
+		if (ctx->state_machine[ctx->state].mini_dump_ops)
+			rc = ctx->state_machine[ctx->state].mini_dump_ops(ctx, args);
+		else
+			CAM_WARN(CAM_CORE, "No dump ctx in dev %d, state %d",
+				ctx->dev_hdl, ctx->state);
+	}
+	return rc;
+}
+
 int cam_context_dump_pf_info(struct cam_context *ctx,
 	struct cam_smmu_pf_info *pf_info)
 {

+ 16 - 0
drivers/cam_core/cam_context.h

@@ -168,6 +168,7 @@ struct cam_ctx_crm_ops {
  * @dumpinfo_ops:          Function to be invoked for dumping any
  *                         context info
  * @recovery_ops:          Function to be invoked to try hardware recovery
+ * @mini_dump_ops:         Function for mini dump
  *
  */
 struct cam_ctx_ops {
@@ -177,6 +178,7 @@ struct cam_ctx_ops {
 	cam_hw_pagefault_cb_func     pagefault_ops;
 	cam_ctx_info_dump_cb_func    dumpinfo_ops;
 	cam_ctx_recovery_cb_func     recovery_ops;
+	cam_ctx_mini_dump_cb_func    mini_dump_ops;
 };
 
 /**
@@ -218,6 +220,7 @@ struct cam_ctx_ops {
  * @hw_updater_entry:      Hw update entry
  * @in_map_entries:        In map update entry
  * @out_map_entries:       Out map entry
+ * @mini dump cb:          Mini dump cb
  *
  */
 struct cam_context {
@@ -262,6 +265,7 @@ struct cam_context {
 	struct cam_hw_update_entry    *hw_update_entry;
 	struct cam_hw_fence_map_entry *in_map_entries;
 	struct cam_hw_fence_map_entry *out_map_entries;
+	cam_ctx_mini_dump_cb_func      mini_dump_cb;
 
 };
 
@@ -408,6 +412,18 @@ int cam_context_handle_crm_process_evt(struct cam_context *ctx,
 int cam_context_handle_crm_dump_req(struct cam_context *ctx,
 	struct cam_req_mgr_dump_info *dump);
 
+/**
+ * cam_context_mini_dump_from_hw()
+ *
+ * @brief:        Handle mini dump request command
+ *
+ * @ctx:          Object pointer for cam_context
+ * @args:         Args to be passed
+ *
+ */
+int cam_context_mini_dump_from_hw(struct cam_context *ctx,
+	void  *args);
+
 /**
  * cam_context_dump_pf_info()
  *

+ 152 - 0
drivers/cam_core/cam_context_utils.c

@@ -615,6 +615,7 @@ int32_t cam_context_acquire_dev_to_hw(struct cam_context *ctx,
 	param.context_data = ctx;
 	param.ctx_id = ctx->ctx_id;
 	param.event_cb = ctx->irq_cb_intf;
+	param.mini_dump_cb = ctx->mini_dump_cb;
 	param.num_acq = cmd->num_resources;
 	param.acquire_info = cmd->resource_hdl;
 
@@ -1318,3 +1319,154 @@ err:
 
 	return 0;
 }
+
+static void __cam_context_req_mini_dump(struct cam_ctx_request *req,
+	uint8_t *start_addr, uint8_t *end_addr,
+	unsigned long *bytes_updated)
+{
+	struct cam_hw_req_mini_dump      *req_md;
+	struct cam_buf_io_cfg            *io_cfg;
+	struct cam_packet                *packet = NULL;
+	unsigned long                     bytes_written = 0;
+	unsigned long                     bytes_required = 0;
+
+	bytes_required = sizeof(*req_md);
+	if (start_addr + bytes_written + bytes_required > end_addr)
+		goto end;
+
+	req_md = (struct cam_hw_req_mini_dump *)start_addr;
+
+	req_md->num_fence_map_in = req->num_in_map_entries;
+	req_md->num_fence_map_out = req->num_out_map_entries;
+	req_md->num_in_acked = atomic_read(&req->num_in_acked);
+	req_md->num_out_acked = req->num_out_acked;
+	req_md->request_id = req->request_id;
+	bytes_written += bytes_required;
+
+	if (req->num_out_map_entries) {
+		bytes_required = sizeof(struct cam_hw_fence_map_entry) *
+					req->num_out_map_entries;
+		if (start_addr + bytes_written + bytes_required > end_addr)
+			goto end;
+
+		req_md->fence_map_out = (struct cam_hw_fence_map_entry *)
+				(start_addr + bytes_written);
+		memcpy(req_md->fence_map_out, req->out_map_entries, bytes_required);
+		req_md->num_fence_map_out = req->num_out_map_entries;
+		bytes_written += bytes_required;
+	}
+
+	if (req->num_in_map_entries) {
+		bytes_required = sizeof(struct cam_hw_fence_map_entry) *
+				    req->num_in_map_entries;
+		if (start_addr + bytes_written + bytes_required > end_addr)
+			goto end;
+
+		req_md->fence_map_in = (struct cam_hw_fence_map_entry *)
+				(start_addr + bytes_written);
+		memcpy(req_md->fence_map_in, req->in_map_entries, bytes_required);
+		req_md->num_fence_map_in = req->num_in_map_entries;
+		bytes_written += bytes_required;
+	}
+
+	packet = (struct cam_packet *)req->pf_data.packet;
+	if (packet && packet->num_io_configs) {
+		bytes_required = packet->num_io_configs * sizeof(struct cam_buf_io_cfg);
+		if (start_addr + bytes_written + bytes_required > end_addr)
+			goto end;
+
+		io_cfg = (struct cam_buf_io_cfg *)((uint32_t *)&packet->payload +
+			    packet->io_configs_offset / 4);
+		req_md->io_cfg = (struct cam_buf_io_cfg *)(start_addr + bytes_written);
+		memcpy(req_md->io_cfg, io_cfg, bytes_required);
+		bytes_written += bytes_required;
+		req_md->num_io_cfg = packet->num_io_configs;
+	}
+
+end:
+	*bytes_updated = bytes_written;
+}
+
+int cam_context_mini_dump(struct cam_context *ctx, void *args)
+{
+	struct cam_hw_mini_dump_info *md;
+	struct cam_ctx_request *req, *req_temp;
+	struct cam_hw_mini_dump_args *md_args;
+	uint8_t                      *start_addr;
+	uint8_t                      *end_addr;
+	unsigned long                 bytes_written = 0;
+	unsigned long                 bytes_updated = 0;
+
+	if (!ctx || !args) {
+		CAM_ERR(CAM_CTXT, "invalid params");
+		return -EINVAL;
+	}
+
+	md_args = (struct cam_hw_mini_dump_args *)args;
+	if (md_args->len < sizeof(*md)) {
+		md_args->bytes_written = 0;
+		CAM_ERR(CAM_CTXT, "Insufficient len %lu, bytes_written %lu", md_args->len,
+			md_args->bytes_written);
+		return 0;
+	}
+
+	start_addr = (uint8_t *)md_args->start_addr;
+	end_addr  = start_addr + md_args->len;
+	md = (struct cam_hw_mini_dump_info *)md_args->start_addr;
+	md->ctx_id = ctx->ctx_id;
+	md->last_flush_req = ctx->last_flush_req;
+	md->hw_mgr_ctx_id = ctx->hw_mgr_ctx_id;
+	md->dev_id = ctx->dev_id;
+	md->link_hdl = ctx->link_hdl;
+	md->state = ctx->state;
+	md->session_hdl = ctx->session_hdl;
+	md->dev_hdl = ctx->dev_hdl;
+	scnprintf(md->name, CAM_HW_MINI_DUMP_DEV_NAME_LEN, ctx->dev_name);
+	bytes_written += sizeof(*md);
+
+	if (!list_empty(&ctx->active_req_list)) {
+		md->active_list = (struct cam_hw_req_mini_dump *)
+			    (start_addr + bytes_written);
+		list_for_each_entry_safe(req, req_temp, &ctx->active_req_list, list) {
+			bytes_updated = 0;
+			__cam_context_req_mini_dump(req,
+				(uint8_t *)&md->active_list[md->active_cnt++],
+				end_addr, &bytes_updated);
+			if ((start_addr + bytes_written + bytes_updated >= end_addr))
+				goto end;
+			bytes_written += bytes_updated;
+		}
+	}
+
+	if (!list_empty(&ctx->wait_req_list)) {
+		md->wait_list = (struct cam_hw_req_mini_dump *)
+			    (start_addr + bytes_written);
+		list_for_each_entry_safe(req, req_temp, &ctx->wait_req_list, list) {
+			bytes_updated = 0;
+			__cam_context_req_mini_dump(req,
+				(uint8_t *)&md->wait_list[md->wait_cnt++],
+				end_addr, &bytes_updated);
+			if ((start_addr + bytes_written + bytes_updated >= end_addr))
+				goto end;
+			bytes_written += bytes_updated;
+		}
+	}
+
+	if (!list_empty(&ctx->pending_req_list)) {
+		md->pending_list = (struct cam_hw_req_mini_dump *)
+			    (start_addr + bytes_written);
+		list_for_each_entry_safe(req, req_temp, &ctx->pending_req_list, list) {
+			bytes_updated = 0;
+			__cam_context_req_mini_dump(req,
+				(uint8_t *)&md->pending_list[md->pending_cnt++],
+				end_addr, &bytes_updated);
+			if ((start_addr + bytes_written + bytes_updated >= end_addr))
+				goto end;
+			bytes_written += bytes_updated;
+		}
+	}
+end:
+	md_args->bytes_written = bytes_written;
+	CAM_INFO(CAM_CTXT, "Ctx %s bytes_written %lu", ctx->dev_name, md_args->bytes_written);
+	return 0;
+}

+ 1 - 0
drivers/cam_core/cam_context_utils.h

@@ -36,4 +36,5 @@ int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx,
 	struct cam_dump_req_cmd *cmd);
 size_t cam_context_parse_config_cmd(struct cam_context *ctx, struct cam_config_dev_cmd *cmd,
 	struct cam_packet **packet);
+int cam_context_mini_dump(struct cam_context *ctx, void *args);
 #endif /* _CAM_CONTEXT_UTILS_H_ */

+ 70 - 0
drivers/cam_core/cam_hw_mgr_intf.h

@@ -26,6 +26,9 @@
 /* Maximum reg dump cmd buffer entries in a context */
 #define CAM_REG_DUMP_MAX_BUF_ENTRIES        10
 
+/* max device name string length*/
+#define CAM_HW_MINI_DUMP_DEV_NAME_LEN       20
+
 /**
  * enum cam_context_dump_id -
  *              context dump type
@@ -415,6 +418,73 @@ struct cam_hw_mini_dump_args {
 	unsigned long     bytes_written;
 };
 
+/**
+ * struct cam_hw_req_mini_dump - Mini dump context req
+ *
+ * @fence_map_out:       Fence map out array
+ * @fence_map_in:        Fence map in array
+ * @io_cfg:              IO cfg.
+ * @request_id:          Request id
+ * @num_fence_map_in:    num of fence map in
+ * @num_fence_map_in:    num of fence map out
+ * @num_io_cfg:          num of io cfg
+ * @num_in_acked:        num in acked
+ * @num_out_acked:       num out acked
+ * @status:              Status
+ * @flushed:             whether request is flushed
+ *
+ */
+struct cam_hw_req_mini_dump {
+	struct cam_hw_fence_map_entry     *fence_map_out;
+	struct cam_hw_fence_map_entry     *fence_map_in;
+	struct cam_buf_io_cfg             *io_cfg;
+	uint64_t                           request_id;
+	uint16_t                           num_fence_map_in;
+	uint16_t                           num_fence_map_out;
+	uint16_t                           num_io_cfg;
+	uint16_t                           num_in_acked;
+	uint16_t                           num_out_acked;
+	uint8_t                            status;
+	uint8_t                            flushed;
+};
+
+/**
+ * struct cam_hw_mini_dump_info - Mini dump context info
+ *
+ * @active_list:          array of active req in context
+ * @wait_list:            array of  wait req in context
+ * @pending_list:         array of pending req in context
+ * @name:                 name of context
+ * @dev_id:               dev id.
+ * @last_flush_req:       last flushed request id
+ * @refcount:             kernel ref count
+ * @ctx_id:               Context id
+ * @session_hdl:          Session handle
+ * @link_hdl:             link handle
+ * @dev_hdl:              Dev hdl
+ * @state:                State of context
+ * @hw_mgr_ctx_id:        ctx id with hw mgr
+ *
+ */
+struct cam_hw_mini_dump_info {
+	struct   cam_hw_req_mini_dump   *active_list;
+	struct   cam_hw_req_mini_dump   *wait_list;
+	struct   cam_hw_req_mini_dump   *pending_list;
+	char                             name[CAM_HW_MINI_DUMP_DEV_NAME_LEN];
+	uint64_t                         dev_id;
+	uint32_t                         last_flush_req;
+	uint32_t                         refcount;
+	uint32_t                         ctx_id;
+	uint32_t                         active_cnt;
+	uint32_t                         pending_cnt;
+	uint32_t                         wait_cnt;
+	int32_t                          session_hdl;
+	int32_t                          link_hdl;
+	int32_t                          dev_hdl;
+	uint8_t                          state;
+	uint8_t                          hw_mgr_ctx_id;
+};
+
 /**
  * cam_hw_mgr_intf - HW manager interface
  *

+ 23 - 0
drivers/cam_icp/cam_icp_context.c

@@ -66,6 +66,25 @@ end:
 	return rc;
 }
 
+static int cam_icp_context_mini_dump(void *priv, void *args)
+{
+	int rc;
+	struct cam_context *ctx;
+
+	if (!priv || !args) {
+		CAM_ERR(CAM_ICP, "Invalid priv %pK args %pK", priv, args);
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *)priv;
+	rc = cam_context_mini_dump(ctx, args);
+	if (rc)
+		CAM_ERR(CAM_ICP, "ctx [id: %u name: %s] Mini Dump failed rc %d", ctx->dev_name,
+			ctx->ctx_id, rc);
+
+	return rc;
+}
+
 static int __cam_icp_acquire_dev_in_available(struct cam_context *ctx,
 	struct cam_acquire_dev_cmd *cmd)
 {
@@ -236,6 +255,7 @@ static struct cam_ctx_ops
 		},
 		.crm_ops = {},
 		.irq_ops = NULL,
+		.mini_dump_ops = cam_icp_context_mini_dump,
 	},
 	/* Acquired */
 	{
@@ -249,6 +269,7 @@ static struct cam_ctx_ops
 		.crm_ops = {},
 		.irq_ops = __cam_icp_handle_buf_done_in_ready,
 		.pagefault_ops = cam_icp_context_dump_active_request,
+		.mini_dump_ops = cam_icp_context_mini_dump,
 	},
 	/* Ready */
 	{
@@ -262,6 +283,7 @@ static struct cam_ctx_ops
 		.crm_ops = {},
 		.irq_ops = __cam_icp_handle_buf_done_in_ready,
 		.pagefault_ops = cam_icp_context_dump_active_request,
+		.mini_dump_ops = cam_icp_context_mini_dump,
 	},
 	/* Flushed */
 	{
@@ -273,6 +295,7 @@ static struct cam_ctx_ops
 		.crm_ops = {},
 		.irq_ops = NULL,
 		.pagefault_ops = cam_icp_context_dump_active_request,
+		.mini_dump_ops = cam_icp_context_mini_dump,
 	},
 };
 

+ 14 - 1
drivers/cam_icp/cam_icp_subdev.c

@@ -66,6 +66,19 @@ static void cam_icp_dev_iommu_fault_handler(struct cam_smmu_pf_info *pf_info)
 		cam_context_dump_pf_info(&(node->ctx_list[i]), pf_info);
 }
 
+static void cam_icp_dev_mini_dump_cb(void *priv, void *args)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!priv || !args) {
+		CAM_ERR(CAM_ICP, "Invalid param priv: %pK args %pK", priv, args);
+		return;
+	}
+
+	ctx = (struct cam_context *)priv;
+	cam_context_mini_dump_from_hw(ctx, args);
+}
+
 static int cam_icp_subdev_open(struct v4l2_subdev *sd,
 	struct v4l2_subdev_fh *fh)
 {
@@ -187,7 +200,7 @@ static int cam_icp_component_bind(struct device *dev,
 	}
 
 	rc = cam_icp_hw_mgr_init(pdev->dev.of_node, (uint64_t *)hw_mgr_intf,
-		&iommu_hdl);
+		&iommu_hdl, cam_icp_dev_mini_dump_cb);
 	if (rc) {
 		CAM_ERR(CAM_ICP, "ICP HW manager init failed: %d", rc);
 		goto hw_init_fail;

+ 20 - 0
drivers/cam_icp/fw_inc/hfi_intf.h

@@ -8,6 +8,9 @@
 
 #include <linux/types.h>
 
+#define HFI_CMD_Q_MINI_DUMP_SIZE_IN_BYTES      4096
+#define HFI_MSG_Q_MINI_DUMP_SIZE_IN_BYTES      4096
+
 /**
  * struct hfi_mem
  * @len: length of memory
@@ -61,6 +64,19 @@ struct hfi_ops {
 	void __iomem *(*iface_addr)(void *data);
 };
 
+/**
+ * struct hfi_mini_dump_info
+ * @cmd_q: cmd queue
+ * @msg_q: msg queue
+ * @msg_q_state: msg queue state
+ * @cmd_q_state: cmd queue state
+ */
+struct hfi_mini_dump_info {
+	uint32_t       cmd_q[HFI_CMD_Q_MINI_DUMP_SIZE_IN_BYTES];
+	uint32_t       msg_q[HFI_MSG_Q_MINI_DUMP_SIZE_IN_BYTES];
+	bool           msg_q_state;
+	bool           cmd_q_state;
+};
 /**
  * hfi_write_cmd() - function for hfi write
  * @cmd_ptr: pointer to command data for hfi write
@@ -163,5 +179,9 @@ int cam_hfi_resume(struct hfi_mem_info *hfi_mem);
  */
 void cam_hfi_queue_dump(void);
 
+/**
+ * cam_hfi_mini_dump() - utility function for mini dump
+ */
+void cam_hfi_mini_dump(struct hfi_mini_dump_info *dst);
 
 #endif /* _HFI_INTF_H_ */

+ 26 - 0
drivers/cam_icp/hfi.c

@@ -87,6 +87,32 @@ static void hfi_queue_dump(uint32_t *dwords, int count)
 			rows * 4, dwords[0], dwords[1], dwords[2]);
 }
 
+void cam_hfi_mini_dump(struct hfi_mini_dump_info *dst)
+{
+	struct hfi_mem_info *hfi_mem = &g_hfi->map;
+	struct hfi_qtbl *qtbl;
+	struct hfi_q_hdr *q_hdr;
+	uint32_t *dwords;
+	int num_dwords;
+
+	if (!hfi_mem) {
+		CAM_ERR(CAM_HFI, "hfi mem info NULL... unable to dump queues");
+		return;
+	}
+
+	qtbl = (struct hfi_qtbl *)hfi_mem->qtbl.kva;
+	q_hdr = &qtbl->q_hdr[Q_CMD];
+	dwords = (uint32_t *)hfi_mem->cmd_q.kva;
+	num_dwords = ICP_CMD_Q_SIZE_IN_BYTES >> BYTE_WORD_SHIFT;
+	memcpy(dst->cmd_q, dwords, ICP_CMD_Q_SIZE_IN_BYTES);
+
+	q_hdr = &qtbl->q_hdr[Q_MSG];
+	dwords = (uint32_t *)hfi_mem->msg_q.kva;
+	memcpy(dst->msg_q, dwords, ICP_CMD_Q_SIZE_IN_BYTES);
+	dst->msg_q_state = g_hfi->msg_q_state;
+	dst->cmd_q_state = g_hfi->cmd_q_state;
+}
+
 void cam_hfi_queue_dump(void)
 {
 	struct hfi_mem_info *hfi_mem = &g_hfi->map;

+ 38 - 0
drivers/cam_icp/icp_hw/a5_hw/a5_core.c

@@ -178,6 +178,37 @@ static int cam_a5_fw_dump(
 	return 0;
 }
 
+static int cam_a5_fw_mini_dump(
+	struct cam_icp_hw_dump_args    *dump_args,
+	struct cam_a5_device_core_info *core_info)
+{
+	u8                         *dest;
+	u8                         *src;
+
+	if (!core_info || !dump_args) {
+		CAM_ERR(CAM_ICP, "invalid params %pK %pK", core_info, dump_args);
+		return -EINVAL;
+	}
+
+	if (!core_info->fw_kva_addr || !dump_args->cpu_addr) {
+		CAM_ERR(CAM_ICP, "invalid params %pK, 0x%zx", core_info->fw_kva_addr,
+			dump_args->cpu_addr);
+		return -EINVAL;
+	}
+
+	if (dump_args->buf_len < core_info->fw_buf_len) {
+		CAM_WARN(CAM_ICP, "Insufficient Len %lu fw_len %llu",
+			dump_args->buf_len, core_info->fw_buf_len);
+		return -ENOSPC;
+	}
+
+	dest = (u8 *)dump_args->cpu_addr;
+	src = (u8 *)core_info->fw_kva_addr;
+	memcpy_fromio(dest, src, core_info->fw_buf_len);
+	dump_args->offset = core_info->fw_buf_len;
+	return 0;
+}
+
 int cam_a5_init_hw(void *device_priv,
 	void *init_hw_args, uint32_t arg_size)
 {
@@ -706,6 +737,13 @@ int cam_a5_process_cmd(void *device_priv, uint32_t cmd_type,
 		rc = cam_a5_fw_dump(dump_args, core_info);
 		break;
 	}
+
+	case CAM_ICP_CMD_HW_MINI_DUMP: {
+		struct cam_icp_hw_dump_args *dump_args = cmd_args;
+
+		rc = cam_a5_fw_mini_dump(dump_args, core_info);
+		break;
+	}
 	default:
 		break;
 	}

+ 130 - 1
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c

@@ -3711,6 +3711,132 @@ static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id)
 	return 0;
 }
 
+static unsigned long cam_icp_hw_mgr_mini_dump_cb(void *dst, unsigned long len)
+{
+	struct cam_icp_hw_mini_dump_info   *md;
+	struct cam_icp_hw_ctx_mini_dump    *ctx_md;
+	struct cam_icp_hw_ctx_data         *ctx;
+	struct cam_icp_hw_mgr              *hw_mgr;
+	struct cam_hw_mini_dump_args        hw_dump_args;
+	struct cam_icp_hw_dump_args         icp_dump_args;
+	struct cam_hw_intf                 *icp_dev_intf = NULL;
+	uint32_t                            i = 0, j = 0;
+	unsigned long                       dumped_len = 0;
+	unsigned long                       remain_len = len;
+	int                                 rc = 0;
+
+	if (!dst || len < sizeof(*md)) {
+		CAM_ERR(CAM_ICP, "Invalid params dst %pk len %lu", dst, len);
+		return 0;
+	}
+
+	md = (struct cam_icp_hw_mini_dump_info *)dst;
+	md->num_context = 0;
+	hw_mgr = &icp_hw_mgr;
+	cam_hfi_mini_dump(&md->hfi_info);
+	memcpy(&md->hfi_mem_info, &hw_mgr->hfi_mem,
+		sizeof(struct icp_hfi_mem_info));
+	md->recovery = atomic_read(&hw_mgr->recovery);
+	md->icp_booted = hw_mgr->icp_booted;
+	md->icp_resumed = hw_mgr->icp_resumed;
+	md->ipe_clk_state = hw_mgr->ipe_clk_state;
+	md->ipe_clk_state = hw_mgr->ipe_clk_state;
+	md->bps_clk_state = hw_mgr->bps_clk_state;
+	md->disable_ubwc_comp = hw_mgr->disable_ubwc_comp;
+	md->ipe0_enable = hw_mgr->ipe0_enable;
+	md->ipe1_enable = hw_mgr->ipe1_enable;
+	md->bps_enable = hw_mgr->bps_enable;
+	md->icp_pc_flag = hw_mgr->icp_pc_flag;
+	md->ipe_bps_pc_flag = hw_mgr->ipe_bps_pc_flag;
+	md->icp_use_pil = hw_mgr->icp_use_pil;
+	dumped_len += sizeof(*md);
+	remain_len = len -  dumped_len;
+	for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
+		ctx = &hw_mgr->ctx_data[i];
+		if (ctx->state == CAM_ICP_CTX_STATE_FREE ||
+			ctx->state == CAM_ICP_CTX_STATE_RELEASE)
+			continue;
+
+		if (remain_len < sizeof(*ctx_md))
+			goto end;
+
+		md->num_context++;
+		ctx_md = (struct cam_icp_hw_ctx_mini_dump *)
+			    ((uint8_t *)dst + dumped_len);
+		md->ctx[i] = ctx_md;
+		ctx_md->state = ctx->state;
+		ctx_md->ctx_id = ctx->ctx_id;
+		memcpy(ctx_md->ctx_id_string, ctx->ctx_id_string,
+			strlen(ctx->ctx_id_string));
+		if (ctx->icp_dev_acquire_info) {
+			ctx_md->acquire.secure_mode =
+				ctx->icp_dev_acquire_info->secure_mode;
+			ctx_md->acquire.dev_type =
+				ctx->icp_dev_acquire_info->dev_type;
+			ctx_md->acquire.num_out_res =
+				ctx->icp_dev_acquire_info->num_out_res;
+			memcpy(&ctx_md->acquire.in_res,
+				&ctx->icp_dev_acquire_info->in_res,
+				sizeof(struct cam_icp_res_info));
+			memcpy(ctx_md->acquire.out_res,
+				ctx->icp_dev_acquire_info->out_res,
+				sizeof(ctx->icp_dev_acquire_info->out_res));
+		} else {
+			memset(&ctx_md->acquire, 0,
+				sizeof(struct cam_icp_mini_dump_acquire_info));
+		}
+
+		memcpy(ctx_md->hfi_frame.request_id, ctx->hfi_frame_process.request_id,
+			sizeof(ctx->hfi_frame_process.request_id));
+		memcpy(ctx_md->hfi_frame.in_resource, ctx->hfi_frame_process.in_resource,
+			sizeof(ctx->hfi_frame_process.in_resource));
+		memcpy(ctx_md->hfi_frame.submit_timestamp,
+			ctx->hfi_frame_process.submit_timestamp,
+			sizeof(ctx->hfi_frame_process.submit_timestamp));
+		memcpy(ctx_md->hfi_frame.num_out_res, ctx->hfi_frame_process.num_out_resources,
+			sizeof(ctx->hfi_frame_process.num_out_resources));
+		memcpy(ctx_md->hfi_frame.out_res, ctx->hfi_frame_process.out_resource,
+			sizeof(ctx->hfi_frame_process.out_resource));
+		for (j = 0; j < CAM_FRAME_CMD_MAX; j++) {
+			ctx_md->hfi_frame.fw_process_flag[j] =
+				ctx->hfi_frame_process.fw_process_flag[j];
+		}
+
+		dumped_len += sizeof(*ctx_md);
+		remain_len = len - dumped_len;
+		hw_dump_args.len = remain_len;
+		hw_dump_args.bytes_written = 0;
+		hw_dump_args.start_addr = (void *)((uint8_t *)dst + dumped_len);
+		hw_mgr->mini_dump_cb(ctx->context_priv, &hw_dump_args);
+		if (dumped_len + hw_dump_args.bytes_written >= len)
+			goto end;
+
+		ctx_md->hw_ctx = hw_dump_args.start_addr;
+		dumped_len += hw_dump_args.bytes_written;
+		remain_len = len - dumped_len;
+	}
+
+	/* Dump fw image */
+	if (!hw_mgr->icp_use_pil) {
+		icp_dump_args.cpu_addr = (uintptr_t)((uint8_t *)dst + dumped_len);
+		icp_dump_args.offset = 0;
+		icp_dump_args.buf_len = remain_len;
+		icp_dev_intf = hw_mgr->icp_dev_intf;
+		rc = icp_dev_intf->hw_ops.process_cmd(
+			icp_dev_intf->hw_priv,
+			CAM_ICP_CMD_HW_MINI_DUMP, &icp_dump_args,
+			sizeof(struct cam_icp_hw_dump_args));
+		if (rc)
+			goto end;
+
+		dumped_len += icp_dump_args.offset;
+		md->fw_img = (void *)icp_dump_args.cpu_addr;
+		remain_len = len - dumped_len;
+	}
+end:
+	return dumped_len;
+}
+
 static void cam_icp_mgr_device_deinit(struct cam_icp_hw_mgr *hw_mgr)
 {
 	struct cam_hw_intf *icp_dev_intf = NULL;
@@ -6351,7 +6477,7 @@ static int cam_icp_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 }
 
 int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
-	int *iommu_hdl)
+	int *iommu_hdl, cam_icp_mini_dump_cb mini_dump_cb)
 {
 	int i, rc = 0;
 	struct cam_hw_mgr_intf *hw_mgr_intf;
@@ -6380,6 +6506,7 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 	hw_mgr_intf->hw_dump = cam_icp_mgr_hw_dump;
 
 	icp_hw_mgr.secure_mode = CAM_SECURE_MODE_NON_SECURE;
+	icp_hw_mgr.mini_dump_cb = mini_dump_cb;
 	mutex_init(&icp_hw_mgr.hw_mgr_mutex);
 	spin_lock_init(&icp_hw_mgr.hw_mgr_lock);
 
@@ -6445,6 +6572,8 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 		*iommu_hdl = icp_hw_mgr.iommu_hdl;
 
 	init_completion(&icp_hw_mgr.icp_complete);
+	cam_common_register_mini_dump_cb(
+		cam_icp_hw_mgr_mini_dump_cb, "cam_icp");
 	return rc;
 
 icp_wq_create_failed:

+ 98 - 0
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h

@@ -14,6 +14,7 @@
 #include "cam_hw_intf.h"
 #include "cam_a5_hw_intf.h"
 #include "hfi_session_defs.h"
+#include "hfi_intf.h"
 #include "cam_req_mgr_workq.h"
 #include "cam_mem_mgr.h"
 #include "cam_smmu_api.h"
@@ -75,6 +76,8 @@
  */
 #define CAM_ICP_CTX_RESPONSE_TIME_THRESHOLD   300000
 
+struct hfi_mini_dump_info;
+
 /**
  * struct icp_hfi_mem_info
  * @qtbl: Memory info of queue table
@@ -321,6 +324,7 @@ struct cam_icp_clk_info {
  * @devices: Devices of ICP hardware manager
  * @ctx_data: Context data
  * @icp_caps: ICP capabilities
+ * @mini_dump_cb: Mini dump cb
  * @icp_booted: Processor is booted i.e. firmware loaded
  * @icp_resumed: Processor is powered on
  * @iommu_hdl: Non secure IOMMU handle
@@ -372,6 +376,7 @@ struct cam_icp_hw_mgr {
 	struct cam_hw_intf **devices[CAM_ICP_DEV_MAX];
 	struct cam_icp_hw_ctx_data ctx_data[CAM_ICP_CTX_MAX];
 	struct cam_icp_query_cap_cmd icp_caps;
+	cam_icp_mini_dump_cb mini_dump_cb;
 
 	bool icp_booted;
 	bool icp_resumed;
@@ -415,6 +420,99 @@ struct cam_icp_hw_mgr {
 	atomic_t recovery;
 };
 
+/**
+ * struct cam_icp_mini_dump_acquire_info - ICP mini dump device info
+ *
+ * @in_res: resource info used for clock and bandwidth calculation
+ * @out_res: output resource
+ * @num_out_res: number of output resources
+ * @dev_type: device type (IPE_RT/IPE_NON_RT/BPS)
+ * @secure_mode: camera mode (secure/non secure)
+ */
+struct cam_icp_mini_dump_acquire_info {
+	struct cam_icp_res_info out_res[ICP_MAX_OUTPUT_SUPPORTED];
+	struct cam_icp_res_info in_res;
+	uint16_t                num_out_res;
+	uint8_t                 dev_type;
+	uint8_t                 secure_mode;
+};
+
+/**
+ * struct hfi_frame_process_info
+ * @request_id: Request id list
+ * @num_out_res: Number of out syncs
+ * @out_res: Out sync info
+ * @in_resource: In sync info
+ * @submit_timestamp: Submit timestamp to hw
+ * @fw_process_flag: Frame process flag
+ */
+struct  hfi_frame_mini_dump_info {
+	uint64_t                              request_id[CAM_FRAME_CMD_MAX];
+	uint32_t                              num_out_res[CAM_FRAME_CMD_MAX];
+	uint32_t                              out_res[CAM_FRAME_CMD_MAX][CAM_MAX_OUT_RES];
+	uint32_t                              in_resource[CAM_FRAME_CMD_MAX];
+	ktime_t                               submit_timestamp[CAM_FRAME_CMD_MAX];
+	uint8_t                               fw_process_flag[CAM_FRAME_CMD_MAX];
+};
+
+/**
+ * struct cam_icp_hw_ctx_mini_dump
+ * @acquire: Acquire device info
+ * @hfi_frame: Frame  command
+ * @hw_ctx: Context private data
+ * @state: context state
+ * @ctx_id_string: Context id string
+ * @ctx_id: Context Id
+ */
+struct cam_icp_hw_ctx_mini_dump {
+	struct cam_icp_mini_dump_acquire_info acquire;
+	struct hfi_frame_mini_dump_info       hfi_frame;
+	void                                 *hw_ctx;
+	char                                  ctx_id_string[128];
+	uint8_t                               state;
+	uint8_t                               ctx_id;
+};
+
+/**
+ * struct cam_icp_hw_mini_dump_info
+ *
+ * @ctx: Context for minidump
+ * @hfi_info: hfi info
+ * @hfi_mem_info: hfi mem info
+ * @fw_img: FW image
+ * @recovery: To indicate if recovery is on
+ * @icp_booted: Indicate if ICP is booted
+ * @icp_resumed: Indicate if ICP is resumed
+ * @ipe_clk_state: IPE Clk state
+ * @bps_clk_state: BPS clk state
+ * @disable_ubwc_comp: Indicate if ubws comp is disabled
+ * @ipe0_enable: Is IPE0 enabled
+ * @ipe1_enable: Is IPE1 enabled
+ * @bps_enable:  Is BPS enabled
+ * @icp_pc_flag: Is ICP PC enabled
+ * @ipe_bps_pc_flag: Is IPE BPS PC enabled
+ * @icp_use_pil: Is PIL used
+ */
+struct cam_icp_hw_mini_dump_info {
+	struct cam_icp_hw_ctx_mini_dump   *ctx[CAM_ICP_CTX_MAX];
+	struct hfi_mini_dump_info          hfi_info;
+	struct icp_hfi_mem_info            hfi_mem_info;
+	void                              *fw_img;
+	uint32_t                           recovery;
+	uint32_t                           num_context;
+	bool                               icp_booted;
+	bool                               icp_resumed;
+	bool                               ipe_clk_state;
+	bool                               bps_clk_state;
+	bool                               disable_ubwc_comp;
+	bool                               ipe0_enable;
+	bool                               ipe1_enable;
+	bool                               bps_enable;
+	bool                               icp_pc_flag;
+	bool                               ipe_bps_pc_flag;
+	bool                               icp_use_pil;
+};
+
 static int cam_icp_mgr_hw_close(void *hw_priv, void *hw_close_args);
 static int cam_icp_mgr_hw_open(void *hw_mgr_priv, void *download_fw_args);
 static int cam_icp_mgr_icp_resume(struct cam_icp_hw_mgr *hw_mgr);

+ 1 - 0
drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h

@@ -42,6 +42,7 @@ enum cam_icp_cmd_type {
 	CAM_ICP_CMD_PC_PREP,
 	CAM_ICP_CMD_CLK_UPDATE,
 	CAM_ICP_CMD_HW_DUMP,
+	CAM_ICP_CMD_HW_MINI_DUMP,
 	CAM_ICP_CMD_MAX,
 };
 

+ 5 - 1
drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h

@@ -30,8 +30,12 @@
 #define CAM_ICP_DUMP_TAG_MAX_LEN 32
 #define CAM_ICP_DUMP_NUM_WORDS   5
 
+typedef void(*cam_icp_mini_dump_cb)(void *priv,
+	void *args);
+
 int cam_icp_hw_mgr_init(struct device_node *of_node,
-	uint64_t *hw_mgr_hdl, int *iommu_hdl);
+	uint64_t *hw_mgr_hdl, int *iommu_hdl,
+	cam_icp_mini_dump_cb mini_dump_cb);
 
 void cam_icp_hw_mgr_deinit(void);
 

+ 36 - 0
drivers/cam_icp/icp_hw/lx7_hw/lx7_core.c

@@ -777,6 +777,38 @@ static int __cam_lx7_update_clk_rate(
 	return rc;
 }
 
+static int __cam_lx7_fw_mini_dump(
+	struct cam_lx7_core_info       *core_info,
+	struct cam_icp_hw_dump_args    *args)
+{
+	u8                          *dest;
+	u8                          *src;
+	struct cam_icp_hw_dump_args *dump_args = args;
+
+	if (!core_info || !dump_args) {
+		CAM_ERR(CAM_ICP, "invalid params %pK %pK", core_info, dump_args);
+		return -EINVAL;
+	}
+
+	if (!core_info->fw_params.fw_kva_addr || !dump_args->cpu_addr) {
+		CAM_ERR(CAM_ICP, "invalid params %pK, 0x%zx",
+		    core_info->fw_params.fw_kva_addr, dump_args->cpu_addr);
+		return -EINVAL;
+	}
+
+	if (dump_args->buf_len < core_info->fw_params.fw_buf_len) {
+		CAM_WARN(CAM_ICP, "Insufficient Len %lu fw_len %llu",
+			dump_args->buf_len, core_info->fw_params.fw_buf_len);
+		return -ENOSPC;
+	}
+
+	dest = (u8 *)dump_args->cpu_addr;
+	src = (u8 *)core_info->fw_params.fw_kva_addr;
+	memcpy_fromio(dest, src, core_info->fw_params.fw_buf_len);
+	dump_args->offset = core_info->fw_params.fw_buf_len;
+	return 0;
+}
+
 int cam_lx7_process_cmd(void *priv, uint32_t cmd_type,
 			void *args, uint32_t arg_size)
 {
@@ -829,6 +861,10 @@ int cam_lx7_process_cmd(void *priv, uint32_t cmd_type,
 		/* Not supported for lx7 */
 		rc = 0;
 		break;
+	case CAM_ICP_CMD_HW_MINI_DUMP: {
+		rc = __cam_lx7_fw_mini_dump(lx7_info->core_info, args);
+		break;
+	}
 	default:
 		CAM_ERR(CAM_ICP, "invalid command type=%u", cmd_type);
 		break;

+ 20 - 0
drivers/cam_jpeg/cam_jpeg_context.c

@@ -56,6 +56,24 @@ static int cam_jpeg_context_dump_active_request(void *data,
 	return rc;
 }
 
+static int cam_jpeg_context_mini_dump(void *priv, void *args)
+{
+	int rc;
+	struct cam_context *ctx;
+
+	if (!priv || args) {
+		CAM_ERR(CAM_ICP, "Invalid param priv %pK args %pK", priv, args);
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *)priv;
+	rc = cam_context_mini_dump(ctx, args);
+	if (rc)
+		CAM_ERR(CAM_JPEG, "Mini Dump failed %d", rc);
+
+	return rc;
+}
+
 static int __cam_jpeg_ctx_acquire_dev_in_available(struct cam_context *ctx,
 	struct cam_acquire_dev_cmd *cmd)
 {
@@ -151,6 +169,7 @@ static struct cam_ctx_ops
 		},
 		.crm_ops = { },
 		.irq_ops = NULL,
+		.mini_dump_ops = cam_jpeg_context_mini_dump,
 	},
 	/* Acquired */
 	{
@@ -164,6 +183,7 @@ static struct cam_ctx_ops
 		.crm_ops = { },
 		.irq_ops = __cam_jpeg_ctx_handle_buf_done_in_acquired,
 		.pagefault_ops = cam_jpeg_context_dump_active_request,
+		.mini_dump_ops = cam_jpeg_context_mini_dump,
 	},
 	/* Ready */
 	{

+ 15 - 1
drivers/cam_jpeg/cam_jpeg_dev.c

@@ -38,6 +38,19 @@ static void cam_jpeg_dev_iommu_fault_handler(
 		cam_context_dump_pf_info(&(node->ctx_list[i]), pf_info);
 }
 
+static void cam_jpeg_dev_mini_dump_cb(void *priv, void *args)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!priv || !args) {
+		CAM_ERR(CAM_JPEG, "Invalid param priv %pK %pK args", priv, args);
+		return;
+	}
+
+	ctx = (struct cam_context *)priv;
+	cam_context_mini_dump_from_hw(ctx, args);
+}
+
 static const struct of_device_id cam_jpeg_dt_match[] = {
 	{
 		.compatible = "qcom,cam-jpeg"
@@ -123,7 +136,8 @@ static int cam_jpeg_dev_component_bind(struct device *dev,
 	node = (struct cam_node *)g_jpeg_dev.sd.token;
 
 	rc = cam_jpeg_hw_mgr_init(pdev->dev.of_node,
-		(uint64_t *)&hw_mgr_intf, &iommu_hdl);
+		(uint64_t *)&hw_mgr_intf, &iommu_hdl,
+		cam_jpeg_dev_mini_dump_cb);
 	if (rc) {
 		CAM_ERR(CAM_JPEG, "Can not initialize JPEG HWmanager %d", rc);
 		goto unregister;

+ 81 - 2
drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c

@@ -1421,7 +1421,7 @@ static int cam_jpeg_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
 	mutex_unlock(&ctx_data->ctx_mutex);
 
 	hw_mgr->ctx_data[ctx_id].ctxt_event_cb = args->event_cb;
-
+	hw_mgr->ctx_data[ctx_id].mini_dump_cb = args->mini_dump_cb;
 
 	if (copy_to_user((void __user *)args->acquire_info,
 		&jpeg_dev_acquire_info,
@@ -1971,8 +1971,83 @@ static int cam_jpeg_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
 	return rc;
 }
 
+static unsigned long cam_jpeg_hw_mgr_mini_dump_cb(void *dst, unsigned long len)
+{
+	struct cam_jpeg_hw_mini_dump_req *md_req;
+	struct cam_jpeg_hw_mgr_mini_dump *md;
+	struct cam_jpeg_hw_ctx_mini_dump *ctx_md;
+	struct cam_jpeg_hw_ctx_data      *ctx;
+	struct cam_jpeg_hw_mgr           *hw_mgr;
+	struct cam_jpeg_hw_cfg_req       *req;
+	struct cam_hw_mini_dump_args      hw_dump_args;
+	uint32_t                          dev_type;
+	uint32_t                          i = 0;
+	unsigned long                     dumped_len = 0;
+	unsigned long                     remain_len = len;
+
+	if (!dst || len < sizeof(*md)) {
+		CAM_ERR(CAM_JPEG, "Invalid params dst %pk len %lu", dst, len);
+		return 0;
+	}
+
+	md = (struct cam_jpeg_hw_mgr_mini_dump *)dst;
+	md->num_context = 0;
+	hw_mgr = &g_jpeg_hw_mgr;
+	for (i = 0; i < CAM_JPEG_RES_TYPE_MAX; i++) {
+		if (hw_mgr->devices[i][0]->hw_ops.process_cmd) {
+			hw_mgr->devices[i][0]->hw_ops.process_cmd(
+				hw_mgr->devices[i][0]->hw_priv,
+				CAM_JPEG_CMD_MINI_DUMP,
+				&md->core[i],
+				sizeof(struct cam_jpeg_mini_dump_core_info));
+		}
+	}
+
+	dumped_len += sizeof(*md);
+	remain_len = len - dumped_len;
+	for (i = 0; i < CAM_JPEG_CTX_MAX; i++) {
+		ctx = &hw_mgr->ctx_data[i];
+		if (!ctx->in_use)
+			continue;
+
+		if (remain_len < sizeof(*ctx_md))
+			goto end;
+
+		md->num_context++;
+		ctx_md = (struct cam_jpeg_hw_ctx_mini_dump *)
+			    ((uint8_t *)dst + dumped_len);
+		md->ctx[i] = ctx_md;
+		ctx_md->in_use  = ctx->in_use;
+		memcpy(&ctx_md->acquire_info, &ctx->jpeg_dev_acquire_info,
+			sizeof(struct cam_jpeg_acquire_dev_info));
+		dev_type = ctx->jpeg_dev_acquire_info.dev_type;
+		req = hw_mgr->dev_hw_cfg_args[dev_type][0];
+		if (req) {
+			md_req = &md->cfg_req[dev_type];
+			memcpy(&md_req->submit_timestamp, &req->submit_timestamp,
+				sizeof(ktime_t));
+			md_req->req_id = req->req_id;
+			md_req->dev_type = req->dev_type;
+			md_req->num_hw_entry_processed = req->num_hw_entry_processed;
+		}
+
+		hw_dump_args.len = remain_len;
+		hw_dump_args.bytes_written = 0;
+		hw_dump_args.start_addr = (void *)((uint8_t *)dst + dumped_len);
+		hw_mgr->mini_dump_cb(ctx->context_priv, &hw_dump_args);
+		if (dumped_len + hw_dump_args.bytes_written >= len)
+			goto end;
+
+		dumped_len += hw_dump_args.bytes_written;
+		remain_len = len - dumped_len;
+	}
+
+end:
+	return dumped_len;
+}
+
 int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
-	int *iommu_hdl)
+	int *iommu_hdl, cam_jpeg_mini_dump_cb mini_dump_cb)
 {
 	int i, rc;
 	uint32_t num_dev;
@@ -2048,6 +2123,8 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 	g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.incr  = 0;
 	g_jpeg_hw_mgr.jpeg_caps.dev_ver[CAM_JPEG_DEV_DMA].hw_ver.reserved = 0;
 
+	g_jpeg_hw_mgr.mini_dump_cb = mini_dump_cb;
+
 	rc = cam_jpeg_setup_workqs();
 	if (rc) {
 		CAM_ERR(CAM_JPEG, "setup work qs failed  %d", rc);
@@ -2057,6 +2134,8 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
 	if (iommu_hdl)
 		*iommu_hdl = g_jpeg_hw_mgr.iommu_hdl;
 
+	cam_common_register_mini_dump_cb(cam_jpeg_hw_mgr_mini_dump_cb, "CAM_JPEG");
+
 	return rc;
 
 cdm_iommu_failed:

+ 46 - 0
drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h

@@ -103,6 +103,7 @@ struct cam_jpeg_hw_cfg_req {
  * @in_use: Flag for context usage
  * @wait_complete: Completion info
  * @cdm_cmd: Cdm cmd submitted for that context.
+ * @mini_dump_cb: Mini dump cb
  */
 struct cam_jpeg_hw_ctx_data {
 	void *context_priv;
@@ -112,6 +113,7 @@ struct cam_jpeg_hw_ctx_data {
 	bool in_use;
 	struct completion wait_complete;
 	struct cam_cdm_bl_request *cdm_cmd;
+	cam_ctx_mini_dump_cb_func      mini_dump_cb;
 };
 
 /**
@@ -138,6 +140,7 @@ struct cam_jpeg_hw_ctx_data {
  * @free_req_list: Free nodes for above list
  * @req_list: Nodes of hw update list
  * @num_pid: num of pids supported in the device
+ * @mini_dump_cb: Mini dump cb
  */
 struct cam_jpeg_hw_mgr {
 	struct mutex hw_mgr_mutex;
@@ -167,6 +170,49 @@ struct cam_jpeg_hw_mgr {
 	struct list_head free_req_list;
 	struct cam_jpeg_hw_cfg_req req_list[CAM_JPEG_HW_CFG_Q_MAX];
 	uint32_t num_pid[CAM_JPEG_DEV_TYPE_MAX];
+	cam_jpeg_mini_dump_cb      mini_dump_cb;
 };
 
+/**
+ * struct cam_jpeg_hw_mini_dump_req
+ *
+ * @submit_timestamp:        Time stamp of request submit
+ * @req_id:                  Request Id
+ * @dev_type:                Dev type
+ * @num_hw_entry_processed:  Num of hw entry processed
+ */
+struct cam_jpeg_hw_mini_dump_req {
+	ktime_t    submit_timestamp;
+	uintptr_t  req_id;
+	uint32_t   dev_type;
+	uint32_t   num_hw_entry_processed;
+};
+
+/**
+ * struct cam_jpeg_hw_ctx_mini_dump
+ *
+ * @acquire_info:        Acquire info
+ * @hw_ctx:              hw context info
+ * @in_use:              flag to indicate if in use
+ */
+struct cam_jpeg_hw_ctx_mini_dump {
+	struct cam_jpeg_acquire_dev_info        acquire_info;
+	struct cam_hw_mini_dump_info            hw_ctx;
+	bool                                    in_use;
+};
+
+/**
+ * struct cam_jpeg_hw_mgr_mini_dump
+ *
+ * @ctx:               Context info array
+ * @cfg_req:           Cfg req
+ * @core:              core info
+ * @num_context:       Num of context
+ */
+struct cam_jpeg_hw_mgr_mini_dump {
+	struct cam_jpeg_hw_ctx_mini_dump      *ctx[CAM_JPEG_CTX_MAX];
+	struct cam_jpeg_hw_mini_dump_req       cfg_req[CAM_JPEG_DEV_TYPE_MAX];
+	struct cam_jpeg_mini_dump_core_info    core[CAM_JPEG_RES_TYPE_MAX];
+	uint32_t                               num_context;
+};
 #endif /* CAM_JPEG_HW_MGR_H */

+ 12 - 0
drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h

@@ -56,12 +56,24 @@ struct cam_jpeg_match_pid_args {
 	uint32_t    match_res;
 };
 
+struct cam_jpeg_mini_dump_core_info {
+	uint32_t           framedone;
+	uint32_t           resetdone;
+	uint32_t           iserror;
+	uint32_t           stopdone;
+	uint32_t           open_count;
+	int32_t            ref_count;
+	uint32_t           core_state;
+	uint32_t           hw_state;
+};
+
 enum cam_jpeg_cmd_type {
 	CAM_JPEG_CMD_CDM_CFG,
 	CAM_JPEG_CMD_SET_IRQ_CB,
 	CAM_JPEG_CMD_HW_DUMP,
 	CAM_JPEG_CMD_GET_NUM_PID,
 	CAM_JPEG_CMD_MATCH_PID_MID,
+	CAM_JPEG_CMD_MINI_DUMP,
 	CAM_JPEG_CMD_MAX,
 };
 

+ 4 - 1
drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h

@@ -33,7 +33,10 @@ struct cam_jpeg_request_data {
 	uint32_t                            thumbnail_threshold_size;
 };
 
+typedef void (*cam_jpeg_mini_dump_cb)(void *priv, void *dst);
+
 int cam_jpeg_hw_mgr_init(struct device_node *of_node,
-	uint64_t *hw_mgr_hdl, int *iommu_hdl);
+	uint64_t *hw_mgr_hdl, int *iommu_hdl,
+	cam_jpeg_mini_dump_cb mini_dump_cb);
 
 #endif /* CAM_JPEG_HW_MGR_INTF_H */

+ 29 - 0
drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c

@@ -369,6 +369,32 @@ int cam_jpeg_dma_stop_hw(void *data,
 	return 0;
 }
 
+static int  cam_jpeg_dma_mini_dump(struct cam_hw_info *dev, void *args) {
+
+	struct cam_jpeg_mini_dump_core_info *md;
+	struct cam_jpeg_dma_device_hw_info   *hw_info;
+	struct cam_jpeg_dma_device_core_info *core_info;
+
+	if (!dev || !args) {
+		CAM_ERR(CAM_JPEG, "Invalid params dev %pK args %pK", dev, args);
+		return -EINVAL;
+	}
+
+	core_info = (struct cam_jpeg_dma_device_core_info *)dev->core_info;
+	hw_info = core_info->jpeg_dma_hw_info;
+	md = (struct cam_jpeg_mini_dump_core_info *)args;
+
+	md->framedone = hw_info->int_status.framedone;
+	md->resetdone = hw_info->int_status.resetdone;
+	md->iserror = hw_info->int_status.iserror;
+	md->stopdone = hw_info->int_status.stopdone;
+	md->open_count = dev->open_count;
+	md->hw_state = dev->hw_state;
+	md->ref_count = core_info->ref_count;
+	md->core_state = core_info->core_state;
+	return 0;
+}
+
 int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type,
 	void *cmd_args, uint32_t arg_size)
 {
@@ -456,6 +482,9 @@ int cam_jpeg_dma_process_cmd(void *device_priv, uint32_t cmd_type,
 				match_pid_mid->pid_match_found = false;
 		}
 
+		break;
+	case CAM_JPEG_CMD_MINI_DUMP:
+		rc = cam_jpeg_dma_mini_dump(jpeg_dma_dev, cmd_args);
 		break;
 	default:
 		rc = -EINVAL;

+ 31 - 0
drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c

@@ -496,6 +496,32 @@ int cam_jpeg_enc_hw_dump(
 	return 0;
 }
 
+static int  cam_jpeg_enc_mini_dump(struct cam_hw_info *dev, void *args) {
+
+	struct cam_jpeg_mini_dump_core_info *md;
+	struct cam_jpeg_enc_device_hw_info   *hw_info;
+	struct cam_jpeg_enc_device_core_info *core_info;
+
+	if (!dev || !args) {
+		CAM_ERR(CAM_JPEG, "Invalid params priv %pK args %pK", dev, args);
+		return -EINVAL;
+	}
+
+	core_info = (struct cam_jpeg_enc_device_core_info *)dev->core_info;
+	hw_info = core_info->jpeg_enc_hw_info;
+	md = (struct cam_jpeg_mini_dump_core_info *)args;
+
+	md->framedone = hw_info->int_status.framedone;
+	md->resetdone = hw_info->int_status.resetdone;
+	md->iserror = hw_info->int_status.iserror;
+	md->stopdone = hw_info->int_status.stopdone;
+	md->open_count = dev->open_count;
+	md->hw_state = dev->hw_state;
+	md->ref_count = core_info->ref_count;
+	md->core_state = core_info->core_state;
+	return 0;
+}
+
 int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type,
 	void *cmd_args, uint32_t arg_size)
 {
@@ -590,6 +616,11 @@ int cam_jpeg_enc_process_cmd(void *device_priv, uint32_t cmd_type,
 		}
 
 		break;
+	case CAM_JPEG_CMD_MINI_DUMP:
+	{
+		rc = cam_jpeg_enc_mini_dump(jpeg_enc_dev, cmd_args);
+		break;
+	}
 	default:
 		rc = -EINVAL;
 		break;