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

Commit 78b8ee08 authored by Tejas Prajapati's avatar Tejas Prajapati
Browse files

msm: camera: isp: Reapply bubble request in RDI path



For recovery of the bubble the request from active list
should be added back to pending request list.

Re-apply bubble request if buf done has not come for
two bubble frames. Also before re-submitting the
request to CDM check if CDM callback for that
request has come or not, if CDM callback is received
then wait for buf done else reset CDM and re-submit
the request to CDM.

CRs-Fixed: 2886414
Change-Id: If7daf738b680ffe651340c014122b15f6beda75c
Signed-off-by: default avatarTejas Prajapati <tpraja@codeaurora.org>
parent ef11e3f7
Loading
Loading
Loading
Loading
+12 −9
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
 */

#ifndef _CAM_HW_MGR_INTF_H_
@@ -242,7 +242,9 @@ struct cam_hw_stream_setttings {
 * @num_out_map_entries:       Number of out map entries
 * @priv:                      Private pointer
 * @request_id:                Request ID
 * @reapply                True if reapplying after bubble
 * @reapply:                   True if reapplying after bubble
 * @cdm_reset_before_apply:    True is need to reset CDM before re-apply bubble
 *                             request
 *
 */
struct cam_hw_config_args {
@@ -255,6 +257,7 @@ struct cam_hw_config_args {
	uint64_t                        request_id;
	bool                            init_packet;
	bool                            reapply;
	bool                            cdm_reset_before_apply;
};

/**
+143 −14
Original line number Diff line number Diff line
@@ -893,6 +893,8 @@ static int __cam_isp_ctx_handle_buf_done_for_request(
		req_isp->bubble_detected = false;
		list_del_init(&req->list);
		atomic_set(&ctx_isp->process_bubble, 0);
		req_isp->cdm_reset_before_apply = false;
		ctx_isp->bubble_frame_cnt = 0;

		if (buf_done_req_id <= ctx->last_flush_req) {
			for (i = 0; i < req_isp->num_fence_map_out; i++)
@@ -926,6 +928,7 @@ static int __cam_isp_ctx_handle_buf_done_for_request(
		list_del_init(&req->list);
		list_add_tail(&req->list, &ctx->free_req_list);
		req_isp->reapply = false;
		req_isp->cdm_reset_before_apply = false;

		CAM_DBG(CAM_REQ,
			"Move active request %lld to free list(cnt = %d) [all fences done], ctx %u",
@@ -1208,6 +1211,10 @@ static int __cam_isp_ctx_notify_sof_in_activated_state(
	struct cam_context *ctx = ctx_isp->base;
	struct cam_ctx_request  *req;
	struct cam_isp_ctx_req  *req_isp;
	struct cam_hw_cmd_args   hw_cmd_args;
	struct cam_isp_hw_cmd_args  isp_hw_cmd_args;
	uint64_t last_cdm_done_req = 0;

	struct cam_isp_hw_epoch_event_data *epoch_done_event_data =
			(struct cam_isp_hw_epoch_event_data *)evt_data;

@@ -1250,9 +1257,37 @@ static int __cam_isp_ctx_notify_sof_in_activated_state(

		if (ctx_isp->bubble_frame_cnt >= 1 &&
			req_isp->bubble_detected) {
			hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
			hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL;
			isp_hw_cmd_args.cmd_type =
				CAM_ISP_HW_MGR_GET_LAST_CDM_DONE;
			hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args;
			rc = ctx->hw_mgr_intf->hw_cmd(
				ctx->hw_mgr_intf->hw_mgr_priv,
				&hw_cmd_args);
			if (rc) {
				CAM_ERR(CAM_ISP,
				"HW command failed to get last CDM done");
				return rc;
			}

			last_cdm_done_req = isp_hw_cmd_args.u.last_cdm_done;
			CAM_DBG(CAM_ISP, "last_cdm_done req: %d",
				last_cdm_done_req);

			if (last_cdm_done_req >= req->request_id) {
				CAM_INFO_RATE_LIMIT(CAM_ISP,
					"CDM callback detected for req: %lld, possible buf_done delay, waiting for buf_done",
					req->request_id);
				ctx_isp->bubble_frame_cnt = 0;
			} else {
				CAM_DBG(CAM_ISP,
					"CDM callback not happened for req: %lld, possible CDM stuck or workqueue delay",
					req->request_id);
				req_isp->num_acked = 0;
				ctx_isp->bubble_frame_cnt = 0;
				req_isp->bubble_detected = false;
				req_isp->cdm_reset_before_apply = true;
				list_del_init(&req->list);
				list_add(&req->list, &ctx->pending_req_list);
				atomic_set(&ctx_isp->process_bubble, 0);
@@ -1261,6 +1296,7 @@ static int __cam_isp_ctx_notify_sof_in_activated_state(
					"Move active req: %lld to pending list(cnt = %d) [bubble re-apply],ctx %u",
					req->request_id,
					ctx_isp->active_req_cnt, ctx->ctx_id);
			}
		} else if (req_isp->bubble_detected) {
			if (ctx_isp->last_sof_timestamp !=
				ctx_isp->sof_timestamp_val) {
@@ -1492,6 +1528,7 @@ static int __cam_isp_ctx_epoch_in_applied(struct cam_isp_context *ctx_isp,
	req_isp = (struct cam_isp_ctx_req *)req->req_priv;
	req_isp->bubble_detected = true;
	req_isp->reapply = true;
	req_isp->cdm_reset_before_apply = false;

	CAM_INFO(CAM_ISP, "ctx:%d Report Bubble flag %d req id:%lld",
		ctx->ctx_id, req_isp->bubble_report, req->request_id);
@@ -1678,6 +1715,7 @@ static int __cam_isp_ctx_epoch_in_bubble_applied(
	CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld",
		ctx->ctx_id, req_isp->bubble_report, req->request_id);
	req_isp->reapply = true;
	req_isp->cdm_reset_before_apply = false;

	if (req_isp->bubble_report && ctx->ctx_crm_intf &&
		ctx->ctx_crm_intf->notify_err) {
@@ -2545,11 +2583,10 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
	cfg.priv  = &req_isp->hw_update_data;
	cfg.init_packet = 0;
	cfg.reapply = req_isp->reapply;
	cfg.cdm_reset_before_apply = req_isp->cdm_reset_before_apply;

	rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg);
	if (rc) {
		CAM_ERR_RATE_LIMIT(CAM_ISP, "Can not apply the configuration");
	} else {
	if (!rc) {
		spin_lock_bh(&ctx->lock);
		ctx_isp->substate_activated = next_state;
		ctx_isp->last_applied_req_id = apply->request_id;
@@ -2565,6 +2602,22 @@ static int __cam_isp_ctx_apply_req_in_activated_state(
			req->request_id);
		__cam_isp_ctx_update_event_record(ctx_isp,
			CAM_ISP_CTX_EVENT_APPLY, req);
	} else if (rc == -EALREADY) {
		spin_lock_bh(&ctx->lock);
		req_isp->bubble_detected = true;
		req_isp->cdm_reset_before_apply = false;
		atomic_set(&ctx_isp->process_bubble, 1);
		list_del_init(&req->list);
		list_add(&req->list, &ctx->active_req_list);
		ctx_isp->active_req_cnt++;
		spin_unlock_bh(&ctx->lock);
		CAM_DBG(CAM_REQ,
			"move request %lld to active list(cnt = %d), ctx %u",
			req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id);
	} else {
		CAM_ERR_RATE_LIMIT(CAM_ISP,
			"ctx_id:%d ,Can not apply (req %lld) the configuration, rc %d",
			ctx->ctx_id, apply->request_id, rc);
	}
end:
	return rc;
@@ -2900,6 +2953,7 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx,
			}
		}
		req_isp->reapply = false;
		req_isp->cdm_reset_before_apply = false;
		list_del_init(&req->list);
		list_add_tail(&req->list, &ctx->free_req_list);
	}
@@ -3265,6 +3319,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied(
	CAM_INFO(CAM_ISP, "Ctx:%d Report Bubble flag %d req id:%lld",
		ctx->ctx_id, req_isp->bubble_report, req->request_id);
	req_isp->reapply = true;
	req_isp->cdm_reset_before_apply = false;

	if (req_isp->bubble_report && ctx->ctx_crm_intf &&
		ctx->ctx_crm_intf->notify_err) {
@@ -3285,6 +3340,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_applied(
			ctx_isp->frame_id,
			ctx->ctx_id);
		ctx->ctx_crm_intf->notify_err(&notify);
		atomic_set(&ctx_isp->process_bubble, 1);
	} else {
		req_isp->bubble_report = 0;
	}
@@ -3330,7 +3386,11 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state(
	struct cam_req_mgr_trigger_notify      notify;
	struct cam_isp_hw_sof_event_data      *sof_event_data = evt_data;
	struct cam_isp_ctx_req                *req_isp;
	struct cam_hw_cmd_args                 hw_cmd_args;
	struct cam_isp_hw_cmd_args             isp_hw_cmd_args;
	uint64_t                               request_id  = 0;
	uint64_t                               last_cdm_done_req = 0;
	int                                    rc = 0;

	if (!evt_data) {
		CAM_ERR(CAM_ISP, "in valid sof event data");
@@ -3342,6 +3402,71 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state(
	ctx_isp->boot_timestamp = sof_event_data->boot_time;
	CAM_DBG(CAM_ISP, "frame id: %lld time stamp:0x%llx",
		ctx_isp->frame_id, ctx_isp->sof_timestamp_val);


	if (atomic_read(&ctx_isp->process_bubble)) {
		if (list_empty(&ctx->active_req_list)) {
			CAM_ERR(CAM_ISP, "No available active req in bubble");
			atomic_set(&ctx_isp->process_bubble, 0);
			return -EINVAL;
		}

		if (ctx_isp->last_sof_timestamp ==
				ctx_isp->sof_timestamp_val) {
			CAM_DBG(CAM_ISP,
				"Tasklet delay detected! Bubble frame check skipped, sof_timestamp: %lld, ctx_id: %d",
				ctx_isp->sof_timestamp_val,
				ctx->ctx_id);
			goto end;
		}

		req = list_first_entry(&ctx->active_req_list,
				struct cam_ctx_request, list);
		req_isp = (struct cam_isp_ctx_req *) req->req_priv;

		if (req_isp->bubble_detected) {
			hw_cmd_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
			hw_cmd_args.cmd_type = CAM_HW_MGR_CMD_INTERNAL;
			isp_hw_cmd_args.cmd_type =
				CAM_ISP_HW_MGR_GET_LAST_CDM_DONE;
			hw_cmd_args.u.internal_args = (void *)&isp_hw_cmd_args;
			rc = ctx->hw_mgr_intf->hw_cmd(
				ctx->hw_mgr_intf->hw_mgr_priv,
				&hw_cmd_args);
			if (rc) {
				CAM_ERR(CAM_ISP,
				"HW command failed to get last CDM done");
				return rc;
			}

			last_cdm_done_req = isp_hw_cmd_args.u.last_cdm_done;
			CAM_DBG(CAM_ISP, "last_cdm_done req: %d ctx_id: %d",
				last_cdm_done_req, ctx->ctx_id);

			if (last_cdm_done_req >= req->request_id) {
				CAM_DBG(CAM_ISP,
					"CDM callback detected for req: %lld, possible buf_done delay, waiting for buf_done",
					req->request_id);
				goto end;
			} else {
				CAM_DBG(CAM_ISP,
					"CDM callback not happened for req: %lld, possible CDM stuck or workqueue delay",
					req->request_id);
				req_isp->num_acked = 0;
				req_isp->bubble_detected = false;
				req_isp->cdm_reset_before_apply = true;
				list_del_init(&req->list);
				list_add(&req->list, &ctx->pending_req_list);
				atomic_set(&ctx_isp->process_bubble, 0);
				ctx_isp->active_req_cnt--;
				CAM_DBG(CAM_REQ,
					"Move active req: %lld to pending list(cnt = %d) [bubble re-apply],ctx %u",
					req->request_id,
					ctx_isp->active_req_cnt, ctx->ctx_id);
			}
			goto end;
		}
	}
	/*
	 * Signal all active requests with error and move the  all the active
	 * requests to free list
@@ -3363,6 +3488,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state(
		ctx_isp->active_req_cnt--;
	}

end:
	/* notify reqmgr with sof signal */
	if (ctx->ctx_crm_intf && ctx->ctx_crm_intf->notify_trigger) {
		notify.link_hdl = ctx->link_hdl;
@@ -3393,6 +3519,7 @@ static int __cam_isp_ctx_rdi_only_sof_in_bubble_state(
		__cam_isp_ctx_substate_val_to_type(
		ctx_isp->substate_activated));

	ctx_isp->last_sof_timestamp = ctx_isp->sof_timestamp_val;
	return 0;
}

@@ -3857,6 +3984,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
	req_isp->num_fence_map_in = cfg.num_in_map_entries;
	req_isp->num_acked = 0;
	req_isp->bubble_detected = false;
	req_isp->cdm_reset_before_apply = false;

	for (i = 0; i < req_isp->num_fence_map_out; i++) {
		rc = cam_sync_get_obj_ref(req_isp->fence_map_out[i].sync_id);
@@ -4604,6 +4732,7 @@ static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
	start_isp.hw_config.priv  = &req_isp->hw_update_data;
	start_isp.hw_config.init_packet = 1;
	start_isp.hw_config.reapply = 0;
	start_isp.hw_config.cdm_reset_before_apply = false;

	ctx_isp->last_applied_req_id = req->request_id;

+21 −18
Original line number Diff line number Diff line
/* SPDX-License-Identifier: GPL-2.0-only */
/*
 * Copyright (c) 2017-2020, The Linux Foundation. All rights reserved.
 * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved.
 */

#ifndef _CAM_ISP_CONTEXT_H_
@@ -148,6 +148,8 @@ struct cam_isp_ctx_irq_ops {
 * @hw_update_data:            HW update data for this request
 * @event_timestamp:           Timestamp for different stage of request
 * @reapply:                   True if reapplying after bubble
 * @cdm_reset_before_apply:    For bubble re-apply when buf done not coming set
 *                             to True
 *
 */
struct cam_isp_ctx_req {
@@ -167,6 +169,7 @@ struct cam_isp_ctx_req {
		[CAM_ISP_CTX_EVENT_MAX];
	bool                                  bubble_detected;
	bool                                  reapply;
	bool                                  cdm_reset_before_apply;
};

/**
@@ -238,6 +241,7 @@ struct cam_isp_context_event_record {
 * @subscribe_event:           The irq event mask that CRM subscribes to, IFE
 *                             will invoke CRM cb at those event.
 * @last_applied_req_id:       Last applied request id
 * @last_sof_timestamp:        SOF timestamp of the last frame
 * @state_monitor_head:        Write index to the state monitoring array
 * @req_info                   Request id information about last buf done
 * @cam_isp_ctx_state_monitor: State monitoring array
@@ -256,7 +260,6 @@ struct cam_isp_context_event_record {
 *                             decide whether to apply request in offline ctx
 * @workq:                     Worker thread for offline ife
 * @trigger_id:                ID provided by CRM for each ctx on the link
 * @last_sof_timestamp:        SOF timestamp of the last frame
 *
 */
struct cam_isp_context {
@@ -280,6 +283,7 @@ struct cam_isp_context {
	int64_t                          reported_req_id;
	uint32_t                         subscribe_event;
	int64_t                          last_applied_req_id;
	uint64_t                         last_sof_timestamp;
	atomic64_t                       state_monitor_head;
	struct cam_isp_context_state_monitor cam_isp_ctx_state_monitor[
		CAM_ISP_CTX_STATE_MONITOR_MAX_ENTRIES];
@@ -299,7 +303,6 @@ struct cam_isp_context {
	atomic_t                              rxd_epoch;
	struct cam_req_mgr_core_workq        *workq;
	int32_t                               trigger_id;
	uint64_t                              last_sof_timestamp;
};

/**
+34 −0
Original line number Diff line number Diff line
@@ -2710,6 +2710,7 @@ void cam_ife_cam_cdm_callback(uint32_t handle, void *userdata,
	if (status == CAM_CDM_CB_STATUS_BL_SUCCESS) {
		complete_all(&ctx->config_done_complete);
		atomic_set(&ctx->cdm_done, 1);
		ctx->last_cdm_done_req = cookie;
		if (g_ife_hw_mgr.debug_cfg.per_req_reg_dump)
			cam_ife_mgr_handle_reg_dump(ctx,
				hw_update_data->reg_dump_buf_desc,
@@ -3016,6 +3017,7 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args)
	ife_ctx->cdm_handle = cdm_acquire.handle;
	ife_ctx->cdm_ops = cdm_acquire.ops;
	atomic_set(&ife_ctx->cdm_done, 1);
	ife_ctx->last_cdm_done_req = 0;

	acquire_hw_info =
		(struct cam_isp_acquire_hw_info *)acquire_args->acquire_info;
@@ -3225,6 +3227,7 @@ static int cam_ife_mgr_acquire_dev(void *hw_mgr_priv, void *acquire_hw_args)
	ife_ctx->cdm_handle = cdm_acquire.handle;
	ife_ctx->cdm_ops = cdm_acquire.ops;
	atomic_set(&ife_ctx->cdm_done, 1);
	ife_ctx->last_cdm_done_req = 0;

	isp_resource = (struct cam_isp_resource *)acquire_args->acquire_info;

@@ -3662,6 +3665,7 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
	struct cam_ife_hw_mgr_ctx *ctx;
	struct cam_isp_prepare_hw_update_data *hw_update_data;
	unsigned long rem_jiffies = 0;
	bool cdm_hang_detect = false;

	if (!hw_mgr_priv || !config_hw_args) {
		CAM_ERR(CAM_ISP,
@@ -3697,6 +3701,31 @@ static int cam_ife_mgr_config_hw(void *hw_mgr_priv,
	CAM_DBG(CAM_ISP, "Ctx[%pK][%d] : Applying Req %lld, init_packet=%d",
		ctx, ctx->ctx_index, cfg->request_id, cfg->init_packet);

	if (cfg->reapply && cfg->cdm_reset_before_apply) {
		if (ctx->last_cdm_done_req < cfg->request_id) {
			cdm_hang_detect =
				cam_cdm_detect_hang_error(ctx->cdm_handle);
			CAM_ERR_RATE_LIMIT(CAM_ISP,
				"CDM callback not received for req: %lld, last_cdm_done_req: %lld, cdm_hang_detect: %d",
				cfg->request_id, ctx->last_cdm_done_req,
				cdm_hang_detect);
			rc = cam_cdm_reset_hw(ctx->cdm_handle);
			if (rc) {
				CAM_ERR_RATE_LIMIT(CAM_ISP,
					"CDM reset unsuccessful for req: %lld. ctx: %d, rc: %d",
					cfg->request_id, ctx->ctx_index, rc);
				ctx->last_cdm_done_req = 0;
				return rc;
			}
		} else {
			CAM_ERR_RATE_LIMIT(CAM_ISP,
				"CDM callback received, should wait for buf done for req: %lld",
				cfg->request_id);
			return -EALREADY;
		}
		ctx->last_cdm_done_req = 0;
	}

	for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
		if (hw_update_data->bw_config_valid[i] == true) {

@@ -4540,6 +4569,7 @@ static int cam_ife_mgr_release_hw(void *hw_mgr_priv,
	ctx->is_fe_enabled = false;
	ctx->is_offline = false;
	ctx->dual_ife_irq_mismatch_cnt = 0;
	ctx->last_cdm_done_req = 0;
	atomic_set(&ctx->overflow_pending, 0);
	for (i = 0; i < CAM_IFE_HW_NUM_MAX; i++) {
		ctx->sof_cnt[i] = 0;
@@ -6523,6 +6553,10 @@ static int cam_ife_mgr_cmd(void *hw_mgr_priv, void *cmd_args)
	case CAM_HW_MGR_CMD_DUMP_ACQ_INFO:
		cam_ife_hw_mgr_dump_acq_data(ctx);
		break;
	case CAM_ISP_HW_MGR_GET_LAST_CDM_DONE:
		isp_hw_cmd_args->u.last_cdm_done =
			ctx->last_cdm_done_req;
		break;
	default:
		CAM_ERR(CAM_ISP, "Invalid cmd");
	}
+2 −0
Original line number Diff line number Diff line
@@ -133,6 +133,7 @@ struct cam_ife_hw_mgr_debug {
 *                          context
 * @cdm_done                flag to indicate cdm has finished writing shadow
 *                          registers
 * @last_cdm_done_req:      Last cdm done request
 * @is_rdi_only_context     flag to specify the context has only rdi resource
 * @config_done_complete    indicator for configuration complete
 * @reg_dump_buf_desc:      cmd buffer descriptors for reg dump
@@ -185,6 +186,7 @@ struct cam_ife_hw_mgr_ctx {
	uint32_t                        eof_cnt[CAM_IFE_HW_NUM_MAX];
	atomic_t                        overflow_pending;
	atomic_t                        cdm_done;
	uint64_t                        last_cdm_done_req;
	uint32_t                        is_rdi_only_context;
	struct completion               config_done_complete;
	struct cam_cmd_buf_desc         reg_dump_buf_desc[
Loading