Sfoglia il codice sorgente

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 <[email protected]>
Pranav Sanwal 3 anni fa
parent
commit
1220255b08

+ 28 - 0
drivers/cam_core/cam_context.c

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

+ 17 - 0
drivers/cam_core/cam_context.h

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

+ 20 - 0
drivers/cam_core/cam_context_utils.c

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

+ 1 - 0
drivers/cam_core/cam_context_utils.h

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

+ 21 - 0
drivers/cam_core/cam_hw_mgr_intf.h

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

+ 47 - 0
drivers/cam_icp/cam_icp_context.c

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

+ 21 - 0
drivers/cam_icp/cam_icp_subdev.c

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

+ 46 - 0
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.c

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

+ 2 - 0
drivers/cam_icp/icp_hw/icp_hw_mgr/cam_icp_hw_mgr.h

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

+ 95 - 0
drivers/cam_isp/cam_isp_context.c

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

+ 1 - 0
drivers/cam_isp/cam_isp_context.h

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

+ 19 - 0
drivers/cam_isp/cam_isp_dev.c

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

+ 55 - 0
drivers/cam_jpeg/cam_jpeg_context.c

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

+ 20 - 0
drivers/cam_jpeg/cam_jpeg_dev.c

@@ -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) {

+ 44 - 0
drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.c

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

+ 2 - 0
drivers/cam_jpeg/jpeg_hw/cam_jpeg_hw_mgr.h

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

+ 201 - 0
drivers/cam_utils/cam_common_util.c

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

+ 70 - 0
drivers/cam_utils/cam_common_util.h

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