Przeglądaj źródła

msm: camera: req_mgr: LDAR Debug framework implementation

When user space detects an error or does not receive
response for a request, Lets do a reset(LDAR) is triggered.
Before LDAR, user space sends flush command to the
kernel space.
To debug the cause for this situation and to dump
the information, user space sends a dump command to the
kernel space before sending flush.
As a part of this command, it passes the culprit request id
and the buffer into which the information can be dumped.
Kernel space traverses across the drivers and find the culprit hw
and dumps the relevant information in the buffer.
This data is written to a file for offline processing.
This commit implements the framework for traversal
across the RT and NRT devices.

CRs-Fixed: 2602180
Change-Id: I7e24006c20c23bfab163a2ad13b4ac6e2913bb9e
Signed-off-by: Gaurav Jindal <[email protected]>
Gaurav Jindal 5 lat temu
rodzic
commit
d95d140d40

+ 65 - 0
drivers/cam_core/cam_context.c

@@ -230,6 +230,34 @@ int cam_context_handle_crm_process_evt(struct cam_context *ctx,
 	return rc;
 }
 
+int cam_context_handle_crm_dump_req(struct cam_context *ctx,
+	struct cam_req_mgr_dump_info *dump)
+{
+	int rc = 0;
+
+	if (!ctx) {
+		CAM_ERR(CAM_CORE, "Invalid Context");
+		return -EINVAL;
+	}
+	if (!ctx->state_machine) {
+		CAM_ERR(CAM_CORE, "Context %s ctx_id %d is not ready",
+			ctx->dev_name, ctx->ctx_id);
+		return -EINVAL;
+	}
+	mutex_lock(&ctx->ctx_mutex);
+
+	if (ctx->state_machine[ctx->state].crm_ops.dump_req)
+		rc = ctx->state_machine[ctx->state].crm_ops.dump_req(ctx,
+			dump);
+	else
+		CAM_ERR(CAM_CORE, "No crm dump req for %s dev %d, state %d",
+			ctx->dev_name, ctx->dev_hdl, ctx->state);
+
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
 int cam_context_dump_pf_info(struct cam_context *ctx, unsigned long iova,
 	uint32_t buf_info)
 {
@@ -524,6 +552,43 @@ int cam_context_handle_info_dump(void *context,
 	return rc;
 }
 
+int cam_context_handle_dump_dev(struct cam_context *ctx,
+	struct cam_dump_req_cmd *cmd)
+{
+	int rc = 0;
+
+	if (!ctx) {
+		CAM_ERR(CAM_CORE, "Invalid Context");
+		return -EINVAL;
+	}
+
+	if (!ctx->state_machine) {
+		CAM_ERR(CAM_CORE, "Context %s ctx_id %d is not ready",
+			ctx->dev_name, ctx->ctx_id);
+		return -EINVAL;
+	}
+
+	if (!cmd) {
+		CAM_ERR(CAM_CORE,
+			"Context %s ctx_id %d Invalid dump command payload",
+			ctx->dev_name, ctx->ctx_id);
+		return -EINVAL;
+	}
+
+	mutex_lock(&ctx->ctx_mutex);
+	CAM_DBG(CAM_CORE, "dump device in dev %d, name %s state %d",
+		ctx->dev_hdl, ctx->dev_name, ctx->state);
+	if (ctx->state_machine[ctx->state].ioctl_ops.dump_dev)
+		rc = ctx->state_machine[ctx->state].ioctl_ops.dump_dev(
+			ctx, cmd);
+	else
+		CAM_WARN(CAM_CORE, "No dump device in dev %d, name %s state %d",
+			ctx->dev_hdl, ctx->dev_name, ctx->state);
+	mutex_unlock(&ctx->ctx_mutex);
+
+	return rc;
+}
+
 int cam_context_init(struct cam_context *ctx,
 	const char *dev_name,
 	uint64_t dev_id,

+ 49 - 0
drivers/cam_core/cam_context.h

@@ -23,6 +23,12 @@ struct cam_context;
 #define CAM_CTX_CFG_MAX              20
 #define CAM_CTX_RES_MAX              20
 
+/* max tag  dump header string length*/
+#define CAM_CTXT_DUMP_TAG_MAX_LEN 32
+
+/* Number of words to be dumped for context*/
+#define CAM_CTXT_DUMP_NUM_WORDS 10
+
 /**
  * enum cam_ctx_state -  context top level states
  *
@@ -86,6 +92,7 @@ struct cam_ctx_request {
  * @flush_dev:             Function pointer for flush device
  * @acquire_hw:            Function pointer for acquire hw
  * @release_hw:            Function pointer for release hw
+ * @dump_dev:              Function pointer for dump dev
  *
  */
 struct cam_ctx_ioctl_ops {
@@ -103,6 +110,8 @@ struct cam_ctx_ioctl_ops {
 			struct cam_flush_dev_cmd *cmd);
 	int (*acquire_hw)(struct cam_context *ctx, void *args);
 	int (*release_hw)(struct cam_context *ctx, void *args);
+	int (*dump_dev)(struct cam_context *ctx,
+			struct cam_dump_req_cmd *cmd);
 };
 
 /**
@@ -114,6 +123,7 @@ struct cam_ctx_ioctl_ops {
  * @apply_req:             Apply setting for the context
  * @flush_req:             Flush request to remove request ids
  * @process_evt:           Handle event notification from CRM.(optional)
+ * @dump_req:              Dump information for the issue request
  *
  */
 struct cam_ctx_crm_ops {
@@ -129,6 +139,8 @@ struct cam_ctx_crm_ops {
 			struct cam_req_mgr_flush_request *flush);
 	int (*process_evt)(struct cam_context *ctx,
 			struct cam_req_mgr_link_evt_data *evt_data);
+	int (*dump_req)(struct cam_context *ctx,
+			struct cam_req_mgr_dump_info *dump);
 };
 
 
@@ -219,6 +231,19 @@ struct cam_context {
 	uint32_t                     last_flush_req;
 };
 
+/**
+ * struct cam_context_dump_header -  Function for context dump header
+ *
+ * @tag         :    Tag for context dump header
+ * @size        :    Size of data
+ * @word_size   :    Word size of data
+ */
+struct cam_context_dump_header {
+	uint8_t   tag[CAM_CTXT_DUMP_TAG_MAX_LEN];
+	uint64_t  size;
+	uint32_t  word_size;
+};
+
 /**
  * cam_context_shutdown()
  *
@@ -301,6 +326,18 @@ int cam_context_handle_crm_flush_req(struct cam_context *ctx,
 int cam_context_handle_crm_process_evt(struct cam_context *ctx,
 	struct cam_req_mgr_link_evt_data *process_evt);
 
+/**
+ * cam_context_handle_crm_dump_req()
+ *
+ * @brief:        Handle CRM dump request
+ *
+ * @ctx:          Object pointer for cam_context
+ * @dump:         Dump request command payload
+ *
+ */
+int cam_context_handle_crm_dump_req(struct cam_context *ctx,
+	struct cam_req_mgr_dump_info *dump);
+
 /**
  * cam_context_dump_pf_info()
  *
@@ -410,6 +447,18 @@ int cam_context_handle_start_dev(struct cam_context *ctx,
 int cam_context_handle_stop_dev(struct cam_context *ctx,
 		struct cam_start_stop_dev_cmd *cmd);
 
+/**
+ * cam_context_handle_dump_dev()
+ *
+ * @brief:        Handle dump device command
+ *
+ * @ctx:          Object pointer for cam_context
+ * @cmd:          Dump device command payload
+ *
+ */
+int cam_context_handle_dump_dev(struct cam_context *ctx,
+	struct cam_dump_req_cmd *cmd);
+
 /**
  * cam_context_handle_info_dump()
  *

+ 127 - 0
drivers/cam_core/cam_context_utils.c

@@ -1046,3 +1046,130 @@ int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx)
 end:
 	return rc;
 }
+
+static int cam_context_dump_context(struct cam_context *ctx,
+	struct cam_hw_dump_args *dump_args)
+{
+	int                             rc;
+	int                             i;
+	size_t                          buf_len;
+	size_t                          remain_len;
+	uint8_t                        *dst;
+	uint64_t                       *addr, *start;
+	uint32_t                        min_len;
+	uintptr_t                       cpu_addr;
+	struct cam_ctx_request         *req;
+	struct cam_context_dump_header *hdr;
+
+	if (!ctx || !dump_args) {
+		CAM_ERR(CAM_CORE, "Invalid parameters %pK %pK",
+			ctx, dump_args);
+		return -EINVAL;
+	}
+
+	spin_lock_bh(&ctx->lock);
+	if (list_empty(&ctx->active_req_list)) {
+		CAM_ERR(CAM_CTXT, "[%s][%d] no active request",
+			ctx->dev_name, ctx->ctx_id);
+		spin_unlock_bh(&ctx->lock);
+		return -EIO;
+	}
+	req = list_first_entry(&ctx->active_req_list,
+		struct cam_ctx_request, list);
+	spin_unlock_bh(&ctx->lock);
+	rc  = cam_mem_get_cpu_buf(dump_args->buf_handle,
+		&cpu_addr, &buf_len);
+	if (rc) {
+		CAM_ERR(CAM_CTXT, "Invalid hdl %u rc %d",
+			dump_args->buf_handle, rc);
+		return rc;
+	}
+	if (dump_args->offset >= buf_len) {
+		CAM_WARN(CAM_CTXT, "dump buffer overshoot offset %zu len %zu",
+			dump_args->offset, buf_len);
+		return -ENOSPC;
+	}
+
+	remain_len = buf_len - dump_args->offset;
+	min_len =  sizeof(struct cam_context_dump_header) +
+		    (CAM_CTXT_DUMP_NUM_WORDS + req->num_in_map_entries +
+		    (req->num_out_map_entries * 2)) * sizeof(uint64_t);
+
+	if (remain_len < min_len) {
+		CAM_WARN(CAM_CTXT, "dump buffer exhaust remain %zu min %u",
+			remain_len, min_len);
+		return -ENOSPC;
+	}
+	dst = (uint8_t *)cpu_addr + dump_args->offset;
+	hdr = (struct cam_context_dump_header *)dst;
+	scnprintf(hdr->tag, CAM_CTXT_DUMP_TAG_MAX_LEN,
+		"%s_CTXT_DUMP:", ctx->dev_name);
+	hdr->word_size = sizeof(uint64_t);
+	addr = (uint64_t *)(dst + sizeof(struct cam_context_dump_header));
+	start = addr;
+	*addr++ = ctx->ctx_id;
+	*addr++ = refcount_read(&(ctx->refcount.refcount));
+	*addr++ = ctx->last_flush_req;
+	*addr++ = ctx->state;
+	*addr++ = req->num_out_map_entries;
+	for (i = 0; i < req->num_out_map_entries; i++) {
+		*addr++ = req->out_map_entries[i].resource_handle;
+		*addr++ = req->out_map_entries[i].sync_id;
+	}
+	*addr++ = req->num_in_map_entries;
+	for (i = 0; i < req->num_in_map_entries; i++)
+		*addr++ = req->in_map_entries[i].sync_id;
+	hdr->size = hdr->word_size * (addr - start);
+	dump_args->offset += hdr->size +
+		sizeof(struct cam_context_dump_header);
+	return rc;
+}
+
+int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx,
+	struct cam_dump_req_cmd *cmd)
+{
+	int                     rc = 0;
+	struct cam_hw_dump_args dump_args;
+
+	if (!ctx || !cmd) {
+		CAM_ERR(CAM_CTXT, "Invalid input params %pK %pK", ctx, cmd);
+		return -EINVAL;
+	}
+	if (!ctx->hw_mgr_intf) {
+		CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready",
+			ctx->dev_name, ctx->ctx_id);
+		return -EFAULT;
+	}
+	memset(&dump_args, 0, sizeof(dump_args));
+	if (ctx->hw_mgr_intf->hw_dump) {
+		dump_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map;
+		dump_args.buf_handle = cmd->buf_handle;
+		dump_args.offset = cmd->offset;
+		dump_args.request_id = cmd->issue_req_id;
+		dump_args.error_type = cmd->error_type;
+		rc  = ctx->hw_mgr_intf->hw_dump(
+			ctx->hw_mgr_intf->hw_mgr_priv,
+			&dump_args);
+		if (rc) {
+			CAM_ERR(CAM_CTXT, "[%s][%d] handle[%u] failed",
+			    ctx->dev_name, ctx->ctx_id, dump_args.buf_handle);
+			return rc;
+		}
+		/* Offset will change if the issue request id is found with
+		 * the hw and has been lying with it beyond threshold time.
+		 * If offset does not change, do not dump the context
+		 * information as the current context has no problem with
+		 * the provided request id.
+		 */
+		if (dump_args.offset > cmd->offset) {
+			cam_context_dump_context(ctx, &dump_args);
+			CAM_INFO(CAM_CTXT, "[%s] ctx: %d Filled Length %u",
+				 ctx->dev_name, ctx->ctx_id,
+				 dump_args.offset - cmd->offset);
+			cmd->offset  = dump_args.offset;
+		}
+	} else {
+		CAM_DBG(CAM_CTXT, "%s hw dump not registered", ctx->dev_name);
+	}
+	return rc;
+}

+ 2 - 1
drivers/cam_core/cam_context_utils.h

@@ -30,5 +30,6 @@ int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx,
 	struct cam_packet *packet, unsigned long iova, uint32_t buf_info,
 	bool *mem_found);
 int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx);
