msm: camera: req_mgr: Handle apply failure

Handle apply failure in workqueue. Add recovery mechanism
to recovery in req_mgr to handle frame out of sync issue.

CRs-Fixed: 2997164
Change-Id: I0e04571b3a31d7a879a7aa579c1f0be51c233277
Signed-off-by: Ayush Kumar <ayushkr@codeaurora.org>
This commit is contained in:
Ayush Kumar
2021-07-22 15:54:54 +05:30
committed by Gerrit - the friendly Code Review server
parent 4baa6ec428
commit f428aed04a
5 changed files with 185 additions and 109 deletions

View File

@@ -1773,7 +1773,7 @@ static int __cam_isp_ctx_reg_upd_in_applied_state(
list_add_tail(&req->list, &ctx->active_req_list);
ctx_isp->active_req_cnt++;
if (req_isp->is_sync_mode) {
if (req_isp->is_sync_mode && !atomic_read(&req_isp->buf_done_ready)) {
request_id = req->request_id;
notify_rup_info.link_hdl = ctx->link_hdl;
notify_rup_info.req_id = request_id;
@@ -3423,7 +3423,9 @@ static int __cam_isp_ctx_signal_buf_done(
}
}
CAM_WARN(CAM_ISP, "Request %lld not found", signal_buf_done->req_id);
CAM_WARN(CAM_ISP, "Request %lld not found in ctx : %d",
signal_buf_done->req_id,
ctx->ctx_id);
end:
return 0;
}
@@ -3441,6 +3443,7 @@ static int __cam_isp_ctx_change_substate(
struct cam_isp_context *ctx_isp =
(struct cam_isp_context *) ctx->ctx_priv;
spin_lock_bh(&ctx->lock);
if (!list_empty(&ctx->wait_req_list)) {
req = list_first_entry(&ctx->wait_req_list,
struct cam_ctx_request,
@@ -3450,13 +3453,16 @@ static int __cam_isp_ctx_change_substate(
req_isp->bubble_detected = true;
req_isp->reapply = true;
bubble_req = req;
ctx_isp->active_req_cnt++;
list_del_init(&req->list);
list_add_tail(&req->list, &ctx->active_req_list);
spin_unlock_bh(&ctx->lock);
goto end;
}
} else {
CAM_ERR(CAM_ISP, "Ctx:%d No wait request", ctx->ctx_id);
}
spin_unlock_bh(&ctx->lock);
if (!bubble_req) {
list_for_each_entry_safe(req, req_temp,
@@ -4959,6 +4965,7 @@ static int __cam_isp_ctx_config_dev_in_top_state(
cfg.num_in_map_entries = 0;
memset(&req_isp->hw_update_data, 0, sizeof(req_isp->hw_update_data));
req_isp->hw_update_data.fps = -1;
req_isp->is_sync_mode = false;
req_isp->hw_update_data.packet = packet;
rc = ctx->hw_mgr_intf->hw_prepare_update(
@@ -5811,10 +5818,19 @@ static int __cam_isp_ctx_get_isp_info(int32_t dev_hdl, void *data)
if ((isp_ctx->substate_activated ==
CAM_ISP_CTX_ACTIVATED_APPLIED) ||
(isp_ctx->substate_activated ==
CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED))
CAM_ISP_CTX_ACTIVATED_BUBBLE_APPLIED)) {
if (!list_empty(&ctx->wait_req_list)) {
struct cam_ctx_request *req;
req = list_first_entry(&ctx->wait_req_list,
struct cam_ctx_request, list);
isp_dev->bubble_req = req->request_id;
}
isp_dev->is_applied = true;
else
} else {
isp_dev->is_applied = false;
isp_dev->bubble_req = 0;
}
return rc;
}

View File

@@ -69,10 +69,11 @@ void cam_req_mgr_core_link_reset(struct cam_req_mgr_core_link *link)
link->wq_congestion = false;
link->sync_data.num_sync_link = 0;
link->activate_seq = -1;
link->bubble_skip = 0;
link->skip_apply_count = 0;
link->sync_data.sync_frame_id = 0;
link->sync_data.is_sync_req = true;
link->skip_sync_apply = false;
link->sync_data.sync_mismatch_count = 0;
link->fps = CAM_REQ_MGR_DEFAULT_FPS;
link->num_isp_dev = 0;
link->retry_threshold = 0;
@@ -666,6 +667,7 @@ static void __cam_req_mgr_flush_req_slot(
link->trigger_cnt[0][CAM_TRIGGER_POINT_EOF] = 0;
link->trigger_cnt[1][CAM_TRIGGER_POINT_SOF] = 0;
link->trigger_cnt[1][CAM_TRIGGER_POINT_EOF] = 0;
link->sync_data.sync_link_sof_skip = false;
}
/**
@@ -1338,7 +1340,7 @@ static int __cam_req_mgr_check_multi_sync_link_ready(
if (rc)
CAM_WARN(CAM_CRM, "Unexpected return value rc: %d", rc);
return 0;
return rc;
}
/**
@@ -1582,15 +1584,6 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link,
}
}
if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC &&
((link->sync_data.initial_sync_req == slot->req_id) ||
((link->sync_data.initial_sync_req < slot->req_id) &&
link->sync_data.sync_frame_id == 0))) {
link->sync_data.sync_frame_id = trigger_data->frame_id;
CAM_DBG(CAM_CRM, "Setting sync frame %lld for link 0x%x",
link->sync_data.sync_frame_id, link->link_hdl);
}
rc = __cam_req_mgr_send_req(link, link->req.in_q, trigger, &dev);
if (rc < 0) {
/* Apply req failed retry at next sof */
@@ -1623,10 +1616,24 @@ static int __cam_req_mgr_process_req(struct cam_req_mgr_core_link *link,
"workqueue congestion, last applied idx:%d rd idx:%d",
in_q->last_applied_idx,
in_q->rd_idx);
if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) {
link->sync_data.sync_link_sof_skip = true;
for (i = 0; i < link->sync_data.num_sync_link; i++)
link->sync_data.sync_link[i]->skip_apply_count = 1;
}
} else {
if (link->retry_cnt)
link->retry_cnt = 0;
if (slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC &&
((link->sync_data.sync_frame_id == 0 &&
link->sync_data.initial_sync_req < slot->req_id) ||
link->sync_data.initial_sync_req == slot->req_id)) {
link->sync_data.sync_frame_id = trigger_data->frame_id;
CAM_DBG(CAM_CRM, "Setting sync frame %lld for link 0x%x",
link->sync_data.sync_frame_id, link->link_hdl);
}
/* Check for any long exposure settings */
__cam_req_mgr_validate_crm_wd_timer(link);
@@ -2340,6 +2347,7 @@ int cam_req_mgr_process_sched_req(void *priv, void *data)
slot->req_id = sched_req->req_id;
slot->skip_idx = 0;
slot->recover = sched_req->bubble_enable;
if (slot->sync_mode != CAM_REQ_MGR_SYNC_MODE_INITIAL_SYNC)
slot->sync_mode = sched_req->sync_mode;
if (sched_req->additional_timeout < 0) {
CAM_WARN(CAM_CRM,
@@ -2397,7 +2405,7 @@ int cam_req_mgr_process_sched_req(void *priv, void *data)
if (link->sync_data.is_sync_req && tmp_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC
&& ((link->sync_data.initial_sync_req + 6) > tmp_slot->req_id)) {
slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_TRANSITION_SYNC;
slot->sync_mode = CAM_REQ_MGR_SYNC_MODE_INITIAL_SYNC;
} else if (tmp_slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_SYNC) {
if (link->sync_data.is_sync_req && (link->initial_skip == 0)) {
link->sync_data.is_sync_req = false;
@@ -3495,7 +3503,7 @@ static int cam_req_mgr_send_to_bubble(
CAM_ERR(CAM_CRM,
"Failed to change state");
} else {
link->bubble_skip = link->max_delay - 1;
link->skip_apply_count = link->max_delay - 1;
}
}
rc = cam_req_mgr_cb_notify_err(&notify);
@@ -3507,6 +3515,35 @@ static int cam_req_mgr_send_to_bubble(
return rc;
}
static void cam_req_mgr_trigger_initial_sync_mode(
struct cam_req_mgr_core_link *link)
{
struct cam_req_mgr_req_queue *link_in_q;
uint32_t rd_idx = 0;
int i, j;
link_in_q = link->req.in_q;
rd_idx = link_in_q->rd_idx;
for (i = 0; i < CAM_REQ_MGR_INIT_SYNC_REQ_NUM; i++) {
if (link_in_q->slot[rd_idx].status == CRM_SLOT_STATUS_REQ_APPLIED)
__cam_req_mgr_inc_idx(&rd_idx, 1, link_in_q->num_slots);
link_in_q->slot[rd_idx].sync_mode = CAM_REQ_MGR_SYNC_MODE_INITIAL_SYNC;
__cam_req_mgr_inc_idx(&rd_idx, 1, link_in_q->num_slots);
}
for (i = 0; i < link->sync_data.num_sync_link; i++) {
link_in_q = link->sync_data.sync_link[i]->req.in_q;
rd_idx = link_in_q->rd_idx;
for (j = 0; j < CAM_REQ_MGR_INIT_SYNC_REQ_NUM; j++) {
if (link_in_q->slot[rd_idx].status == CRM_SLOT_STATUS_REQ_APPLIED)
__cam_req_mgr_inc_idx(&rd_idx, 1, link_in_q->num_slots);
link_in_q->slot[rd_idx].sync_mode = CAM_REQ_MGR_SYNC_MODE_INITIAL_SYNC;
__cam_req_mgr_inc_idx(&rd_idx, 1, link_in_q->num_slots);
}
}
}
static uint64_t cam_req_mgr_get_threshold_time(
struct cam_req_mgr_core_link *link,
uint64_t frame_duration_ns,
@@ -3627,6 +3664,7 @@ static int cam_req_mgr_is_slave_link_ready(
sync_link->sync_data.sync_frame_id);
if (!master_link->sync_data.sync_link_sof_skip &&
!sync_link->sync_data.sync_link_sof_skip &&
master_link->sync_data.sync_frame_id &&
master_link->sync_data.initial_sync_req != slot->req_id
&& (diff != (master_link->frame_id - dev_data.frame_id))) {
@@ -3634,6 +3672,17 @@ static int cam_req_mgr_is_slave_link_ready(
CAM_INFO_RATE_LIMIT(CAM_CRM,
"Initial Frame diff %d not matching with current frame diff %d",
diff, (master_link->frame_id - dev_data.frame_id));
master_link->sync_data.sync_mismatch_count++;
if (master_link->sync_data.sync_mismatch_count ==
CAM_REQ_MGR_SYNC_MISMATCH_THRESHOLD) {
cam_req_mgr_trigger_initial_sync_mode(master_link);
master_link->sync_data.sync_mismatch_count = 0;
CAM_DBG(CAM_CRM,
"Continous frame sync mismatch, triggering recovery");
}
dump_info.m_link = master_link;
dump_info.s_link = sync_link;
dump_info.dev_data = dev_data;
@@ -3686,14 +3735,16 @@ static int cam_req_mgr_is_slave_link_ready(
*/
if (dev_data.is_applied &&
master_link->sync_data.initial_sync_req != slot->req_id) {
if (dev_data.bubble_req) {
rc = cam_req_mgr_send_to_bubble(master_link, dev_data.bubble_req);
} else {
rc = cam_req_mgr_send_to_bubble(
master_link, (sync_slot->req_id -sync_link->max_delay));
}
CAM_ERR(CAM_CRM,
"Slave link %x req %lld is in applied state, triggering bubble recovery",
"Slave link %x req %lld in applied state, dev req %lld triggering bubble recovery",
sync_link->link_hdl,
(sync_slot->req_id -
sync_link->max_delay));
rc = cam_req_mgr_send_to_bubble(master_link,
(sync_slot->req_id -
sync_link->max_delay));
(sync_slot->req_id - sync_link->max_delay), dev_data.bubble_req);
master_link->sync_data.sync_link_sof_skip = true;
CAM_DBG(CAM_CRM,
"Master sof %lld slave sof %lld",
@@ -3709,7 +3760,8 @@ static int cam_req_mgr_is_slave_link_ready(
sync_link->sync_data.initial_sync_req;
if (!master_link->sync_data.sync_link_sof_skip &&
diff != (slot->req_id - sync_slot->req_id)) {
diff != (slot->req_id - sync_slot->req_id &&
!sync_link->sync_data.sync_link_sof_skip)) {
CAM_INFO(CAM_CRM,
"Req diff %lld Master link %x req %lld slave link %x req %lld",
@@ -3762,6 +3814,7 @@ static int cam_req_mgr_cb_notify_trigger(
uint32_t trigger;
struct crm_workq_task *task = NULL;
struct cam_req_mgr_core_link *link = NULL;
struct cam_req_mgr_core_link *sync_link = NULL;
struct cam_req_mgr_trigger_notify *notify_trigger;
struct crm_task_payload *task_data;
struct cam_req_mgr_slot *slot = NULL;
@@ -3938,25 +3991,8 @@ static int cam_req_mgr_cb_notify_trigger(
}
}
if (link->bubble_skip) {
link->bubble_skip--;
if (link->bubble_skip == 0)
link->sync_data.sync_link_sof_skip = false;
goto slave;
}
if (trigger == CAM_TRIGGER_POINT_SOF &&
slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_TRANSITION_SYNC) {
rc = __cam_req_mgr_check_link_is_ready(
link, slot_rd_idx, true);
if (rc) {
CAM_DBG(CAM_CRM,
"M Req:%lld not ready on link: %x, rc=%d",
slot->req_id, link->link_hdl, rc);
link->skip_sync_apply = true;
return 0;
}
slot->sync_mode == CAM_REQ_MGR_SYNC_MODE_INITIAL_SYNC) {
CAM_DBG(CAM_CRM,
"Start sync cond link %x modified sync req %lld enter",
@@ -4066,8 +4102,23 @@ cl:
link->sync_data.sync_link[i]->link_hdl,
sync_slot->req_id);
}
rc = __cam_req_mgr_check_link_is_ready(
link, slot_rd_idx, true);
if (rc) {
CAM_DBG(CAM_CRM,
"M Req:%lld not ready on link: %x, rc=%d",
slot->req_id, link->link_hdl, rc);
link->skip_sync_apply = true;
return 0;
}
}
if (link->skip_apply_count) {
link->skip_apply_count--;
if (link->skip_apply_count == 0)
link->sync_data.sync_link_sof_skip = false;
} else {
task = cam_req_mgr_workq_get_task(link->workq);
if (!task) {
CAM_ERR_RATE_LIMIT(CAM_CRM, "no empty task frame %lld",
@@ -4091,8 +4142,7 @@ cl:
notify_trigger->sof_timestamp_val = trigger_data->sof_timestamp_val;
task->process_cb = &cam_req_mgr_process_trigger;
rc = cam_req_mgr_workq_enqueue_task(task, link, CRM_TASK_PRIORITY_0);
slave:
}
/* If sync mode is on and master epoch then enqueue workqueue to apply
* request for all sync link of master.
@@ -4107,13 +4157,17 @@ slave:
slot->req_id, tmp_slot->sync_mode,
slot->sync_mode, link->link_hdl);
dev_name = __cam_req_mgr_dev_handle_to_name(
trigger_data->dev_hdl, link);
dev_name = __cam_req_mgr_dev_handle_to_name(trigger_data->dev_hdl, link);
for (i = 0; i < link->sync_data.num_sync_link; i++) {
sync_link = link->sync_data.sync_link[i];
task = cam_req_mgr_workq_get_task(
link->sync_data.sync_link[i]->workq);
if (sync_link->skip_apply_count) {
sync_link->skip_apply_count--;
if (sync_link->skip_apply_count == 0)
sync_link->sync_data.sync_link_sof_skip = false;
} else {
task = cam_req_mgr_workq_get_task(sync_link->workq);
if (!task) {
CAM_ERR(CAM_CRM, "No empty task frame %lld",
trigger_data->frame_id);
@@ -4121,33 +4175,31 @@ slave:
goto end;
}
sync_dev_hdl = cam_req_mgr_get_dev_hdl(dev_name,
link->sync_data.sync_link[i]);
sync_dev_hdl = cam_req_mgr_get_dev_hdl(dev_name, sync_link);
if (sync_dev_hdl == -1) {
CAM_ERR(CAM_CRM, "Sync dev hdl is null");
goto end;
}
CAM_DBG(CAM_CRM, "Sync link 0x%x sync dev hdl %x",
link->sync_data.sync_link[i]->link_hdl, sync_dev_hdl);
CAM_DBG(CAM_CRM,
"Sync link 0x%x sync dev hdl %x", sync_link->link_hdl, sync_dev_hdl);
cam_req_mgr_get_device_info(
link->sync_data.sync_link[i], &dev_data);
cam_req_mgr_get_device_info(sync_link, &dev_data);
task_data = (struct crm_task_payload *)task->payload;
task_data->type = CRM_WORKQ_TASK_NOTIFY_SOF;
notify_trigger = (struct cam_req_mgr_trigger_notify *)
&task_data->u;
notify_trigger->frame_id = dev_data.frame_id;
notify_trigger->link_hdl = link->sync_data.sync_link[i]->link_hdl;
notify_trigger->link_hdl = sync_link->link_hdl;
notify_trigger->dev_hdl = sync_dev_hdl;
notify_trigger->trigger = trigger_data->trigger;
notify_trigger->req_id = trigger_data->req_id;
notify_trigger->sof_timestamp_val =
trigger_data->sof_timestamp_val;
task->process_cb = &cam_req_mgr_process_trigger;
rc = cam_req_mgr_workq_enqueue_task(task,
link->sync_data.sync_link[i], CRM_TASK_PRIORITY_0);
rc = cam_req_mgr_workq_enqueue_task(task, sync_link, CRM_TASK_PRIORITY_0);
}
}
}
@@ -4977,7 +5029,7 @@ int cam_req_mgr_sync_config(
link[i]->in_msync_mode = false;
link[i]->sync_data.initial_sync_req = -1;
link[i]->sync_data.num_sync_link = 0;
link[i]->bubble_skip = 0;
link[i]->skip_apply_count = 0;
link[i]->sync_data.sync_frame_id = 0;
link[i]->sync_data.is_sync_req = true;
link[i]->sync_data.modified_init_sync_req = -1;

View File

@@ -42,6 +42,10 @@
#define VERSION_2 2
#define CAM_REQ_MGR_MAX_TRIGGERS 2
#define CAM_REQ_MGR_INIT_SYNC_REQ_NUM 5
#define CAM_REQ_MGR_SYNC_MISMATCH_THRESHOLD 3
/**
* enum crm_req_eof_trigger_type
* @codes: to identify which type of eof trigger for next slot
@@ -362,6 +366,7 @@ struct cam_req_mgr_sof_time {
* @sync_frame_id : current frame id of sync link
* @sof_time : sof timing value in different format
* @is_sync_req : flag used for deciding sync and non-sync
* @sync_mismatch_count : counter to store number of frame sync mismatch
*/
struct cam_req_mgr_sync_data {
int32_t num_sync_link;
@@ -372,6 +377,7 @@ struct cam_req_mgr_sync_data {
uint64_t sync_frame_id;
struct cam_req_mgr_sof_time sof_time;
bool is_sync_req;
int32_t sync_mismatch_count;
};
/**
@@ -420,7 +426,7 @@ struct cam_req_mgr_sync_data {
* @wq_congestion : Indicates if WQ congestion is detected or not
* @activate_seq : sequence in which link is activated
* @frame_id : current frame id
* @bubble_skip : req to skip on bubble
* @skip_apply_count : Counter that track number of frames to skip apply request
* @num_isp_dev : number of isp dev in a link
* @retry_threshold : number of times to retry apply on increased threshold
* @fps : current frame rate
@@ -457,7 +463,7 @@ struct cam_req_mgr_core_link {
bool wq_congestion;
int32_t activate_seq;
uint64_t frame_id;
int32_t bubble_skip;
int32_t skip_apply_count;
bool skip_sync_apply;
uint32_t num_isp_dev;
uint32_t retry_threshold;

View File

@@ -470,6 +470,7 @@ struct cam_req_mgr_dump_info {
* @timestamp : time stamp for the sof event
* @boot_time : boot time stamp for the sof event
* @frame_id : frame id
* @bubble_req : request id for which bubble is detected
* @is_applied : if ISP is in applied state
*
*/
@@ -479,6 +480,7 @@ struct cam_req_mgr_dev_info {
uint64_t timestamp;
uint64_t boot_time;
uint64_t frame_id;
uint64_t bubble_req;
bool is_applied;
};

View File

@@ -84,13 +84,13 @@
* @CAM_REQ_MGR_SYNC_MODE_NO_SYNC: Req mgr will apply non-sync mode for this
* request.
* @CAM_REQ_MGR_SYNC_MODE_SYNC: Req mgr will apply sync mode for this request.
* @CAM_REQ_MGR_SYNC_MODE_TRANSITION_SYNC: Req mgr will apply transition sync
* @CAM_REQ_MGR_SYNC_MODE_INITIAL_SYNC: Req mgr will apply initial sync
* mode for this request. Only first few request before sync mode will apply
* transition sync mode.
*/
#define CAM_REQ_MGR_SYNC_MODE_NO_SYNC 0
#define CAM_REQ_MGR_SYNC_MODE_SYNC 1
#define CAM_REQ_MGR_SYNC_MODE_TRANSITION_SYNC 2
#define CAM_REQ_MGR_SYNC_MODE_INITIAL_SYNC 2
/**
* struct cam_req_mgr_event_data