diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index 35b92d9073..e8301568d1 100644 --- a/drivers/cam_core/cam_context.c +++ b/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) { diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h index 0ddc84034e..a2673131a0 100644 --- a/drivers/cam_core/cam_context.h +++ b/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() * diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index b728f3b1af..c356ed838d 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/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; +} diff --git a/drivers/cam_core/cam_context_utils.h b/drivers/cam_core/cam_context_utils.h index 3fb8b56a8a..482c4ee746 100644 --- a/drivers/cam_core/cam_context_utils.h +++ b/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_ */ diff --git a/drivers/cam_core/cam_hw_mgr_intf.h b/drivers/cam_core/cam_hw_mgr_intf.h index 134e3bfb52..5d8a03f5c2 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/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 * diff --git a/drivers/cam_icp/cam_icp_context.c b/drivers/cam_icp/cam_icp_context.c index 1e01077b85..e291f92550 100644 --- a/drivers/cam_icp/cam_icp_context.c +++ b/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, }, }; diff --git a/drivers/cam_icp/cam_icp_subdev.c b/drivers/cam_icp/cam_icp_subdev.c index 5116e2fb0f..016217bfa8 100644 --- a/drivers/cam_icp/cam_icp_subdev.c +++ b/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; diff --git a/drivers/cam_icp/fw_inc/hfi_intf.h b/drivers/cam_icp/fw_inc/hfi_intf.h index e92700f633..9e60229378 100644 --- a/drivers/cam_icp/fw_inc/hfi_intf.h +++ b/drivers/cam_icp/fw_inc/hfi_intf.h @@ -8,6 +8,9 @@ #include +#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_ */ diff --git a/drivers/cam_icp/hfi.c b/drivers/cam_icp/hfi.c index c38e935baf..9ee6c28fad 100644 --- a/drivers/cam_icp/hfi.c +++ b/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; diff --git a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c b/drivers/cam_icp/icp_hw/a5_hw/a5_core.c index 9b49960f91..df6bc73170 100644 --- a/drivers/cam_icp/icp_hw/a5_hw/a5_core.c +++ b/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; } diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c index 8f334a38c9..e8bdc728c5 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c +++ b/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: diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h index 065a69f18f..0b07c674f4 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h +++ b/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); diff --git a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h b/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h index e7cede9fab..2a38d3a153 100644 --- a/drivers/cam_icp/icp_hw/icp_hw_mgr/include/cam_icp_hw_intf.h +++ b/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, }; diff --git a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h b/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h index c072069eec..f01cf0cd60 100644 --- a/drivers/cam_icp/icp_hw/include/cam_icp_hw_mgr_intf.h +++ b/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); diff --git a/drivers/cam_icp/icp_hw/lx7_hw/lx7_core.c b/drivers/cam_icp/icp_hw/lx7_hw/lx7_core.c index 993afbb3ad..d5218d8c42 100644 --- a/drivers/cam_icp/icp_hw/lx7_hw/lx7_core.c +++ b/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; diff --git a/drivers/cam_jpeg/cam_jpeg_context.c b/drivers/cam_jpeg/cam_jpeg_context.c index 31a0a85bc0..a4ff774ad1 100644 --- a/drivers/cam_jpeg/cam_jpeg_context.c +++ b/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 */ { diff --git a/drivers/cam_jpeg/cam_jpeg_dev.c b/drivers/cam_jpeg/cam_jpeg_dev.c index 1cb0bf148c..b4c2c31cf1 100644 --- a/drivers/cam_jpeg/cam_jpeg_dev.c +++ b/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; diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c index 0b12d530dd..6ab04f6562 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c +++ b/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: diff --git a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h b/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h index a8bded03c9..51a3723c06 100644 --- a/drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h +++ b/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 */ diff --git a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h index 0674bf5c4d..9a7a27036e 100644 --- a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_intf.h +++ b/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, }; diff --git a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h b/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h index 530bdfe7c4..bef99c5448 100644 --- a/drivers/cam_jpeg/jpeg_hw/include/cam_jpeg_hw_mgr_intf.h +++ b/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 */ diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c b/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c index a90d501677..9f29c8fe83 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_dma_hw/jpeg_dma_core.c +++ b/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; diff --git a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c b/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c index a0000a7754..be0a4f79d9 100644 --- a/drivers/cam_jpeg/jpeg_hw/jpeg_enc_hw/jpeg_enc_core.c +++ b/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;