diff --git a/drivers/cam_core/cam_context.c b/drivers/cam_core/cam_context.c index d2ec399e2895..5e42f02dd9ad 100644 --- a/drivers/cam_core/cam_context.c +++ b/drivers/cam_core/cam_context.c @@ -493,6 +493,31 @@ int cam_context_handle_stop_dev(struct cam_context *ctx, return rc; } +int cam_context_handle_info_dump(void *context, + enum cam_context_dump_id id) +{ + int rc = 0; + struct cam_context *ctx = (struct cam_context *)context; + + if (!ctx || !ctx->state_machine) { + CAM_ERR(CAM_CORE, "Context is not ready"); + return -EINVAL; + } + + mutex_lock(&ctx->ctx_mutex); + if (ctx->state_machine[ctx->state].dumpinfo_ops) + rc = ctx->state_machine[ctx->state].dumpinfo_ops(ctx, + id); + mutex_unlock(&ctx->ctx_mutex); + + if (rc) + CAM_WARN(CAM_CORE, + "Dump for id %u failed on ctx_id %u name %s state %d", + id, ctx->ctx_id, ctx->dev_name, ctx->state); + + return rc; +} + int cam_context_init(struct cam_context *ctx, const char *dev_name, uint64_t dev_id, diff --git a/drivers/cam_core/cam_context.h b/drivers/cam_core/cam_context.h index 1583dd06df3f..854ea0067a27 100644 --- a/drivers/cam_core/cam_context.h +++ b/drivers/cam_core/cam_context.h @@ -138,6 +138,8 @@ struct cam_ctx_crm_ops { * @crm_ops: CRM to context interface function table * @irq_ops: Hardware event handle function * @pagefault_ops: Function to be called on page fault + * @dumpinfo_ops: Function to be invoked for dumping any + * context info * */ struct cam_ctx_ops { @@ -145,6 +147,7 @@ struct cam_ctx_ops { struct cam_ctx_crm_ops crm_ops; cam_hw_event_cb_func irq_ops; cam_hw_pagefault_cb_func pagefault_ops; + cam_ctx_info_dump_cb_func dumpinfo_ops; }; /** @@ -406,6 +409,19 @@ 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_info_dump() + * + * @brief: Handle any dump info for the context + * + * @ctx: Object pointer for cam_context + * @id: To indicate which info pertaining + * to that ctx needs to be dumped + * + */ +int cam_context_handle_info_dump(void *context, + enum cam_context_dump_id id); + /** * cam_context_deinit() * diff --git a/drivers/cam_core/cam_context_utils.c b/drivers/cam_core/cam_context_utils.c index 34dc7b81d454..5ec9c6cdc7b1 100644 --- a/drivers/cam_core/cam_context_utils.c +++ b/drivers/cam_core/cam_context_utils.c @@ -1016,3 +1016,32 @@ int32_t cam_context_dump_pf_info_to_hw(struct cam_context *ctx, end: return rc; } + +int32_t cam_context_dump_hw_acq_info(struct cam_context *ctx) +{ + int rc = 0; + struct cam_hw_cmd_args cmd_args; + + if (!ctx) { + CAM_ERR(CAM_CTXT, "Invalid input params"); + rc = -EINVAL; + goto end; + } + + if (!ctx->hw_mgr_intf) { + CAM_ERR(CAM_CTXT, "[%s][%d] HW interface is not ready", + ctx->dev_name, ctx->ctx_id); + rc = -EFAULT; + goto end; + } + + if (ctx->hw_mgr_intf->hw_cmd) { + cmd_args.ctxt_to_hw_map = ctx->ctxt_to_hw_map; + cmd_args.cmd_type = CAM_HW_MGR_CMD_DUMP_ACQ_INFO; + ctx->hw_mgr_intf->hw_cmd(ctx->hw_mgr_intf->hw_mgr_priv, + &cmd_args); + } + +end: + return rc; +} diff --git a/drivers/cam_core/cam_context_utils.h b/drivers/cam_core/cam_context_utils.h index c3483327ba81..087fdbf36544 100644 --- a/drivers/cam_core/cam_context_utils.h +++ b/drivers/cam_core/cam_context_utils.h @@ -1,6 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ /* - * Copyright (c) 2017-2018, The Linux Foundation. All rights reserved. + * Copyright (c) 2017-2019, The Linux Foundation. All rights reserved. */ #ifndef _CAM_CONTEXT_UTILS_H_ @@ -29,5 +29,6 @@ int32_t cam_context_flush_req_to_hw(struct cam_context *ctx, 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); #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 b7b6ae1bb6b7..462b30119b50 100644 --- a/drivers/cam_core/cam_hw_mgr_intf.h +++ b/drivers/cam_core/cam_hw_mgr_intf.h @@ -24,6 +24,17 @@ /* Maximum reg dump cmd buffer entries in a context */ #define CAM_REG_DUMP_MAX_BUF_ENTRIES 10 +/** + * enum cam_context_dump_id - + * context dump type + * + */ +enum cam_context_dump_id { + CAM_CTX_DUMP_TYPE_NONE, + CAM_CTX_DUMP_ACQ_INFO, + CAM_CTX_DUMP_TYPE_MAX, +}; + /* hardware event callback function type */ typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id, void *evt_data); @@ -32,6 +43,10 @@ typedef int (*cam_hw_event_cb_func)(void *context, uint32_t evt_id, typedef int (*cam_hw_pagefault_cb_func)(void *context, unsigned long iova, uint32_t buf_info); +/* ctx dump callback function type */ +typedef int (*cam_ctx_info_dump_cb_func)(void *context, + enum cam_context_dump_id dump_id); + /** * struct cam_hw_update_entry - Entry for hardware config * @@ -276,6 +291,7 @@ enum cam_hw_mgr_command { CAM_HW_MGR_CMD_DUMP_PF_INFO, CAM_HW_MGR_CMD_REG_DUMP_ON_FLUSH, CAM_HW_MGR_CMD_REG_DUMP_ON_ERROR, + CAM_HW_MGR_CMD_DUMP_ACQ_INFO, }; /** diff --git a/drivers/cam_core/cam_node.c b/drivers/cam_core/cam_node.c index 9c4c6f242336..4fefa2f35db3 100644 --- a/drivers/cam_core/cam_node.c +++ b/drivers/cam_core/cam_node.c @@ -122,6 +122,16 @@ err: return rc; } +static void __cam_node_handle_acquired_hw_dump( + struct cam_node *node) +{ + int i; + + for (i = 0; i < node->ctx_size; i++) + cam_context_handle_info_dump(&(node->ctx_list[i]), + CAM_CTX_DUMP_ACQ_INFO); +} + static int __cam_node_handle_acquire_hw_v1(struct cam_node *node, struct cam_acquire_hw_cmd_v1 *acquire) { @@ -158,6 +168,7 @@ static int __cam_node_handle_acquire_hw_v1(struct cam_node *node, if (rc) { CAM_ERR(CAM_CORE, "Acquire device failed for node %s", node->name); + __cam_node_handle_acquired_hw_dump(node); return rc; } @@ -197,6 +208,7 @@ static int __cam_node_handle_acquire_hw_v2(struct cam_node *node, if (rc) { CAM_ERR(CAM_CORE, "Acquire device failed for node %s", node->name); + __cam_node_handle_acquired_hw_dump(node); return rc; } @@ -734,7 +746,6 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) "acquire device failed(rc = %d)", rc); goto acquire_kfree; } - CAM_INFO(CAM_CORE, "Acquire HW successful"); } else if (api_version == 2) { rc = __cam_node_handle_acquire_hw_v2(node, acquire_ptr); if (rc) { @@ -742,7 +753,6 @@ int cam_node_handle_ioctl(struct cam_node *node, struct cam_control *cmd) "acquire device failed(rc = %d)", rc); goto acquire_kfree; } - CAM_INFO(CAM_CORE, "Acquire HW successful"); } if (copy_to_user((void __user *)cmd->handle, acquire_ptr, @@ -849,8 +859,6 @@ acquire_kfree: "release device failed(rc = %d)", rc); } - CAM_INFO(CAM_CORE, "Release HW done(rc = %d)", rc); - release_kfree: kfree(release_ptr); break; diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index c51b8e4a2e5e..46dfeb1915ca 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -139,6 +139,24 @@ static void __cam_isp_ctx_dump_state_monitor_array( } } +static int cam_isp_context_info_dump(void *context, + enum cam_context_dump_id id) +{ + struct cam_context *ctx = (struct cam_context *)context; + + switch (id) { + case CAM_CTX_DUMP_ACQ_INFO: { + cam_context_dump_hw_acq_info(ctx); + break; + } + default: + CAM_DBG(CAM_ISP, "DUMP id not valid %u", id); + break; + } + + return 0; +} + static void cam_isp_ctx_dump_req(struct cam_isp_ctx_req *req_isp) { int i = 0, rc = 0; @@ -3365,7 +3383,6 @@ end: return rc; } - static int __cam_isp_ctx_acquire_hw_in_acquired(struct cam_context *ctx, void *args) { @@ -3904,6 +3921,7 @@ static struct cam_ctx_ops }, .irq_ops = NULL, .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, }, /* Ready */ { @@ -3919,6 +3937,7 @@ static struct cam_ctx_ops }, .irq_ops = NULL, .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, }, /* Activated */ { @@ -3936,6 +3955,7 @@ static struct cam_ctx_ops }, .irq_ops = __cam_isp_ctx_handle_irq_in_activated, .pagefault_ops = cam_isp_context_dump_active_request, + .dumpinfo_ops = cam_isp_context_info_dump, }, }; diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c index 96a12a707dd3..b076583cada2 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c @@ -471,6 +471,206 @@ static int cam_ife_hw_mgr_free_hw_res( return 0; } +static const char *cam_ife_hw_mgr_get_res_state( + uint32_t res_state) +{ + switch (res_state) { + case CAM_ISP_RESOURCE_STATE_UNAVAILABLE: + return "UNAVAILABLE"; + case CAM_ISP_RESOURCE_STATE_AVAILABLE: + return "AVAILABLE"; + case CAM_ISP_RESOURCE_STATE_RESERVED: + return "RESERVED"; + case CAM_ISP_RESOURCE_STATE_INIT_HW: + return "HW INIT DONE"; + case CAM_ISP_RESOURCE_STATE_STREAMING: + return "STREAMING"; + default: + return "INVALID STATE"; + } +} + +static const char *cam_ife_hw_mgr_get_csid_res_id( + uint32_t res_id) +{ + switch (res_id) { + case CAM_IFE_PIX_PATH_RES_RDI_0: + return "RDI_0"; + case CAM_IFE_PIX_PATH_RES_RDI_1: + return "RDI_1"; + case CAM_IFE_PIX_PATH_RES_RDI_2: + return "RDI_2"; + case CAM_IFE_PIX_PATH_RES_RDI_3: + return "RDI_3"; + case CAM_IFE_PIX_PATH_RES_IPP: + return "IPP"; + case CAM_IFE_PIX_PATH_RES_PPP: + return "PPP"; + default: + return "INVALID"; + } +} + +static const char *cam_ife_hw_mgr_get_src_res_id( + uint32_t res_id) +{ + switch (res_id) { + case CAM_ISP_HW_VFE_IN_CAMIF: + return "CAMIF"; + case CAM_ISP_HW_VFE_IN_TESTGEN: + return "TESTGEN"; + case CAM_ISP_HW_VFE_IN_RD: + return "BUS_RD"; + case CAM_ISP_HW_VFE_IN_RDI0: + return "RDI_0"; + case CAM_ISP_HW_VFE_IN_RDI1: + return "RDI_1"; + case CAM_ISP_HW_VFE_IN_RDI2: + return "RDI_2"; + case CAM_ISP_HW_VFE_IN_RDI3: + return "RDI_3"; + case CAM_ISP_HW_VFE_IN_PDLIB: + return "PDLIB"; + case CAM_ISP_HW_VFE_IN_LCR: + return "LCR"; + default: + return "INVALID"; + } +} + +static void cam_ife_hw_mgr_dump_src_acq_info( + struct cam_ife_hw_mgr_ctx *hwr_mgr_ctx, + uint32_t num_pix_port, uint32_t num_rdi_port) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; + struct cam_isp_resource_node *hw_res = NULL; + int i = 0; + + CAM_INFO(CAM_ISP, + "Acquired HW for ctx: %u with pix_port: %u rdi_port: %u", + hwr_mgr_ctx->ctx_index, num_pix_port, num_rdi_port); + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE src split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_src_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } +} + +static void cam_ife_hw_mgr_dump_acq_data( + struct cam_ife_hw_mgr_ctx *hwr_mgr_ctx) +{ + struct cam_ife_hw_mgr_res *hw_mgr_res = NULL; + struct cam_ife_hw_mgr_res *hw_mgr_res_temp = NULL; + struct cam_isp_resource_node *hw_res = NULL; + struct timespec64 *ts = NULL; + uint64_t ms, tmp; + int i = 0, j = 0; + + ts = &hwr_mgr_ctx->ts; + tmp = ts->tv_sec; + ms = (ts->tv_nsec) / 1000000; + + CAM_INFO(CAM_ISP, + "**** %llu:%llu:%llu.%llu ctx_idx: %u rdi_only: %s is_dual: %s acquired ****", + (tmp / 3600) % 24, (tmp / 60) % 60, tmp % 60, ms, + hwr_mgr_ctx->ctx_index, + (hwr_mgr_ctx->is_rdi_only_context ? "true" : "false"), + (hwr_mgr_ctx->is_dual ? "true" : "false")); + + /* Iterate over CID resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_cid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) { + CAM_INFO(CAM_ISP, + "CID split_id: %d res_id: %u hw_idx: %u state: %s", + i, hw_res->res_id, + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + } + + /* Iterate over CSID resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_csid, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "CSID split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_csid_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + + /* Iterate over IFE IN resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_src, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE src split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_src_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + + /* Iterate over IFE RD resources */ + list_for_each_entry_safe(hw_mgr_res, hw_mgr_res_temp, + &hwr_mgr_ctx->res_list_ife_in_rd, list) { + for (i = 0; i < CAM_ISP_HW_SPLIT_MAX; i++) { + hw_res = hw_mgr_res->hw_res[i]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE src_rd split_id: %d res_id: %s hw_idx: %u state: %s", + i, + cam_ife_hw_mgr_get_src_res_id( + hw_res->res_id), + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } + + /* Iterate over IFE OUT resources */ + for (i = 0; i < CAM_IFE_HW_OUT_RES_MAX; i++) { + for (j = 0; j < CAM_ISP_HW_SPLIT_MAX; j++) { + hw_mgr_res = &hwr_mgr_ctx->res_list_ife_out[i]; + hw_res = hw_mgr_res->hw_res[j]; + if (hw_res && hw_res->hw_intf) + CAM_INFO(CAM_ISP, + "IFE out split_id: %d res_id: 0x%x hw_idx: %u state: %s", + i, hw_res->res_id, + hw_res->hw_intf->hw_idx, + cam_ife_hw_mgr_get_res_state + (hw_res->res_state)); + } + } +} + static int cam_ife_mgr_csid_stop_hw( struct cam_ife_hw_mgr_ctx *ctx, struct list_head *stop_list, uint32_t base_idx, uint32_t stop_cmd) @@ -2400,8 +2600,11 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) if (rc) { CAM_ERR(CAM_ISP, "can not acquire resource"); + cam_ife_hw_mgr_dump_src_acq_info(ife_ctx, + total_pix_port, total_rdi_port); goto free_mem; } + kfree(in_port->data); kfree(in_port); in_port = NULL; @@ -2426,9 +2629,13 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) acquire_args->valid_acquired_hw = acquire_hw_info->num_inputs; - cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); + getnstimeofday64(&ife_ctx->ts); + CAM_INFO(CAM_ISP, + "Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u", + total_pix_port, total_rdi_port, + ife_ctx->is_dual, ife_ctx->ctx_index); - CAM_DBG(CAM_ISP, "Exit...(success)"); + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); return 0; free_mem: @@ -2661,9 +2868,12 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args) acquire_args->ctxt_to_hw_map = ife_ctx; ife_ctx->ctx_in_use = 1; - cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); + CAM_INFO(CAM_ISP, + "Acquire HW success with total_pix: %u total_rdi: %u is_dual: %u in ctx: %u", + total_pix_port, total_rdi_port, + ife_ctx->is_dual, ife_ctx->ctx_index); - CAM_DBG(CAM_ISP, "Exit...(success)"); + cam_ife_hw_mgr_put_ctx(&ife_hw_mgr->used_ctx_list, &ife_ctx); return 0; free_res: @@ -3722,8 +3932,11 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv, ctx->eof_cnt[i] = 0; ctx->epoch_cnt[i] = 0; } - CAM_DBG(CAM_ISP, "Exit...ctx id:%d", + + CAM_INFO(CAM_ISP, "Release HW success ctx id: %u", ctx->ctx_index); + + memset(&ctx->ts, 0, sizeof(struct timespec64)); cam_ife_hw_mgr_put_ctx(&hw_mgr->free_ctx_list, &ctx); return rc; } @@ -5494,6 +5707,9 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args) return rc; } + break; + case CAM_HW_MGR_CMD_DUMP_ACQ_INFO: + cam_ife_hw_mgr_dump_acq_data(ctx); break; default: CAM_ERR(CAM_ISP, "Invalid cmd"); diff --git a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h index 698b0c60ca9b..40ec7262122a 100644 --- a/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h +++ b/drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.h @@ -7,6 +7,7 @@ #define _CAM_IFE_HW_MGR_H_ #include +#include #include "cam_isp_hw_mgr.h" #include "cam_vfe_hw_intf.h" #include "cam_ife_csid_hw_intf.h" @@ -132,6 +133,7 @@ struct cam_ife_hw_mgr_debug { * @init_done indicate whether init hw is done * @is_fe_enable indicate whether fetch engine\read path is enabled * @is_dual indicate whether context is in dual VFE mode + * @ts captured timestamp when the ctx is acquired */ struct cam_ife_hw_mgr_ctx { struct list_head list; @@ -175,6 +177,7 @@ struct cam_ife_hw_mgr_ctx { bool init_done; bool is_fe_enable; bool is_dual; + struct timespec64 ts; }; /**