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

Commit fdfa5bac authored by Alok Pandey's avatar Alok Pandey Committed by Karthik Anantha Ram
Browse files

msm: camera: isp: Add support for overflow handling



This change provides support for vfe bus overflow recovery.

Change-Id: Ie9c107a31fa5649c544dd5c30827ad4c04971d58
Signed-off-by: default avatarAlok Pandey <akumarpa@codeaurora.org>
Signed-off-by: default avatarSoundrapandian Jeyaprakash <jsoundra@codeaurora.org>
parent 6b7576b8
Loading
Loading
Loading
Loading
+104 −19
Original line number Original line Diff line number Diff line
@@ -427,6 +427,13 @@ static int __cam_isp_ctx_notify_eof_in_actived_state(
	return rc;
	return rc;
}
}


static int __cam_isp_ctx_reg_upd_in_hw_error(
	struct cam_isp_context *ctx_isp, void *evt_data)
{
	ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF;
	return 0;
}

static int __cam_isp_ctx_sof_in_activated_state(
static int __cam_isp_ctx_sof_in_activated_state(
	struct cam_isp_context *ctx_isp, void *evt_data)
	struct cam_isp_context *ctx_isp, void *evt_data)
{
{
@@ -689,8 +696,13 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp,
	void *evt_data)
	void *evt_data)
{
{
	int                              rc = 0;
	int                              rc = 0;
	struct cam_ctx_request          *req;
	uint32_t                         i = 0;
	bool                             found = 0;
	struct cam_ctx_request          *req = NULL;
	struct cam_ctx_request          *req_temp;
	struct cam_isp_ctx_req          *req_isp = NULL;
	struct cam_req_mgr_error_notify  notify;
	struct cam_req_mgr_error_notify  notify;
	uint64_t                         error_request_id;


	struct cam_context *ctx = ctx_isp->base;
	struct cam_context *ctx = ctx_isp->base;
	struct cam_isp_hw_error_event_data  *error_event_data =
	struct cam_isp_hw_error_event_data  *error_event_data =
@@ -701,7 +713,7 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp,
	CAM_DBG(CAM_ISP, "Enter error_type = %d", error_type);
	CAM_DBG(CAM_ISP, "Enter error_type = %d", error_type);
	if ((error_type == CAM_ISP_HW_ERROR_OVERFLOW) ||
	if ((error_type == CAM_ISP_HW_ERROR_OVERFLOW) ||
		(error_type == CAM_ISP_HW_ERROR_BUSIF_OVERFLOW))
		(error_type == CAM_ISP_HW_ERROR_BUSIF_OVERFLOW))
		notify.error = CRM_KMD_ERR_FATAL;
		notify.error = CRM_KMD_ERR_OVERFLOW;


	/*
	/*
	 * Need to check the active req
	 * Need to check the active req
@@ -712,31 +724,92 @@ static int __cam_isp_ctx_handle_error(struct cam_isp_context *ctx_isp,
	if (list_empty(&ctx->active_req_list)) {
	if (list_empty(&ctx->active_req_list)) {
		CAM_ERR_RATE_LIMIT(CAM_ISP,
		CAM_ERR_RATE_LIMIT(CAM_ISP,
			"handling error with no active request");
			"handling error with no active request");
		rc = -EINVAL;
	} else {
		goto end;
		list_for_each_entry_safe(req, req_temp,
			&ctx->active_req_list, list) {
			req_isp = (struct cam_isp_ctx_req *) req->req_priv;
			if (!req_isp->bubble_report) {
				for (i = 0; i < req_isp->num_fence_map_out;
					i++) {
					CAM_ERR(CAM_ISP, "req %llu, Sync fd %x",
						req->request_id,
						req_isp->fence_map_out[i].
						sync_id);
					if (req_isp->fence_map_out[i].sync_id
						!= -1) {
						rc = cam_sync_signal(
						req_isp->fence_map_out[i].
						sync_id,
						CAM_SYNC_STATE_SIGNALED_ERROR);
						req_isp->fence_map_out[i].
						sync_id = -1;
					}
				}
				list_del_init(&req->list);
				list_add_tail(&req->list, &ctx->free_req_list);
				ctx_isp->active_req_cnt--;
			} else {
				found = 1;
				break;
			}
		}
	}
	}


	req = list_first_entry(&ctx->active_req_list,
	if (found) {
		list_for_each_entry_safe_reverse(req, req_temp,
			&ctx->active_req_list, list) {
			req_isp = (struct cam_isp_ctx_req *) req->req_priv;
			list_del_init(&req->list);
			list_add(&req->list, &ctx->pending_req_list);
			ctx_isp->active_req_cnt--;
		}
	}

	do {
		if (list_empty(&ctx->pending_req_list)) {
			error_request_id = ctx_isp->last_applied_req_id + 1;
			req_isp = NULL;
			break;
		}
		req = list_first_entry(&ctx->pending_req_list,
			struct cam_ctx_request, list);
			struct cam_ctx_request, list);
		req_isp = (struct cam_isp_ctx_req *) req->req_priv;
		error_request_id = ctx_isp->last_applied_req_id;

		if (req_isp->bubble_report)
			break;

		for (i = 0; i < req_isp->num_fence_map_out; i++) {
			if (req_isp->fence_map_out[i].sync_id != -1)
				rc = cam_sync_signal(
					req_isp->fence_map_out[i].sync_id,
					CAM_SYNC_STATE_SIGNALED_ERROR);
			req_isp->fence_map_out[i].sync_id = -1;
		}
		list_del_init(&req->list);
		list_add_tail(&req->list, &ctx->free_req_list);

	} while (req->request_id < ctx_isp->last_applied_req_id);



	if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) {
	if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_err) {
		notify.link_hdl = ctx->link_hdl;
		notify.link_hdl = ctx->link_hdl;
		notify.dev_hdl = ctx->dev_hdl;
		notify.dev_hdl = ctx->dev_hdl;
		notify.req_id = req->request_id;
		notify.req_id = error_request_id;

		if (req_isp && req_isp->bubble_report)
			notify.error = CRM_KMD_ERR_BUBBLE;

		CAM_WARN(CAM_ISP, "Notify CRM: req %lld, frame %lld\n",
			error_request_id, ctx_isp->frame_id);


		ctx->ctx_crm_intf->notify_err(&notify);
		ctx->ctx_crm_intf->notify_err(&notify);
		CAM_ERR_RATE_LIMIT(CAM_ISP, "Notify CRM about ERROR frame %lld",
		ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HW_ERROR;
			ctx_isp->frame_id);
	} else {
	} else {
		CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify ERRROR to CRM");
		CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not notify ERRROR to CRM");
		rc = -EFAULT;
		rc = -EFAULT;
	}
	}


	list_del_init(&req->list);
	list_add(&req->list, &ctx->pending_req_list);
	/* might need to check if active list is empty */

end:
	CAM_DBG(CAM_ISP, "Exit");
	CAM_DBG(CAM_ISP, "Exit");
	return rc;
	return rc;
}
}
@@ -746,7 +819,7 @@ static struct cam_isp_ctx_irq_ops
	/* SOF */
	/* SOF */
	{
	{
		.irq_ops = {
		.irq_ops = {
			NULL,
			__cam_isp_ctx_handle_error,
			__cam_isp_ctx_sof_in_activated_state,
			__cam_isp_ctx_sof_in_activated_state,
			__cam_isp_ctx_reg_upd_in_sof,
			__cam_isp_ctx_reg_upd_in_sof,
			__cam_isp_ctx_notify_sof_in_actived_state,
			__cam_isp_ctx_notify_sof_in_actived_state,
@@ -779,7 +852,7 @@ static struct cam_isp_ctx_irq_ops
	/* BUBBLE */
	/* BUBBLE */
	{
	{
		.irq_ops = {
		.irq_ops = {
			NULL,
			__cam_isp_ctx_handle_error,
			__cam_isp_ctx_sof_in_activated_state,
			__cam_isp_ctx_sof_in_activated_state,
			NULL,
			NULL,
			__cam_isp_ctx_notify_sof_in_actived_state,
			__cam_isp_ctx_notify_sof_in_actived_state,
@@ -790,7 +863,7 @@ static struct cam_isp_ctx_irq_ops
	/* Bubble Applied */
	/* Bubble Applied */
	{
	{
		.irq_ops = {
		.irq_ops = {
			NULL,
			__cam_isp_ctx_handle_error,
			__cam_isp_ctx_sof_in_activated_state,
			__cam_isp_ctx_sof_in_activated_state,
			__cam_isp_ctx_reg_upd_in_activated_state,
			__cam_isp_ctx_reg_upd_in_activated_state,
			__cam_isp_ctx_epoch_in_bubble_applied,
			__cam_isp_ctx_epoch_in_bubble_applied,
@@ -798,6 +871,17 @@ static struct cam_isp_ctx_irq_ops
			__cam_isp_ctx_buf_done_in_bubble_applied,
			__cam_isp_ctx_buf_done_in_bubble_applied,
		},
		},
	},
	},
	/* HW ERROR */
	{
		.irq_ops = {
			NULL,
			__cam_isp_ctx_sof_in_activated_state,
			__cam_isp_ctx_reg_upd_in_hw_error,
			NULL,
			NULL,
			NULL,
		},
	},
	/* HALT */
	/* HALT */
	{
	{
	},
	},
@@ -878,7 +962,9 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
	} else {
	} else {
		spin_lock_bh(&ctx->lock);
		spin_lock_bh(&ctx->lock);
		ctx_isp->substate_activated = next_state;
		ctx_isp->substate_activated = next_state;
		CAM_DBG(CAM_ISP, "new state %d", next_state);
		ctx_isp->last_applied_req_id = apply->request_id;
		CAM_DBG(CAM_ISP, "new substate state %d, applied req %lld",
			next_state, ctx_isp->last_applied_req_id);
		spin_unlock_bh(&ctx->lock);
		spin_unlock_bh(&ctx->lock);
	}
	}
end:
end:
@@ -2203,4 +2289,3 @@ int cam_isp_context_deinit(struct cam_isp_context *ctx)
	memset(ctx, 0, sizeof(*ctx));
	memset(ctx, 0, sizeof(*ctx));
	return rc;
	return rc;
}
}
+3 −0
Original line number Original line Diff line number Diff line
@@ -50,6 +50,7 @@ enum cam_isp_ctx_activated_substate {
	CAM_ISP_CTX_ACTIVATED_EPOCH,
	CAM_ISP_CTX_ACTIVATED_EPOCH,
	CAM_ISP_CTX_ACTIVATED_BUBBLE,
	CAM_ISP_CTX_ACTIVATED_BUBBLE,
	CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED,
	CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED,
	CAM_ISP_CTX_ACTIVATED_HW_ERROR,
	CAM_ISP_CTX_ACTIVATED_HALT,
	CAM_ISP_CTX_ACTIVATED_HALT,
	CAM_ISP_CTX_ACTIVATED_MAX,
	CAM_ISP_CTX_ACTIVATED_MAX,
};
};
@@ -111,6 +112,7 @@ struct cam_isp_ctx_req {
 * @reported_req_id:       Last reported request id
 * @reported_req_id:       Last reported request id
 * @subscribe_event:       The irq event mask that CRM subscribes to, IFE will
 * @subscribe_event:       The irq event mask that CRM subscribes to, IFE will
 *                         invoke CRM cb at those event.
 *                         invoke CRM cb at those event.
 * @last_applied_req_id:   Last applied request id
 *
 *
 */
 */
struct cam_isp_context {
struct cam_isp_context {
@@ -129,6 +131,7 @@ struct cam_isp_context {
	int32_t                          active_req_cnt;
	int32_t                          active_req_cnt;
	int64_t                          reported_req_id;
	int64_t                          reported_req_id;
	uint32_t                         subscribe_event;
	uint32_t                         subscribe_event;
	int64_t                          last_applied_req_id;
};
};


/**
/**
+256 −96

File changed.

Preview size limit exceeded, changes collapsed.

+5 −2
Original line number Original line Diff line number Diff line
@@ -85,11 +85,13 @@ struct ctx_base_info {
 *
 *
 * @dentry:              Debugfs entry
 * @dentry:              Debugfs entry
 * @csid_debug:          csid debug information
 * @csid_debug:          csid debug information
 * @enable_recovery      enable recovery
 *
 *
 */
 */
struct cam_ife_hw_mgr_debug {
struct cam_ife_hw_mgr_debug {
	struct dentry  *dentry;
	struct dentry  *dentry;
	uint64_t       csid_debug;
	uint64_t       csid_debug;
	uint32_t       enable_recovery;
};
};


/**
/**
@@ -171,6 +173,7 @@ struct cam_ife_hw_mgr_ctx {
 * @ife_csid_dev_caps      csid device capability stored per core
 * @ife_csid_dev_caps      csid device capability stored per core
 * @ife_dev_caps           ife device capability per core
 * @ife_dev_caps           ife device capability per core
 * @work q                 work queue for IFE hw manager
 * @work q                 work queue for IFE hw manager
 * @debug_cfg              debug configuration
 */
 */
struct cam_ife_hw_mgr {
struct cam_ife_hw_mgr {
	struct cam_isp_hw_mgr          mgr_common;
	struct cam_isp_hw_mgr          mgr_common;
+10 −0
Original line number Original line Diff line number Diff line
@@ -261,6 +261,15 @@ void cam_tasklet_deinit(void **tasklet_info)
	*tasklet_info = NULL;
	*tasklet_info = NULL;
}
}


static void cam_tasklet_flush(void  *tasklet_info)
{
	unsigned long data;
	struct cam_tasklet_info *tasklet = tasklet_info;

	data = (unsigned long)tasklet;
	cam_tasklet_action(data);
}

int cam_tasklet_start(void  *tasklet_info)
int cam_tasklet_start(void  *tasklet_info)
{
{
	struct cam_tasklet_info       *tasklet = tasklet_info;
	struct cam_tasklet_info       *tasklet = tasklet_info;
@@ -290,6 +299,7 @@ void cam_tasklet_stop(void *tasklet_info)
{
{
	struct cam_tasklet_info  *tasklet = tasklet_info;
	struct cam_tasklet_info  *tasklet = tasklet_info;


	cam_tasklet_flush(tasklet);
	atomic_set(&tasklet->tasklet_active, 0);
	atomic_set(&tasklet->tasklet_active, 0);
	tasklet_disable(&tasklet->tasklet);
	tasklet_disable(&tasklet->tasklet);
}
}
Loading