msm: camera: common: Add camera error injection utility

Add and implement sysfs parameters to inject errors to
camera HW on demand through UMD for IFE,ICP and JPEG.

CRs-Fixed: 3115857
Change-Id: I4376fe31016cd81ad7e6f04cbc55e8ce010a6154
Signed-off-by: Pranav Sanwal <quic_psanwal@quicinc.com>
This commit is contained in:
Pranav Sanwal
2021-10-14 20:38:34 +05:30
committed by Camera Software Integration
vanhempi b997a29613
commit 1220255b08
18 muutettua tiedostoa jossa 710 lisäystä ja 0 poistoa

Näytä tiedosto

@@ -769,3 +769,31 @@ void cam_context_getref(struct cam_context *ctx)
ctx->dev_hdl, refcount_read(&(ctx->refcount.refcount)),
ctx->dev_name);
}
int cam_context_add_err_inject(struct cam_context *ctx, void *err_param)
{
int rc = 0;
if (!ctx->state_machine) {
CAM_ERR(CAM_CORE, "Context is not ready");
return -EINVAL;
}
mutex_lock(&ctx->ctx_mutex);
if ((ctx->state > CAM_CTX_AVAILABLE) &&
(ctx->state < CAM_CTX_STATE_MAX)) {
if (ctx->state_machine[ctx->state].err_inject_ops) {
rc = ctx->state_machine[ctx->state].err_inject_ops(
ctx, err_param);
} else {
CAM_WARN(CAM_CORE, "No err inject ops in dev %d,state %d",
ctx->dev_hdl, ctx->state);
}
} else {
rc = -EINVAL;
}
mutex_unlock(&ctx->ctx_mutex);
return rc;
}

Näytä tiedosto

