msm: camera: isp: Dump previous acq ctx info on acq failure

In case acquire hw fails, dump the previously acquired
streams to infer the reason for the failure.

CRs-Fixed: 2512474
Change-Id: I3ee2b85e0843ab4a605625950dc60366c0b50713
Signed-off-by: Karthik Anantha Ram <kartanan@codeaurora.org>
This commit is contained in:
Karthik Anantha Ram 2019-08-02 11:06:22 -07:00
parent 9712baaea9
commit 03e52e70d6
9 changed files with 345 additions and 11 deletions

View File

@ -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,

View File

@ -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()
*

View File

@ -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;
}

View File

@ -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_ */

View File

@ -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,
};
/**

View File

@ -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;

View File

@ -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,
},
};

View File

@ -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");

View File

@ -7,6 +7,7 @@
#define _CAM_IFE_HW_MGR_H_
#include <linux/completion.h>
#include <linux/time.h>
#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;
};
/**