-
+int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx,
+	struct cam_dump_req_cmd *cmd);
 #endif /* _CAM_CONTEXT_UTILS_H_ */

+ 19 - 0
drivers/cam_core/cam_hw_mgr_intf.h

@@ -300,6 +300,23 @@ struct cam_hw_reset_args {
 	void                           *ctxt_to_hw_map;
 };
 
+/**
+ * struct cam_hw_dump_args - Dump arguments
+ *
+ * @request_id:            request_id
+ * @offset:                Buffer offset. This is updated by the drivers.
+ * @buf_handle:            Buffer handle
+ * @error_type:            Error type, to be used to extend dump information
+ * @ctxt_to_hw_map:        HW context from the acquire
+ */
+struct cam_hw_dump_args {
+	uint64_t          request_id;
+	size_t            offset;
+	uint32_t          buf_handle;
+	uint32_t          error_type;
+	void             *ctxt_to_hw_map;
+};
+
 /* enum cam_hw_mgr_command - Hardware manager command type */
 enum cam_hw_mgr_command {
 	CAM_HW_MGR_CMD_INTERNAL,
@@ -355,6 +372,7 @@ struct cam_hw_cmd_args {
  * @hw_close:                  Function pointer for HW deinit
  * @hw_flush:                  Function pointer for HW flush
  * @hw_reset:                  Function pointer for HW reset
+ * @hw_dump:                   Function pointer for HW dump
  *
  */
 struct cam_hw_mgr_intf {
@@ -376,6 +394,7 @@ struct cam_hw_mgr_intf {
 	int (*hw_close)(void *hw_priv, void *hw_close_args);
 	int (*hw_flush)(void *hw_priv, void *hw_flush_args);
 	int (*hw_reset)(void *hw_priv, void *hw_reset_args);
+	int (*hw_dump)(void *hw_priv, void *hw_dump_args);
 };
 
 #endif /* _CAM_HW_MGR_INTF_H_ */

+ 77 - 0
drivers/cam_core/cam_node.c

@@ -435,6 +435,39 @@ destroy_dev_hdl:
 	return rc;
 }
 
+static int __cam_node_handle_dump_dev(struct cam_node *node,
+	struct cam_dump_req_cmd *dump)
+{
+	int                 rc;
+	struct cam_context *ctx = NULL;
+
+	if (!dump)
+		return -EINVAL;
+
+	if (dump->dev_handle <= 0) {
+		CAM_ERR(CAM_CORE, "Invalid device handle for context");
+		return -EINVAL;
+	}
+
+	if (dump->session_handle <= 0) {
+		CAM_ERR(CAM_CORE, "Invalid session handle for context");
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *)cam_get_device_priv(dump->dev_handle);
+	if (!ctx) {
+		CAM_ERR(CAM_CORE, "Can not get context for handle %d",
+			dump->dev_handle);
+		return -EINVAL;
+	}
+
+	rc = cam_context_handle_dump_dev(ctx, dump);
+	if (rc)
+		CAM_ERR(CAM_CORE, "Dump failure for node %s", node->name);
+
+	return rc;
+}
+
 static int __cam_node_handle_release_hw_v1(struct cam_node *node,
 	struct cam_release_hw_cmd_v1 *release)
 {
@@ -575,6 +608,25 @@ static int __cam_node_crm_process_evt(
 	return cam_context_handle_crm_process_evt(ctx, evt_data);
 }
 
+static int __cam_node_crm_dump_req(struct cam_req_mgr_dump_info *dump)
+{
+	struct cam_context *ctx = NULL;
+
+	if (!dump) {
+		CAM_ERR(CAM_CORE, "Invalid dump request payload");
+		return -EINVAL;
+	}
+
+	ctx = (struct cam_context *) cam_get_device_priv(dump->dev_hdl);
+	if (!ctx) {
+		CAM_ERR(CAM_CORE, "Can not get context for handle %d",
+			dump->dev_hdl);
+		return -EINVAL;
+	}
+
+	return cam_context_handle_crm_dump_req(ctx, dump);
+}
+
 int cam_node_deinit(struct cam_node *node)
 {
 	if (node)
@@ -630,6 +682,7 @@ int cam_node_init(struct cam_node *node, struct cam_hw_mgr_intf *hw_mgr_intf,
 	node->crm_node_intf.link_setup = __cam_node_crm_link_setup;
 	node->crm_node_intf.flush_req = __cam_node_crm_flush_req;
 	node->crm_node_intf.process_evt = __cam_node_crm_process_evt;
+	node->crm_node_intf.dump_req = __cam_node_crm_dump_req;
 
 	mutex_init(&node->list_mutex);
 	INIT_LIST_HEAD(&node->free_ctx_list);
@@ -877,6 +930,30 @@ release_kfree:
 		}
 		break;
 	}
+	case CAM_DUMP_REQ: {
+		struct cam_dump_req_cmd dump;
+
+		if (copy_from_user(&dump, u64_to_user_ptr(cmd->handle),
+			sizeof(dump))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = __cam_node_handle_dump_dev(node, &dump);
+		if (rc) {
+			CAM_ERR(CAM_CORE,
+			    "Dump device %s failed(rc = %d) ",
+			    node->name, rc);
+			break;
+		}
+		if (copy_to_user(u64_to_user_ptr(cmd->handle),
+			&dump, sizeof(dump))) {
+			CAM_ERR(CAM_CORE,
+			    "Dump device %s copy_to_user fail",
+			    node->name);
+			rc = -EFAULT;
+		}
+		break;
+	}
 	default:
 		CAM_ERR(CAM_CORE, "Unknown op code %d", cmd->op_code);
 		rc = -EINVAL;

+ 60 - 0
drivers/cam_req_mgr/cam_req_mgr_core.c

@@ -3863,6 +3863,66 @@ end:
 	return rc;
 }
 
+int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req)
+{
+	int                                  rc = 0;
+	int                                  i;
+	struct cam_req_mgr_dump_info         info;
+	struct cam_req_mgr_core_link        *link = NULL;
+	struct cam_req_mgr_core_session     *session = NULL;
+	struct cam_req_mgr_connected_device *device = NULL;
+
+	if (!dump_req) {
+		CAM_ERR(CAM_CRM, "dump req is NULL");
+		return -EFAULT;
+	}
+
+	mutex_lock(&g_crm_core_dev->crm_lock);
+	/* session hdl's priv data is cam session struct */
+	session = (struct cam_req_mgr_core_session *)
+	    cam_get_device_priv(dump_req->session_handle);
+	if (!session) {
+		CAM_ERR(CAM_CRM, "Invalid session %x",
+			dump_req->session_handle);
+		rc = -EINVAL;
+		goto end;
+	}
+	if (session->num_links <= 0) {
+		CAM_WARN(CAM_CRM, "No active links in session %x",
+			dump_req->session_handle);
+		goto end;
+	}
+
+	link = (struct cam_req_mgr_core_link *)
+		cam_get_device_priv(dump_req->link_hdl);
+	if (!link) {
+		CAM_DBG(CAM_CRM, "link ptr NULL %x", dump_req->link_hdl);
+		rc = -EINVAL;
+		goto end;
+	}
+	info.offset = dump_req->offset;
+	for (i = 0; i < link->num_devs; i++) {
+		device = &link->l_dev[i];
+		info.link_hdl = dump_req->link_hdl;
+		info.dev_hdl = device->dev_hdl;
+		info.req_id = dump_req->issue_req_id;
+		info.buf_handle = dump_req->buf_handle;
+		info.error_type = dump_req->error_type;
+		if (device->ops && device->ops->dump_req) {
+			rc = device->ops->dump_req(&info);
+			if (rc)
+				CAM_ERR(CAM_REQ,
+					"Fail dump req %llu dev %d rc %d",
+					info.req_id, device->dev_hdl, rc);
+		}
+	}
+	dump_req->offset = info.offset;
+	CAM_INFO(CAM_REQ, "req %llu, offset %zu",
+		dump_req->issue_req_id, dump_req->offset);
+end:
+	mutex_unlock(&g_crm_core_dev->crm_lock);
+	return 0;
+}
 
 int cam_req_mgr_core_device_init(void)
 {

+ 6 - 0
drivers/cam_req_mgr/cam_req_mgr_core.h

@@ -505,4 +505,10 @@ void cam_req_mgr_handle_core_shutdown(void);
  */
 int cam_req_mgr_link_control(struct cam_req_mgr_link_control *control);
 
+/**
+ * cam_req_mgr_dump_request()
+ * @brief:   Dumps the request information
+ * @dump_req: Dump request
+ */
+int cam_req_mgr_dump_request(struct cam_dump_req_cmd *dump_req);
 #endif

+ 24 - 0
drivers/cam_req_mgr/cam_req_mgr_dev.c

@@ -523,6 +523,30 @@ static long cam_private_ioctl(struct file *file, void *fh,
 			rc = -EINVAL;
 		}
 		break;
+	case CAM_REQ_MGR_REQUEST_DUMP: {
+		struct cam_dump_req_cmd cmd;
+
+		if (k_ioctl->size != sizeof(cmd))
+			return -EINVAL;
+
+		if (copy_from_user(&cmd,
+			u64_to_user_ptr(k_ioctl->handle),
+			sizeof(struct cam_dump_req_cmd))) {
+			rc = -EFAULT;
+			break;
+		}
+		rc = cam_req_mgr_dump_request(&cmd);
+		if (rc) {
+			CAM_ERR(CAM_CORE, "dump fail for dev %d req %llu rc %d",
+				cmd.dev_handle, cmd.issue_req_id, rc);
+			break;
+		}
+		if (copy_to_user(
+			u64_to_user_ptr(k_ioctl->handle),
+			&cmd, sizeof(struct cam_dump_req_cmd)))
+			rc = -EFAULT;
+		}
+		break;
 	default:
 		return -ENOIOCTLCMD;
 	}

+ 24 - 0
drivers/cam_req_mgr/cam_req_mgr_interface.h

@@ -21,6 +21,7 @@ struct cam_req_mgr_core_dev_link_setup;
 struct cam_req_mgr_apply_request;
 struct cam_req_mgr_flush_request;
 struct cam_req_mgr_link_evt_data;
+struct cam_req_mgr_dump_info;
 
 #define SKIP_NEXT_FRAME 0x100
 
@@ -49,6 +50,7 @@ typedef int (*cam_req_mgr_notify_stop)(struct cam_req_mgr_notify_stop *);
  * @cam_req_mgr_apply_req   : CRM asks device to apply certain request id.
  * @cam_req_mgr_flush_req   : Flush or cancel request
  * cam_req_mgr_process_evt  : generic events
+ * @cam_req_mgr_dump_req    : dump request
  */
 typedef int (*cam_req_mgr_get_dev_info) (struct cam_req_mgr_device_info *);
 typedef int (*cam_req_mgr_link_setup)(
@@ -56,6 +58,7 @@ typedef int (*cam_req_mgr_link_setup)(
 typedef int (*cam_req_mgr_apply_req)(struct cam_req_mgr_apply_request *);
 typedef int (*cam_req_mgr_flush_req)(struct cam_req_mgr_flush_request *);
 typedef int (*cam_req_mgr_process_evt)(struct cam_req_mgr_link_evt_data *);
+typedef int (*cam_req_mgr_dump_req)(struct cam_req_mgr_dump_info *);
 
 /**
  * @brief          : cam_req_mgr_crm_cb - func table
@@ -81,6 +84,7 @@ struct cam_req_mgr_crm_cb {
  * @apply_req    : payload to apply request id on a device linked
  * @flush_req    : payload to flush request
  * @process_evt  : payload to generic event
+ * @dump_req     : payload to dump request
  */
 struct cam_req_mgr_kmd_ops {
 	cam_req_mgr_get_dev_info     get_dev_info;
@@ -88,6 +92,7 @@ struct cam_req_mgr_kmd_ops {
 	cam_req_mgr_apply_req        apply_req;
 	cam_req_mgr_flush_req        flush_req;
 	cam_req_mgr_process_evt      process_evt;
+	cam_req_mgr_dump_req         dump_req;
 };
 
 /**
@@ -372,4 +377,23 @@ struct cam_req_mgr_send_request {
 	int32_t    link_hdl;
 	struct cam_req_mgr_req_queue *in_q;
 };
+
+/**
+ * struct cam_req_mgr_dump_info
+ * @req_id      : request id to dump
+ * @offset      : offset of buffer
+ * @error_type  : error type
+ * @buf_handle  : buf handle
+ * @link_hdl    : link identifier
+ * @dev_hdl     : device handle for cross check
+ *
+ */
+struct cam_req_mgr_dump_info {
+	uint64_t    req_id;
+	size_t      offset;
+	uint32_t    error_type;
+	uint32_t    buf_handle;
+	int32_t     link_hdl;
+	int32_t     dev_hdl;
+};
 #endif

+ 22 - 0
include/uapi/camera/media/cam_defs.h

@@ -26,6 +26,7 @@
 #define CAM_COMMON_OPCODE_BASE_v2           0x150
 #define CAM_ACQUIRE_HW                      (CAM_COMMON_OPCODE_BASE_v2 + 0x1)
 #define CAM_RELEASE_HW                      (CAM_COMMON_OPCODE_BASE_v2 + 0x2)
+#define CAM_DUMP_REQ                        (CAM_COMMON_OPCODE_BASE_v2 + 0x3)
 
 #define CAM_EXT_OPCODE_BASE                     0x200
 #define CAM_CONFIG_DEV_EXTERNAL                 (CAM_EXT_OPCODE_BASE + 0x1)
@@ -868,5 +869,26 @@ struct cam_reg_dump_input_info {
 	uint32_t                   dump_set_offsets[1];
 };
 
+/**
+ * struct cam_dump_req_cmd -
+ *        Dump the information of issue req id
+ *
+ * @issue_req_id   : Issue Request Id
+ * @offset         : Offset for the buffer
+ * @buf_handle     : Buffer Handle
+ * @error_type     : Error type, using it, dumping information can be extended
+ * @session_handle : Session Handle
+ * @link_hdl       : link handle
+ * @dev_handle     : Device Handle
+ */
+struct cam_dump_req_cmd {
+	uint64_t       issue_req_id;
+	size_t         offset;
+	uint32_t       buf_handle;
+	uint32_t       error_type;
+	int32_t        session_handle;
+	int32_t        link_hdl;
+	int32_t        dev_handle;
+};
 
 #endif /* __UAPI_CAM_DEFS_H__ */

+ 2 - 0
include/uapi/camera/media/cam_req_mgr.h

@@ -262,6 +262,8 @@ struct cam_req_mgr_link_control {
 #define CAM_REQ_MGR_CACHE_OPS                   (CAM_COMMON_OPCODE_MAX + 12)
 #define CAM_REQ_MGR_LINK_CONTROL                (CAM_COMMON_OPCODE_MAX + 13)
 #define CAM_REQ_MGR_LINK_V2                     (CAM_COMMON_OPCODE_MAX + 14)
+#define CAM_REQ_MGR_REQUEST_DUMP                (CAM_COMMON_OPCODE_MAX + 15)
+
 /* end of cam_req_mgr opcodes */
 
 #define CAM_MEM_FLAG_HW_READ_WRITE              (1<<0)