Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 5db11533 authored by Shravya Samala's avatar Shravya Samala Committed by Gerrit - the friendly Code Review server
Browse files

msm: camera: isp: Added CSID recovery mechanism



CSID is not able to recover from the fatal errors like lane
overflows, continuous unbound frames and ESD errors. To recover
from such errors, it is necessary to restart the sensor as
just starting the ISP hw do not make any change as the sensor
can still be in bad state.
This commit implements tasklet based CSID recovery mechanism.
On detecting an error in CSID interrupt, tasklet is scheduled
which in turn will call the ISP hw manager to notify the ISP
context, from here a notification is sent to CRM to send a
message to trigger full recovery. This full recovery includes
the sensor release and start.
This feature is debugfs based. Based on need this can be turned
on.

CRs-Fixed: 2674109
Change-Id: I7e4612e9bd24a20691146ae0b9dc6f77ccbc0714
Signed-off-by: default avatarShravya Samala <shravyas@codeaurora.org>
parent e5d41356
Loading
Loading
Loading
Loading
+8 −2
Original line number Diff line number Diff line
@@ -1818,8 +1818,14 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp,
		if (notify.error == CRM_KMD_ERR_FATAL) {
			req_msg.session_hdl = ctx_isp->base->session_hdl;
			req_msg.u.err_msg.device_hdl = ctx_isp->base->dev_hdl;

			if (error_type == CAM_ISP_HW_ERROR_CSID_FATAL)
				req_msg.u.err_msg.error_type =
					CAM_REQ_MGR_ERROR_TYPE_FULL_RECOVERY;
			else
				req_msg.u.err_msg.error_type =
					CAM_REQ_MGR_ERROR_TYPE_RECOVERY;

			req_msg.u.err_msg.link_hdl = ctx_isp->base->link_hdl;
			req_msg.u.err_msg.request_id = error_request_id;
			req_msg.u.err_msg.resource_size = 0x0;
+64 −3
Original line number Diff line number Diff line
@@ -1918,6 +1918,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_pxl(
		csid_acquire.in_port = in_port;
		csid_acquire.out_port = in_port->data;
		csid_acquire.node_res = NULL;
		csid_acquire.event_cb = cam_ife_hw_mgr_event_handler;
		csid_acquire.priv = ife_ctx;
		csid_acquire.crop_enable = crop_enable;
		csid_acquire.drop_enable = false;

@@ -2046,6 +2048,8 @@ static int cam_ife_hw_mgr_acquire_res_ife_csid_rdi(
		csid_acquire.in_port = in_port;
		csid_acquire.out_port = out_port;
		csid_acquire.node_res = NULL;
		csid_acquire.event_cb = cam_ife_hw_mgr_event_handler;
		csid_acquire.priv = ife_ctx;

		/*
		 * Enable RDI pixel drop by default. CSID will enable only for
@@ -6363,6 +6367,12 @@ static int cam_ife_hw_mgr_find_affected_ctx(
			affected_core, CAM_IFE_HW_NUM_MAX))
			continue;

		if (atomic_read(&ife_hwr_mgr_ctx->overflow_pending)) {
			CAM_INFO(CAM_ISP, "CTX:%d already error reported",
				ife_hwr_mgr_ctx->ctx_index);
			continue;
		}

		atomic_set(&ife_hwr_mgr_ctx->overflow_pending, 1);
		notify_err_cb = ife_hwr_mgr_ctx->common.event_cb[event_type];

@@ -6378,8 +6388,13 @@ static int cam_ife_hw_mgr_find_affected_ctx(
		 * In the call back function corresponding ISP context
		 * will update CRM about fatal Error
		 */
		if (notify_err_cb) {
			notify_err_cb(ife_hwr_mgr_ctx->common.cb_priv,
				CAM_ISP_HW_EVENT_ERROR, error_event_data);
		} else {
			CAM_WARN(CAM_ISP, "Error call back is not set");
			goto end;
		}
	}

	/* fill the affected_core in recovery data */
@@ -6388,7 +6403,34 @@ static int cam_ife_hw_mgr_find_affected_ctx(
		CAM_DBG(CAM_ISP, "Vfe core %d is affected (%d)",
			 i, recovery_data->affected_core[i]);
	}
end:
	return 0;
}

static int cam_ife_hw_mgr_handle_csid_event(
	struct cam_isp_hw_event_info *event_info)
{
	struct cam_isp_hw_error_event_data  error_event_data = {0};
	struct cam_ife_hw_event_recovery_data     recovery_data = {0};

	/* this can be extended based on the types of error
	 * received from CSID
	 */
	switch (event_info->err_type) {
	case CAM_ISP_HW_ERROR_CSID_FATAL: {

		if (!g_ife_hw_mgr.debug_cfg.enable_csid_recovery)
			break;

		error_event_data.error_type = event_info->err_type;
		cam_ife_hw_mgr_find_affected_ctx(&error_event_data,
			event_info->hw_idx,
			&recovery_data);
		break;
	}
	default:
		break;
	}
	return 0;
}

@@ -6408,6 +6450,13 @@ static int cam_ife_hw_mgr_handle_hw_err(
	else if (event_info->res_type == CAM_ISP_RESOURCE_VFE_OUT)
		error_event_data.error_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW;

	spin_lock(&g_ife_hw_mgr.ctx_lock);
	if (event_info->err_type == CAM_ISP_HW_ERROR_CSID_FATAL) {
		rc = cam_ife_hw_mgr_handle_csid_event(event_info);
		spin_unlock(&g_ife_hw_mgr.ctx_lock);
		return rc;
	}

	core_idx = event_info->hw_idx;

	if (g_ife_hw_mgr.debug_cfg.enable_recovery)
@@ -6418,6 +6467,8 @@ static int cam_ife_hw_mgr_handle_hw_err(

	rc = cam_ife_hw_mgr_find_affected_ctx(&error_event_data,
		core_idx, &recovery_data);
	if (rc || !(recovery_data.no_of_context))
		goto end;

	if (event_info->err_type == CAM_VFE_IRQ_STATUS_VIOLATION)
		recovery_data.error_type = CAM_ISP_HW_ERROR_VIOLATION;
@@ -6425,7 +6476,8 @@ static int cam_ife_hw_mgr_handle_hw_err(
		recovery_data.error_type = CAM_ISP_HW_ERROR_OVERFLOW;

	cam_ife_hw_mgr_do_error_recovery(&recovery_data);

end:
	spin_unlock(&g_ife_hw_mgr.ctx_lock);
	return rc;
}

@@ -6875,6 +6927,14 @@ static int cam_ife_hw_mgr_debug_register(void)
		goto err;
	}

	if (!debugfs_create_u32("enable_csid_recovery",
		0644,
		g_ife_hw_mgr.debug_cfg.dentry,
		&g_ife_hw_mgr.debug_cfg.enable_csid_recovery)) {
		CAM_ERR(CAM_ISP, "failed to create enable_csid_recovery");
		goto err;
	}

	if (!debugfs_create_bool("enable_req_dump",
		0644,
		g_ife_hw_mgr.debug_cfg.dentry,
@@ -6921,6 +6981,7 @@ int cam_ife_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
	memset(&g_ife_hw_mgr, 0, sizeof(g_ife_hw_mgr));

	mutex_init(&g_ife_hw_mgr.ctx_mutex);
	spin_lock_init(&g_ife_hw_mgr.ctx_lock);

	if (CAM_IFE_HW_NUM_MAX != CAM_IFE_CSID_HW_NUM_MAX) {
		CAM_ERR(CAM_ISP, "CSID num is different then IFE num");
+4 −0
Original line number Diff line number Diff line
@@ -24,6 +24,7 @@
 * @dentry:                    Debugfs entry
 * @csid_debug:                csid debug information
 * @enable_recovery:           enable recovery
 * @enable_csid_recovery:      enable csid recovery
 * @enable_diag_sensor_status: enable sensor diagnosis status
 * @enable_req_dump:           Enable request dump on HW errors
 * @per_req_reg_dump:          Enable per request reg dump
@@ -33,6 +34,7 @@ struct cam_ife_hw_mgr_debug {
	struct dentry  *dentry;
	uint64_t       csid_debug;
	uint32_t       enable_recovery;
	uint32_t       enable_csid_recovery;
	uint32_t       camif_debug;
	bool           enable_req_dump;
	bool           per_req_reg_dump;
@@ -148,6 +150,7 @@ struct cam_ife_hw_mgr_ctx {
 * @ife_dev_caps           ife device capability per core
 * @work q                 work queue for IFE hw manager
 * @debug_cfg              debug configuration
 * @ctx_lock               Spinlock for HW manager
 */
struct cam_ife_hw_mgr {
	struct cam_isp_hw_mgr          mgr_common;
@@ -166,6 +169,7 @@ struct cam_ife_hw_mgr {
	struct cam_vfe_hw_get_hw_cap   ife_dev_caps[CAM_IFE_HW_NUM_MAX];
	struct cam_req_mgr_core_workq *workq;
	struct cam_ife_hw_mgr_debug    debug_cfg;
	spinlock_t                     ctx_lock;
};

/**
+64 −3
Original line number Diff line number Diff line
@@ -1458,6 +1458,8 @@ static int cam_tfe_hw_mgr_acquire_res_tfe_csid_rdi(
		csid_acquire.out_port = out_port;
		csid_acquire.sync_mode = CAM_ISP_HW_SYNC_NONE;
		csid_acquire.node_res = NULL;
		csid_acquire.event_cb = cam_tfe_hw_mgr_event_handler;
		csid_acquire.event_cb_prv = tfe_ctx;

		if (tfe_ctx->is_tpg) {
			if (tfe_ctx->res_list_tpg.hw_res[0]->hw_intf->hw_idx ==
@@ -4904,6 +4906,12 @@ static int cam_tfe_hw_mgr_find_affected_ctx(
			affected_core, CAM_TFE_HW_NUM_MAX))
			continue;

		if (atomic_read(&tfe_hwr_mgr_ctx->overflow_pending)) {
			CAM_INFO(CAM_ISP, "CTX:%d already error reported",
				tfe_hwr_mgr_ctx->ctx_index);
			continue;
		}

		atomic_set(&tfe_hwr_mgr_ctx->overflow_pending, 1);
		notify_err_cb = tfe_hwr_mgr_ctx->common.event_cb[event_type];

@@ -4919,8 +4927,13 @@ static int cam_tfe_hw_mgr_find_affected_ctx(
		 * In the call back function corresponding ISP context
		 * will update CRM about fatal Error
		 */
		if (notify_err_cb) {
			notify_err_cb(tfe_hwr_mgr_ctx->common.cb_priv,
			CAM_ISP_HW_EVENT_ERROR, error_event_data);
		} else {
			CAM_WARN(CAM_ISP, "Error call back is not set");
			goto end;
		}
	}

	/* fill the affected_core in recovery data */
@@ -4929,7 +4942,34 @@ static int cam_tfe_hw_mgr_find_affected_ctx(
		CAM_DBG(CAM_ISP, "tfe core %d is affected (%d)",
			 i, recovery_data->affected_core[i]);
	}
end:
	return 0;
}

static int cam_tfe_hw_mgr_handle_csid_event(
	struct cam_isp_hw_event_info *event_info)
{
	struct cam_isp_hw_error_event_data  error_event_data = {0};
	struct cam_tfe_hw_event_recovery_data     recovery_data = {0};

	/* this can be extended based on the types of error
	 * received from CSID
	 */
	switch (event_info->err_type) {
	case CAM_ISP_HW_ERROR_CSID_FATAL: {

		if (!g_tfe_hw_mgr.debug_cfg.enable_csid_recovery)
			break;

		error_event_data.error_type = event_info->err_type;
		cam_tfe_hw_mgr_find_affected_ctx(&error_event_data,
			event_info->hw_idx,
			&recovery_data);
		break;
	}
	default:
		break;
	}
	return 0;
}

@@ -4950,6 +4990,13 @@ static int cam_tfe_hw_mgr_handle_hw_err(
	else if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT)
		error_event_data.error_type = CAM_ISP_HW_ERROR_BUSIF_OVERFLOW;

	spin_lock(&g_tfe_hw_mgr.ctx_lock);
	if (event_info->err_type == CAM_ISP_HW_ERROR_CSID_FATAL) {
		rc = cam_tfe_hw_mgr_handle_csid_event(event_info);
		spin_unlock(&g_tfe_hw_mgr.ctx_lock);
		return rc;
	}

	core_idx = event_info->hw_idx;

	if (g_tfe_hw_mgr.debug_cfg.enable_recovery)
@@ -4959,9 +5006,13 @@ static int cam_tfe_hw_mgr_handle_hw_err(

	rc = cam_tfe_hw_mgr_find_affected_ctx(&error_event_data,
		core_idx, &recovery_data);
	if (rc || !(recovery_data.no_of_context))
		goto end;

	if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT)
	if (event_info->res_type == CAM_ISP_RESOURCE_TFE_OUT) {
		spin_unlock(&g_tfe_hw_mgr.ctx_lock);
		return rc;
	}

	if (g_tfe_hw_mgr.debug_cfg.enable_recovery) {
		/* Trigger for recovery */
@@ -4974,7 +5025,8 @@ static int cam_tfe_hw_mgr_handle_hw_err(
		CAM_DBG(CAM_ISP, "recovery is not enabled");
		rc = 0;
	}

end:
	spin_unlock(&g_tfe_hw_mgr.ctx_lock);
	return rc;
}

@@ -5422,6 +5474,14 @@ static int cam_tfe_hw_mgr_debug_register(void)
		goto err;
	}

	if (!debugfs_create_u32("enable_csid_recovery",
		0644,
		g_tfe_hw_mgr.debug_cfg.dentry,
		&g_tfe_hw_mgr.debug_cfg.enable_csid_recovery)) {
		CAM_ERR(CAM_ISP, "failed to create enable_csid_recovery");
		goto err;
	}

	if (!debugfs_create_u32("enable_reg_dump",
		0644,
		g_tfe_hw_mgr.debug_cfg.dentry,
@@ -5469,6 +5529,7 @@ int cam_tfe_hw_mgr_init(struct cam_hw_mgr_intf *hw_mgr_intf, int *iommu_hdl)
	memset(&g_tfe_hw_mgr, 0, sizeof(g_tfe_hw_mgr));

	mutex_init(&g_tfe_hw_mgr.ctx_mutex);
	spin_lock_init(&g_tfe_hw_mgr.ctx_lock);

	if (CAM_TFE_HW_NUM_MAX != CAM_TFE_CSID_HW_NUM_MAX) {
		CAM_ERR(CAM_ISP, "CSID num is different then TFE num");
+4 −0
Original line number Diff line number Diff line
@@ -28,6 +28,7 @@
 * @dentry:                    Debugfs entry
 * @csid_debug:                csid debug information
 * @enable_recovery:           enable recovery
 * @enable_csid_recovery:      enable csid recovery
 * @camif_debug:               enable sensor diagnosis status
 * @enable_reg_dump:           enable reg dump on error;
 * @per_req_reg_dump:          Enable per request reg dump
@@ -37,6 +38,7 @@ struct cam_tfe_hw_mgr_debug {
	struct dentry  *dentry;
	uint64_t       csid_debug;
	uint32_t       enable_recovery;
	uint32_t       enable_csid_recovery;
	uint32_t       camif_debug;
	uint32_t       enable_reg_dump;
	uint32_t       per_req_reg_dump;
@@ -152,6 +154,7 @@ struct cam_tfe_hw_mgr_ctx {
 * @tfe_dev_caps           tfe device capability per core
 * @work q                 work queue for TFE hw manager
 * @debug_cfg              debug configuration
 * @ctx_lock               Spinlock for HW manager
 */
struct cam_tfe_hw_mgr {
	struct cam_isp_hw_mgr          mgr_common;
@@ -170,6 +173,7 @@ struct cam_tfe_hw_mgr {
	struct cam_tfe_hw_get_hw_cap   tfe_dev_caps[CAM_TFE_HW_NUM_MAX];
	struct cam_req_mgr_core_workq *workq;
	struct cam_tfe_hw_mgr_debug    debug_cfg;
	spinlock_t                     ctx_lock;
};

/**
Loading