@@ -14,6 +14,7 @@
#include "cam_req_mgr_interface.h"
#include "cam_hw_mgr_intf.h"
#include "cam_smmu_api.h"
#include "cam_common_util.h"
/* Forward declarations */
struct cam_context;
@@ -164,6 +165,7 @@ struct cam_ctx_crm_ops {
* context info
* @recovery_ops: Function to be invoked to try hardware recovery
* @mini_dump_ops: Function for mini dump
* @err_inject_ops: Function for error injection
*
*/
struct cam_ctx_ops {
@@ -174,8 +176,10 @@ struct cam_ctx_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;
cam_ctx_err_inject_cb_func err_inject_ops;
};
/**
* struct cam_context - camera context object for the subdevice node
*
@@ -596,4 +600,17 @@ void cam_context_putref(struct cam_context *ctx);
*/
void cam_context_getref(struct cam_context *ctx);
/**
* cam_context_add_err_inject()
*
* @brief: Add error inject parameters through err_inject_ops.
*
* @ctx: Context for which error is to be injected
*
* @err_param: Error injection parameters
*
*/
int cam_context_add_err_inject(struct cam_context *ctx,
void *err_param);
#endif /* _CAM_CONTEXT_H_ */

Näytä tiedosto

@@ -1575,6 +1575,26 @@ end:
*bytes_updated = bytes_written;
}
int cam_context_err_to_hw(struct cam_context *ctx, void *args)
{
int rc = -EINVAL;
if (!ctx || !args) {
CAM_ERR(CAM_CTXT, "invalid params for error injection");
return rc;
}
if (ctx->hw_mgr_intf->hw_inject_err) {
ctx->hw_mgr_intf->hw_inject_err(ctx->ctxt_to_hw_map, args);
rc = 0;
} else {
CAM_ERR(CAM_CTXT, "hw_intf cb absent for dev hdl: %lld, ctx id: %lld",
ctx->dev_hdl, ctx->ctx_id);
}
return rc;
}
int cam_context_mini_dump(struct cam_context *ctx, void *args)
{
struct cam_hw_mini_dump_info *md;

Näytä tiedosto

@@ -37,4 +37,5 @@ int32_t cam_context_dump_dev_to_hw(struct cam_context *ctx,
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);
int cam_context_err_to_hw(struct cam_context *ctx, void *args);
#endif /* _CAM_CONTEXT_UTILS_H_ */

Näytä tiedosto

@@ -65,6 +65,10 @@ typedef int (*cam_ctx_recovery_cb_func)(void *context,
typedef int (*cam_ctx_mini_dump_cb_func)(void *context,
void *args);
/* ctx error inject callback function type */
typedef int (*cam_ctx_err_inject_cb_func)(void *context,
void *args);
/**
* struct cam_hw_update_entry - Entry for hardware config
*
@@ -496,6 +500,21 @@ struct cam_hw_mini_dump_info {
uint8_t hw_mgr_ctx_id;
};
/**
* cam_hw_err_param - cam hHW error injection parameters
*
* @err_type error type for the injected error
* @err_code error code for the injected error
* @err_req_id Req Id for which the error is injected
* @is_valid bool flag to indicate if error injection is enabled for a context
*/
struct cam_hw_err_param {
uint32_t err_type;
uint32_t err_code;
uint64_t err_req_id;
bool is_valid;
};
/**
* cam_hw_mgr_intf - HW manager interface
*
@@ -526,6 +545,7 @@ struct cam_hw_mini_dump_info {
* @hw_reset: Function pointer for HW reset
* @hw_dump: Function pointer for HW dump
* @hw_recovery: Function pointer for HW recovery callback
* @hw_inject_err Function pointer for HW error injection callback
*
*/
struct cam_hw_mgr_intf {
@@ -549,6 +569,7 @@ struct cam_hw_mgr_intf {
int (*hw_reset)(void *hw_priv, void *hw_reset_args);
int (*hw_dump)(void *hw_priv, void *hw_dump_args);
int (*hw_recovery)(void *hw_priv, void *hw_recovery_args);
void (*hw_inject_err)(void *hw_priv, void *hw_err_inject_args);
};
#endif /* _CAM_HW_MGR_INTF_H_ */

Näytä tiedosto

@@ -111,6 +111,8 @@ static int __cam_icp_release_dev_in_acquired(struct cam_context *ctx,
if (rc)
CAM_ERR(CAM_ICP, "Unable to release device");
cam_common_release_err_params(ctx->dev_hdl);
ctx->state = CAM_CTX_AVAILABLE;
trace_cam_context_state("ICP", ctx);
return rc;
@@ -326,6 +328,48 @@ static int __cam_icp_ctx_handle_hw_event(void *ctx,
return rc;
}
static int cam_icp_context_inject_error(void *context, void *err_param)
{
int rc = 0;
uint32_t err_code;
uint32_t err_type;
uint64_t req_id;
struct cam_context *ctx = (struct cam_context *)context;
if (!err_param) {
CAM_ERR(CAM_ICP, "err_params is not valid");
return -EINVAL;
}
err_code = ((struct cam_err_inject_param *)err_param)->err_code;
err_type = ((struct cam_err_inject_param *)err_param)->err_type;
req_id = ((struct cam_err_inject_param *)err_param)->req_id;
switch (err_type) {
case CAM_SYNC_STATE_SIGNALED_ERROR:
switch (err_code) {
case CAM_SYNC_ICP_EVENT_FRAME_PROCESS_FAILURE:
case CAM_SYNC_ICP_EVENT_CONFIG_ERR:
break;
default:
CAM_ERR(CAM_ICP, "ICP Error code %d not supported!", err_code);
return -EINVAL;
}
break;
default:
CAM_ERR(CAM_ICP, "ICP Error type: %d not supported!", err_code);
return -EINVAL;
}
CAM_INFO(CAM_ICP,
"Err inject params: err_code: %u err_type: %u, to dev_hdl: %lld",
err_code, err_type, ctx->dev_hdl);
rc = cam_context_err_to_hw(ctx, err_param);
return rc;
}
static struct cam_ctx_ops
cam_icp_ctx_state_machine[CAM_CTX_STATE_MAX] = {
/* Uninit */
@@ -356,6 +400,7 @@ static struct cam_ctx_ops
.irq_ops = __cam_icp_ctx_handle_hw_event,
.pagefault_ops = cam_icp_context_dump_active_request,
.mini_dump_ops = cam_icp_context_mini_dump,
.err_inject_ops = cam_icp_context_inject_error,
},
/* Ready */
{
@@ -370,6 +415,7 @@ static struct cam_ctx_ops
.irq_ops = __cam_icp_ctx_handle_hw_event,
.pagefault_ops = cam_icp_context_dump_active_request,
.mini_dump_ops = cam_icp_context_mini_dump,
.err_inject_ops = cam_icp_context_inject_error,
},
/* Flushed */
{
@@ -382,6 +428,7 @@ static struct cam_ctx_ops
.irq_ops = NULL,
.pagefault_ops = cam_icp_context_dump_active_request,
.mini_dump_ops = cam_icp_context_mini_dump,
.err_inject_ops = cam_icp_context_inject_error,
},
};

Näytä tiedosto

@@ -30,6 +30,7 @@
#include "cam_debug_util.h"
#include "cam_smmu_api.h"
#include "camera_main.h"
#include "cam_common_util.h"
#define CAM_ICP_DEV_NAME "cam-icp"
@@ -50,6 +51,23 @@ static const struct of_device_id cam_icp_dt_match[] = {
{}
};
static int cam_icp_dev_err_inject_cb(void *err_param)
{
int i = 0;
for (i = 0; i < CAM_ICP_CTX_MAX; i++) {
if (g_icp_dev.ctx[i].dev_hdl ==
((struct cam_err_inject_param *)err_param)->dev_hdl) {
CAM_INFO(CAM_ICP, "ICP err inject dev_hdl found:%d",
g_icp_dev.ctx[i].dev_hdl);
cam_context_add_err_inject(&g_icp_dev.ctx[i], err_param);
return 0;
}
}
CAM_ERR(CAM_ICP, "No dev hdl found");
return -ENODEV;
}
static void cam_icp_dev_iommu_fault_handler(struct cam_smmu_pf_info *pf_info)
{
int i = 0;
@@ -223,6 +241,9 @@ static int cam_icp_component_bind(struct device *dev,
goto ctx_fail;
}
cam_common_register_err_inject_cb(cam_icp_dev_err_inject_cb,
CAM_COMMON_ERR_INJECT_HW_ICP);
node->sd_handler = cam_icp_subdev_close_internal;
cam_smmu_set_client_page_fault_handler(iommu_hdl,
cam_icp_dev_iommu_fault_handler, node);

Näytä tiedosto

@@ -2248,6 +2248,33 @@ static const char *cam_icp_error_handle_id_to_type(
return name;
}
static inline void cam_icp_mgr_validate_inject_err(uint64_t current_req_id, uint32_t *event_id,
struct cam_hw_done_event_data *buf_data, struct cam_icp_hw_ctx_data *ctx_data)
{
if (ctx_data->err_inject_params.err_req_id == current_req_id) {
switch (ctx_data->err_inject_params.err_code) {
case CAM_SYNC_ICP_EVENT_FRAME_PROCESS_FAILURE:
*event_id = CAM_CTX_EVT_ID_ERROR;
buf_data->evt_param = CAM_SYNC_ICP_EVENT_FRAME_PROCESS_FAILURE;
break;
case CAM_SYNC_ICP_EVENT_CONFIG_ERR:
*event_id = CAM_CTX_EVT_ID_ERROR;
buf_data->evt_param = CAM_SYNC_ICP_EVENT_CONFIG_ERR;
break;
default:
CAM_INFO(CAM_ICP, "ICP error code not supported: %d",
ctx_data->err_inject_params.err_code);
return;
}
} else
return;
CAM_INFO(CAM_ICP, "ICP Err Induced! err_code: %u, req_id: %llu",
ctx_data->err_inject_params.err_code, current_req_id);
memset(&(ctx_data->err_inject_params), 0, sizeof(struct cam_hw_err_param));
}
static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag)
{
int i;
@@ -2347,6 +2374,9 @@ static int cam_icp_mgr_handle_frame_process(uint32_t *msg_ptr, int flag)
"[%s]: BufDone Req %llu event_id %d",
ctx_data->ctx_id_string, hfi_frame_process->request_id[idx], event_id);
if (ctx_data->err_inject_params.is_valid)
cam_icp_mgr_validate_inject_err(request_id, &event_id, &buf_data, ctx_data);
buf_data.request_id = hfi_frame_process->request_id[idx];
icp_done_evt.evt_id = event_id;
icp_done_evt.buf_done_data = &buf_data;
@@ -3914,6 +3944,8 @@ static int cam_icp_mgr_release_ctx(struct cam_icp_hw_mgr *hw_mgr, int ctx_id)
}
mutex_lock(&hw_mgr->ctx_data[ctx_id].ctx_mutex);
memset(&(hw_mgr->ctx_data[ctx_id].err_inject_params), 0,
sizeof(struct cam_hw_err_param));
cam_icp_remove_ctx_bw(hw_mgr, &hw_mgr->ctx_data[ctx_id]);
if (hw_mgr->ctx_data[ctx_id].state !=
CAM_ICP_CTX_STATE_ACQUIRED) {
@@ -6926,6 +6958,19 @@ static int cam_icp_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
return rc;
}
static void cam_icp_mgr_inject_err(void *hw_mgr_priv, void *hw_err_inject_args)
{
struct cam_icp_hw_ctx_data *ctx_data = hw_mgr_priv;
ctx_data->err_inject_params.err_code = ((struct cam_err_inject_param *)
hw_err_inject_args)->err_code;
ctx_data->err_inject_params.err_type = ((struct cam_err_inject_param *)
hw_err_inject_args)->err_type;
ctx_data->err_inject_params.err_req_id = ((struct cam_err_inject_param *)
hw_err_inject_args)->req_id;
ctx_data->err_inject_params.is_valid = true;
}
int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
int *iommu_hdl, cam_icp_mini_dump_cb mini_dump_cb)
{
@@ -6955,6 +7000,7 @@ int cam_icp_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
hw_mgr_intf->hw_flush = cam_icp_mgr_hw_flush;
hw_mgr_intf->hw_cmd = cam_icp_mgr_cmd;
hw_mgr_intf->hw_dump = cam_icp_mgr_hw_dump;
hw_mgr_intf->hw_inject_err = cam_icp_mgr_inject_err;
icp_hw_mgr.secure_mode = CAM_SECURE_MODE_NON_SECURE;
icp_hw_mgr.mini_dump_cb = mini_dump_cb;

Näytä tiedosto

@@ -271,6 +271,7 @@ struct cam_ctx_clk_info {
* @watch_dog_reset_counter: Counter for watch dog reset
* @icp_dev_io_info: io config resource
* @last_flush_req: last flush req for this ctx
* @err_inject_params: Error injection data for hw_mgr_ctx
* @abort_timed_out: Indicates if abort timed out
*/
struct cam_icp_hw_ctx_data {
@@ -295,6 +296,7 @@ struct cam_icp_hw_ctx_data {
struct cam_icp_acquire_dev_info icp_dev_io_info;
uint64_t last_flush_req;
char ctx_id_string[128];
struct cam_hw_err_param err_inject_params;
bool abort_timed_out;
};

Näytä tiedosto

@@ -4009,6 +4009,24 @@ static struct cam_isp_ctx_irq_ops
},
};
static inline int cam_isp_context_apply_error(struct cam_hw_err_param *err_params,
uint64_t current_req_id, struct cam_context *ctx)
{
int rc = 0;
if (err_params->err_req_id == current_req_id) {
CAM_INFO(CAM_ISP,
"Err inject for req: %llu, err_code: %d, err_type: %d ctx id: %d",
current_req_id, err_params->err_code, err_params->err_type, ctx->ctx_id);
__cam_isp_ctx_notify_v4l2_error_event(err_params->err_type, err_params->err_code,
current_req_id, ctx);
memset(err_params, 0, sizeof(struct cam_hw_err_param));
return rc;
}
return -EINVAL;
}
static int __cam_isp_ctx_apply_req_in_activated_state(
struct cam_context *ctx, struct cam_req_mgr_apply_request *apply,
enum cam_isp_ctx_activated_substate next_state)
@@ -4119,6 +4137,13 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
cfg.reapply_type = req_isp->reapply_type;
cfg.cdm_reset_before_apply = req_isp->cdm_reset_before_apply;
if (ctx_isp->err_inject_params.is_valid) {
rc = cam_isp_context_apply_error(&(ctx_isp->err_inject_params),
req->request_id, ctx_isp->base);
if (!rc)
goto end;
}
atomic_set(&ctx_isp->apply_in_progress, 1);
rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
@@ -5626,6 +5651,9 @@ static int __cam_isp_ctx_release_dev_in_top_state(struct cam_context *ctx,
ctx_isp->hw_ctx = NULL;
}
cam_common_release_err_params(ctx->dev_hdl);
memset(&(ctx_isp->err_inject_params), 0, sizeof(struct cam_hw_err_param));
ctx->session_hdl = -1;
ctx->dev_hdl = -1;
ctx->link_hdl = -1;
@@ -7327,6 +7355,69 @@ static int __cam_isp_ctx_handle_irq_in_activated(void *context,
return rc;
}
static int cam_isp_context_inject_error(void *context, void *err_param)
{
int rc = 0;
struct cam_context *ctx = (struct cam_context *)context;
struct cam_isp_context *ctx_isp = ctx->ctx_priv;
uint64_t req_id;
uint32_t err_code;
uint32_t err_type;
if (!err_param) {
CAM_ERR(CAM_ISP, "err_param not valid");
return -EINVAL;
}
req_id = ((struct cam_err_inject_param *)err_param)->req_id;
err_type = ((struct cam_err_inject_param *)err_param)->err_type;
err_code = ((struct cam_err_inject_param *)err_param)->err_code;
switch (err_type) {
case CAM_REQ_MGR_ERROR_TYPE_RECOVERY:
switch (err_code) {
case CAM_REQ_MGR_LINK_STALLED_ERROR:
case CAM_REQ_MGR_CSID_FIFO_OVERFLOW_ERROR:
case CAM_REQ_MGR_CSID_RECOVERY_OVERFLOW_ERROR:
case CAM_REQ_MGR_CSID_PIXEL_COUNT_MISMATCH:
case CAM_REQ_MGR_CSID_ERR_ON_SENSOR_SWITCHING:
break;
default:
CAM_ERR(CAM_ISP, "err code not supported %d", err_code);
return -EINVAL;
}
break;
case CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY:
switch (err_code) {
case CAM_REQ_MGR_CSID_FATAL_ERROR:
break;
default:
CAM_ERR(CAM_ISP, "err code not supported %d", err_code);
return -EINVAL;
}
break;
case CAM_REQ_MGR_ERROR_TYPE_SOF_FREEZE:
err_code = CAM_REQ_MGR_ISP_UNREPORTED_ERROR;
break;
case CAM_REQ_MGR_ERROR_TYPE_PAGE_FAULT:
err_code = CAM_REQ_MGR_ISP_UNREPORTED_ERROR;
break;
default:
CAM_ERR(CAM_ISP, "err type not supported %d", err_type);
return -EINVAL;
}
CAM_DBG(CAM_ISP, "inject err isp code: %d type: %d ctx id: %d",
err_code, err_type, ctx->ctx_id);
ctx_isp->err_inject_params.err_code = err_code;
ctx_isp->err_inject_params.err_type = err_type;
ctx_isp->err_inject_params.err_req_id = req_id;
ctx_isp->err_inject_params.is_valid = true;
return rc;
}
/* top state machine */
static struct cam_ctx_ops
cam_isp_ctx_top_state_machine[CAM_CTX_STATE_MAX] = {
@@ -7363,6 +7454,7 @@ static struct cam_ctx_ops
.irq_ops = NULL,
.pagefault_ops = cam_isp_context_dump_requests,
.dumpinfo_ops = cam_isp_context_info_dump,
.err_inject_ops = cam_isp_context_inject_error,
},
/* Ready */
{
@@ -7381,6 +7473,7 @@ static struct cam_ctx_ops
.irq_ops = NULL,
.pagefault_ops = cam_isp_context_dump_requests,
.dumpinfo_ops = cam_isp_context_info_dump,
.err_inject_ops = cam_isp_context_inject_error,
},
/* Flushed */
{
@@ -7398,6 +7491,7 @@ static struct cam_ctx_ops
.irq_ops = NULL,
.pagefault_ops = cam_isp_context_dump_requests,
.dumpinfo_ops = cam_isp_context_info_dump,
.err_inject_ops = cam_isp_context_inject_error,
},
/* Activated */
{
@@ -7421,6 +7515,7 @@ static struct cam_ctx_ops
.pagefault_ops = cam_isp_context_dump_requests,
.dumpinfo_ops = cam_isp_context_info_dump,
.recovery_ops = cam_isp_context_hw_recovery,
.err_inject_ops = cam_isp_context_inject_error,
},
};

Näytä tiedosto

@@ -340,6 +340,7 @@ struct cam_isp_context {
int32_t trigger_id;
int64_t last_bufdone_err_apply_req_id;
uint32_t v4l2_event_sub_ids;
struct cam_hw_err_param err_inject_params;
bool aeb_enabled;
bool do_internal_recovery;
};

Näytä tiedosto

@@ -19,9 +19,25 @@
#include "cam_debug_util.h"
#include "cam_smmu_api.h"
#include "camera_main.h"
#include "cam_common_util.h"
static struct cam_isp_dev g_isp_dev;
static int cam_isp_dev_err_inject_cb(void *err_param)
{
int i = 0;
for (i = 0; i < g_isp_dev.max_context; i++) {
if ((g_isp_dev.ctx[i].dev_hdl) ==
((struct cam_err_inject_param *)err_param)->dev_hdl) {
cam_context_add_err_inject(&g_isp_dev.ctx[i], err_param);
return 0;
}
}
CAM_ERR(CAM_ISP, "no dev hdl found for IFE");
return -ENODEV;
}
static void cam_isp_dev_iommu_fault_handler(struct cam_smmu_pf_info *pf_info)
{
int i = 0;
@@ -180,6 +196,9 @@ static int cam_isp_dev_component_bind(struct device *dev,
}
}
cam_common_register_err_inject_cb(cam_isp_dev_err_inject_cb,
CAM_COMMON_ERR_INJECT_HW_ISP);
rc = cam_node_init(node, &hw_mgr_intf, g_isp_dev.ctx,
g_isp_dev.max_context, CAM_ISP_DEV_NAME);

Näytä tiedosto

@@ -8,6 +8,7 @@
#include <linux/slab.h>
#include <linux/uaccess.h>
#include <media/cam_sync.h>
#include "cam_mem_mgr.h"
#include "cam_jpeg_context.h"
#include "cam_context_utils.h"
@@ -97,6 +98,8 @@ static int __cam_jpeg_ctx_release_dev_in_acquired(struct cam_context *ctx,
if (rc)
CAM_ERR(CAM_JPEG, "Unable to release device %d", rc);
cam_common_release_err_params(ctx->dev_hdl);
ctx->state = CAM_CTX_AVAILABLE;
return rc;
@@ -153,6 +156,57 @@ static int __cam_jpeg_ctx_stop_dev_in_acquired(struct cam_context *ctx,
return rc;
}
static int cam_jpeg_context_inject_error(void *context, void *err_param)
{
int rc = 0;
struct cam_context *ctx = (struct cam_context *)context;
uint64_t req_id;
uint32_t err_code;
uint32_t err_type;
if (!err_param) {
CAM_ERR(CAM_ISP, "err_param not valid");
return -EINVAL;
}
req_id = ((struct cam_err_inject_param *)err_param)->req_id;
err_code = ((struct cam_err_inject_param *)err_param)->err_code;
err_type = ((struct cam_err_inject_param *)err_param)->err_type;
switch (err_type) {
case CAM_REQ_MGR_RETRY_EVENT:
switch (err_code) {
case CAM_REQ_MGR_JPEG_THUBNAIL_SIZE_ERROR:
break;
default:
CAM_ERR(CAM_ISP, "err code not supported %d", err_code);
return -EINVAL;
}
break;
case CAM_SYNC_STATE_SIGNALED_ERROR:
switch (err_code) {
case CAM_SYNC_JPEG_EVENT_INVLD_CMD:
case CAM_SYNC_JPEG_EVENT_SET_IRQ_CB:
case CAM_SYNC_JPEG_EVENT_HW_RESET_FAILED:
case CAM_SYNC_JPEG_EVENT_CDM_CHANGE_BASE_ERR:
case CAM_SYNC_JPEG_EVENT_CDM_CONFIG_ERR:
case CAM_SYNC_JPEG_EVENT_START_HW_ERR:
break;
default:
CAM_ERR(CAM_ISP, "err code not supported %d", err_code);
return -EINVAL;
}
break;
default:
CAM_ERR(CAM_ISP, "err type not supported %d", err_type);
return -EINVAL;
}
rc = cam_context_err_to_hw(ctx, err_param);
return rc;
}
/* top state machine */
static struct cam_ctx_ops
cam_jpeg_ctx_state_machine[CAM_CTX_STATE_MAX] = {
@@ -184,6 +238,7 @@ static struct cam_ctx_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,
.err_inject_ops = cam_jpeg_context_inject_error,
},
/* Ready */
{

Näytä tiedosto

@@ -16,11 +16,28 @@
#include "cam_debug_util.h"
#include "cam_smmu_api.h"
#include "camera_main.h"
#include "cam_common_util.h"
#define CAM_JPEG_DEV_NAME "cam-jpeg"
static struct cam_jpeg_dev g_jpeg_dev;
static int cam_jpeg_dev_err_inject_cb(void *err_param)
{
int i = 0;
for (i = 0; i < CAM_JPEG_CTX_MAX; i++) {
if (g_jpeg_dev.ctx[i].dev_hdl ==
((struct cam_err_inject_param *)err_param)->dev_hdl) {
CAM_INFO(CAM_ISP, "dev_hdl found:%d", g_jpeg_dev.ctx[i].dev_hdl);
cam_context_add_err_inject(&g_jpeg_dev.ctx[i], err_param);
return 0;
}
}
CAM_ERR(CAM_ISP, "no dev hdl found jpeg");
return -EINVAL;
}
static void cam_jpeg_dev_iommu_fault_handler(
struct cam_smmu_pf_info *pf_info)
{
@@ -155,6 +172,9 @@ static int cam_jpeg_dev_component_bind(struct device *dev,
}
}
cam_common_register_err_inject_cb(cam_jpeg_dev_err_inject_cb,
CAM_COMMON_ERR_INJECT_HW_JPEG);
rc = cam_node_init(node, &hw_mgr_intf, g_jpeg_dev.ctx, CAM_JPEG_CTX_MAX,
CAM_JPEG_DEV_NAME);
if (rc) {

Näytä tiedosto

@@ -56,6 +56,30 @@ static int cam_jpeg_insert_cdm_change_base(
struct cam_jpeg_hw_ctx_data *ctx_data,
struct cam_jpeg_hw_mgr *hw_mgr);
static void cam_jpeg_inject_err(struct cam_jpeg_hw_ctx_data *ctx_data,
struct cam_hw_done_event_data *buf_data)
{
struct cam_req_mgr_message v4l2_msg = {0};
struct cam_context *cam_ctx = ctx_data->context_priv;
if (ctx_data->err_inject_params.err_code == CAM_REQ_MGR_JPEG_THUBNAIL_SIZE_ERROR) {
v4l2_msg.session_hdl = cam_ctx->session_hdl;
v4l2_msg.u.node_msg.request_id = ctx_data->err_inject_params.err_req_id;
v4l2_msg.u.node_msg.link_hdl = cam_ctx->link_hdl;
v4l2_msg.u.node_msg.device_hdl = cam_ctx->dev_hdl;
v4l2_msg.u.node_msg.event_type = CAM_REQ_MGR_RETRY_EVENT;
v4l2_msg.u.node_msg.event_cause =
CAM_REQ_MGR_JPEG_THUBNAIL_SIZE_ERROR;
cam_req_mgr_notify_message(&v4l2_msg,
V4L_EVENT_CAM_REQ_MGR_NODE_EVENT,
V4L_EVENT_CAM_REQ_MGR_EVENT);
} else {
buf_data->evt_param = ctx_data->err_inject_params.err_code;
}
memset(&(ctx_data->err_inject_params), 0, sizeof(struct cam_hw_err_param));
}
static int cam_jpeg_generic_blob_handler(void *user_data,
uint32_t blob_type, uint32_t blob_size, uint8_t *blob_data)
{
@@ -617,6 +641,7 @@ static int cam_jpeg_mgr_release_ctx(
}
ctx_data->in_use = false;
memset(&(ctx_data->err_inject_params), 0, sizeof(struct cam_hw_err_param));
mutex_unlock(&ctx_data->ctx_mutex);
return 0;
@@ -781,6 +806,11 @@ static int cam_jpeg_mgr_process_hw_update_entries(void *priv, void *data)
goto end;
}
if (ctx_data->err_inject_params.is_valid &&
ctx_data->err_inject_params.err_req_id == request_id) {
cam_jpeg_inject_err(ctx_data, &buf_data);
goto end_callcb;
}
irq_cb.jpeg_hw_mgr_cb = cam_jpeg_hw_mgr_sched_bottom_half;
irq_cb.irq_cb_data.private_data = (void *)ctx_data;
irq_cb.irq_cb_data.jpeg_req = jpeg_req;
@@ -2217,6 +2247,19 @@ static int cam_jpeg_mgr_create_debugfs_entry(void)
return rc;
}
static void cam_jpeg_mgr_inject_err(void *hw_mgr_priv, void *hw_err_inject_args)
{
struct cam_jpeg_hw_ctx_data *ctx_data = hw_mgr_priv;
ctx_data->err_inject_params.err_code = ((struct cam_err_inject_param *)
hw_err_inject_args)->err_code;
ctx_data->err_inject_params.err_type = ((struct cam_err_inject_param *)
hw_err_inject_args)->err_type;
ctx_data->err_inject_params.err_req_id = ((struct cam_err_inject_param *)
hw_err_inject_args)->req_id;
ctx_data->err_inject_params.is_valid = true;
}
int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
int *iommu_hdl, cam_jpeg_mini_dump_cb mini_dump_cb)
{
@@ -2244,6 +2287,7 @@ int cam_jpeg_hw_mgr_init(struct device_node *of_node, uint64_t *hw_mgr_hdl,
hw_mgr_intf->hw_stop = cam_jpeg_mgr_hw_stop;
hw_mgr_intf->hw_cmd = cam_jpeg_mgr_cmd;
hw_mgr_intf->hw_dump = cam_jpeg_mgr_hw_dump;
hw_mgr_intf->hw_inject_err = cam_jpeg_mgr_inject_err;
mutex_init(&g_jpeg_hw_mgr.hw_mgr_mutex);
spin_lock_init(&g_jpeg_hw_mgr.hw_mgr_lock);

Näytä tiedosto

@@ -104,6 +104,7 @@ struct cam_jpeg_hw_cfg_req {
* @wait_complete: Completion info
* @cdm_cmd: Cdm cmd submitted for that context.
* @mini_dump_cb: Mini dump cb
* @err_inject_params: Error injection params for hw_mgr_ctx
*/
struct cam_jpeg_hw_ctx_data {
void *context_priv;
@@ -114,6 +115,7 @@ struct cam_jpeg_hw_ctx_data {
struct completion wait_complete;
struct cam_cdm_bl_request *cdm_cmd;
cam_ctx_mini_dump_cb_func mini_dump_cb;
struct cam_hw_err_param err_inject_params;
};
/**

Näytä tiedosto

@@ -22,6 +22,8 @@ static struct cam_common_mini_dump_dev_info g_minidump_dev_info;
#define CAM_PRESIL_POLL_DELAY 20
static struct cam_common_err_inject_info g_err_inject_info;
static uint timeout_multiplier = 1;
module_param(timeout_multiplier, uint, 0644);
@@ -336,3 +338,202 @@ int cam_common_user_dump_helper(
return 0;
}
int cam_common_register_err_inject_cb(
cam_common_err_inject_cb err_inject_cb,
enum cam_common_err_inject_hw_id hw_id)
{
int rc = 0;
if (g_err_inject_info.num_hw_registered >= CAM_COMMON_ERR_INJECT_HW_MAX) {
CAM_ERR(CAM_UTIL, "No free index available");
return -EINVAL;
}
if (!err_inject_cb || hw_id >= CAM_COMMON_ERR_INJECT_HW_MAX) {
CAM_ERR(CAM_UTIL, "Invalid params");
return -EINVAL;
}
g_err_inject_info.err_inject_cb[hw_id] = err_inject_cb;
g_err_inject_info.num_hw_registered++;
CAM_DBG(CAM_UTIL, "err inject cb registered for HW_id:%d, total registered: %d", hw_id,
g_err_inject_info.num_hw_registered);
return rc;
}
int cam_common_release_err_params(uint64_t dev_hdl)
{
int rc = 0;
struct list_head *pos = NULL, *pos_next = NULL;
struct cam_err_inject_param *err_param;
if (!g_err_inject_info.is_list_initialised)
return -EINVAL;
if (list_empty(&g_err_inject_info.active_err_ctx_list)) {
CAM_ERR(CAM_UTIL, "list is empty");
return -EINVAL;
}
list_for_each_safe(pos, pos_next, &g_err_inject_info.active_err_ctx_list) {
err_param = list_entry(pos, struct cam_err_inject_param, list);
if (err_param->dev_hdl == dev_hdl) {
CAM_INFO(CAM_UTIL, "entry deleted for %llu dev hdl", dev_hdl);
list_del(pos);
kfree(err_param);
}
}
return rc;
}
static int cam_err_inject_set(const char *kmessage,
const struct kernel_param *kp)
{
int rc = 0;
char tmp_buff[CAM_COMMON_ERR_INJECT_BUFFER_LEN] = {'\0'};
char *token_start, *token_end;
struct cam_err_inject_param *err_params = NULL;
uint8_t param_counter = 0;
err_params = kzalloc(sizeof(struct cam_err_inject_param), GFP_KERNEL);
if (!err_params) {
CAM_ERR(CAM_UTIL, "no free memory");
return -ENOMEM;
}
memset(tmp_buff, 0, CAM_COMMON_ERR_INJECT_BUFFER_LEN);
rc = strscpy(tmp_buff, kmessage, CAM_COMMON_ERR_INJECT_BUFFER_LEN);
if (rc == -E2BIG)
goto free;
token_start = tmp_buff;
token_end = tmp_buff;
CAM_INFO(CAM_UTIL, "parsing input param for cam_err_inject: %s", tmp_buff);
while (token_start != NULL) {
strsep(&token_end, ":");
switch (param_counter) {
case HW_NAME:
if (strcmp(token_start, CAM_COMMON_IFE_NODE) == 0)
err_params->hw_id = CAM_COMMON_ERR_INJECT_HW_ISP;
else if (strcmp(token_start, CAM_COMMON_ICP_NODE) == 0)
err_params->hw_id = CAM_COMMON_ERR_INJECT_HW_ICP;
else if (strcmp(token_start, CAM_COMMON_JPEG_NODE) == 0)
err_params->hw_id = CAM_COMMON_ERR_INJECT_HW_JPEG;
else {
CAM_ERR(CAM_UTIL, "invalid camera hardware [ %s ]", token_start);
goto free;
}
break;
case REQ_ID:
if (kstrtou64(token_start, 0, &(err_params->req_id)))
goto free;
break;
case ERR_TYPE:
if (kstrtou32(token_start, 0, &(err_params->err_type)))
goto free;
break;
case ERR_CODE:
if (kstrtou32(token_start, 0, &(err_params->err_code)))
goto free;
break;
case DEV_HDL:
if (kstrtou64(token_start, 0, &(err_params->dev_hdl)))
goto free;
break;
default:
CAM_ERR(CAM_UTIL, "Insuffiecient parameter count [%d] ", param_counter);
goto free;
}
param_counter++;
token_start = token_end;
}
if (param_counter < CAM_COMMON_ERR_INJECT_PARAM_NUM) {
CAM_ERR(CAM_UTIL, "Insuffiecient parameter count [%d]", param_counter);
goto free;
}
CAM_INFO(CAM_UTIL, "parsed params: req_id: %llu err_type: %u, err_code: %u dev_hdl: %llu",
err_params->req_id, err_params->err_type, err_params->err_code,
err_params->dev_hdl);
if (g_err_inject_info.err_inject_cb[err_params->hw_id]) {
rc = g_err_inject_info.err_inject_cb[err_params->hw_id](err_params);
if (rc)
goto free;
else {
if (!g_err_inject_info.is_list_initialised) {
INIT_LIST_HEAD(&g_err_inject_info.active_err_ctx_list);
g_err_inject_info.is_list_initialised = true;
}
list_add(&err_params->list, &g_err_inject_info.active_err_ctx_list);
}
} else {
CAM_ERR(CAM_UTIL, "Handler for HW_id [%d] not registered", err_params->hw_id);
goto free;
}
if (rc)
CAM_ERR(CAM_UTIL, "No Dev_hdl found: [%d]", err_params->dev_hdl);
return rc;
free:
kfree(err_params);
return -EINVAL;
}
static int cam_err_inject_get(char *buffer,
const struct kernel_param *kp)
{
uint8_t hw_name[10];
uint16_t buff_max_size = CAM_COMMON_ERR_MODULE_PARAM_MAX_LENGTH;
struct cam_err_inject_param *err_param;
int ret = 0;
if (!g_err_inject_info.is_list_initialised)
return scnprintf(buffer, buff_max_size, "uninitialised");
else if (!list_empty(&g_err_inject_info.active_err_ctx_list)) {
list_for_each_entry(err_param, &g_err_inject_info.active_err_ctx_list, list) {
switch (err_param->hw_id) {
case CAM_COMMON_ERR_INJECT_HW_ISP:
strscpy(hw_name, CAM_COMMON_IFE_NODE, 10);
break;
case CAM_COMMON_ERR_INJECT_HW_ICP:
strscpy(hw_name, CAM_COMMON_ICP_NODE, 10);
break;
case CAM_COMMON_ERR_INJECT_HW_JPEG:
strscpy(hw_name, CAM_COMMON_JPEG_NODE, 10);
break;
default:
strscpy(hw_name, "undef", 10);
}
ret += scnprintf(buffer+ret, buff_max_size,
"hw_name: %s req_id: %u err_type: %u err_code: %u dev_hdl: %d\n",
hw_name, err_param->req_id, err_param->err_type,
err_param->err_code, err_param->dev_hdl);
CAM_DBG(CAM_UTIL, "output buffer: %s", buffer);
if (ret < buff_max_size) {
buff_max_size = buff_max_size - ret;
} else {
CAM_WARN(CAM_UTIL, "out buff max limit reached");
break;
}
}
return ret;
}
return scnprintf(buffer, buff_max_size, "uninitialised");
}
static const struct kernel_param_ops cam_error_inject_ops = {
.set = cam_err_inject_set,
.get = cam_err_inject_get
};
module_param_cb(cam_error_inject, &cam_error_inject_ops, NULL, 0644);

Näytä tiedosto

@@ -19,6 +19,14 @@
#define CAM_COMMON_HW_DUMP_TAG_MAX_LEN 64
#define CAM_COMMON_ERR_MODULE_PARAM_MAX_LENGTH 4096
#define CAM_COMMON_ERR_INJECT_BUFFER_LEN 200
#define CAM_COMMON_ERR_INJECT_DEV_MAX 5
#define CAM_COMMON_ERR_INJECT_PARAM_NUM 5
#define CAM_COMMON_IFE_NODE "IFE"
#define CAM_COMMON_ICP_NODE "IPE"
#define CAM_COMMON_JPEG_NODE "JPEG"
#define PTR_TO_U64(ptr) ((uint64_t)(uintptr_t)ptr)
#define U64_TO_PTR(ptr) ((void *)(uintptr_t)ptr)
@@ -78,6 +86,54 @@ struct cam_common_mini_dump_data {
unsigned long size[CAM_COMMON_MINI_DUMP_DEV_NUM];
};
typedef int (*cam_common_err_inject_cb) (void *err_param);
int cam_common_release_err_params(uint64_t dev_hdl);
enum cam_common_err_inject_hw_id {
CAM_COMMON_ERR_INJECT_HW_ISP,
CAM_COMMON_ERR_INJECT_HW_ICP,
CAM_COMMON_ERR_INJECT_HW_JPEG,
CAM_COMMON_ERR_INJECT_HW_MAX
};
enum cam_common_err_inject_input_param_pos {
HW_NAME = 0,
REQ_ID,
ERR_TYPE,
ERR_CODE,
DEV_HDL
};
/**
* @req_id : req id for err to be injected
* @dev_hdl : dev_hdl for the context
* @err_type: error type for error request
* @err_code: error code for error request
* @hw_id : hw id representing hw nodes of type cam_common_err_inject_hw_id
*/
struct cam_err_inject_param {
struct list_head list;
uint64_t req_id;
uint64_t dev_hdl;
uint32_t err_type;
uint32_t err_code;
uint8_t hw_id;
};
/**
* struct cam_common_err_inject_info
* @err_inject_cb : address of callback
* @active_err_ctx_list: list containing active err inject requests
* @num_hw_registered : number of callbacks registered
* @is_list_initialised: bool to check init for err_inject list
*/
struct cam_common_err_inject_info {
cam_common_err_inject_cb err_inject_cb[CAM_COMMON_ERR_INJECT_HW_MAX];
struct list_head active_err_ctx_list;
uint8_t num_hw_registered;
bool is_list_initialised;
};
/**
* struct cam_common_hw_dump_args
* @req_id : request id
@@ -258,4 +314,18 @@ int cam_common_user_dump_helper(
const char *tag,
...);
/**
* cam_common_register_err_inject_cb()
*
* @brief common interface to register error inject cb
*
* @err_inject_cb: Pointer to err_inject_cb
* @hw_id: HW id of the HW driver registering
*
* @return: 0 if success in register non-zero if failes
*/
int cam_common_register_err_inject_cb(
cam_common_err_inject_cb err_inject_cb,
enum cam_common_err_inject_hw_id hw_id);
#endif /* _CAM_COMMON_UTIL_H_ */