diff --git a/drivers/cam_isp/cam_isp_context.c b/drivers/cam_isp/cam_isp_context.c index 3734e0e036..a23cffa52e 100644 --- a/drivers/cam_isp/cam_isp_context.c +++ b/drivers/cam_isp/cam_isp_context.c @@ -819,6 +819,7 @@ static int __cam_isp_ctx_handle_buf_done_for_req_list( if (req_isp->bubble_detected && req_isp->bubble_report) { req_isp->num_acked = 0; + req_isp->num_deferred_acks = 0; req_isp->bubble_detected = false; list_del_init(&req->list); atomic_set(&ctx_isp->process_bubble, 0); @@ -1019,12 +1020,75 @@ static int __cam_isp_ctx_handle_buf_done_for_request( return rc; } +static int __cam_isp_handle_deferred_buf_done( + struct cam_isp_context *ctx_isp, + struct cam_ctx_request *req, + bool bubble_handling, + uint32_t status, uint32_t event_cause) +{ + int i, j; + int rc = 0; + struct cam_isp_ctx_req *req_isp = + (struct cam_isp_ctx_req *) req->req_priv; + struct cam_context *ctx = ctx_isp->base; + + CAM_DBG(CAM_ISP, + "ctx[%d] : Req %llu : Handling %d deferred buf_dones num_acked=%d, bubble_handling=%d", + ctx->ctx_id, req->request_id, req_isp->num_deferred_acks, + req_isp->num_acked, bubble_handling); + + for (i = 0; i < req_isp->num_deferred_acks; i++) { + j = req_isp->deferred_fence_map_index[i]; + + CAM_DBG(CAM_ISP, + "ctx[%d] : Sync with status=%d, event_cause=%d: req %lld res 0x%x sync_id 0x%x", + ctx->ctx_id, status, event_cause, + req->request_id, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id); + + if (req_isp->fence_map_out[j].sync_id == -1) { + CAM_WARN(CAM_ISP, + "ctx[%d Deferred buf_done already signalled, req_id=%llu, j=%d, res=0x%x", + ctx->ctx_id, req->request_id, j, + req_isp->fence_map_out[j].resource_handle); + continue; + } + + if (!bubble_handling) { + CAM_WARN(CAM_ISP, + "ctx[%d] : Req %llu, status=%d res=0x%x should never happen", + ctx->ctx_id, req->request_id, status, + req_isp->fence_map_out[j].resource_handle); + + rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, + status, event_cause); + if (rc) { + CAM_ERR(CAM_ISP, + "ctx[%d] : Sync signal for Req %llu, sync_id %d status=%d failed with rc = %d", + ctx->ctx_id, req->request_id, + req_isp->fence_map_out[j].sync_id, + status, rc); + } else { + req_isp->num_acked++; + req_isp->fence_map_out[j].sync_id = -1; + } + } else { + req_isp->num_acked++; + } + } + + req_isp->num_deferred_acks = 0; + + return rc; +} static int __cam_isp_ctx_handle_buf_done_for_request_verify_addr( struct cam_isp_context *ctx_isp, struct cam_ctx_request *req, struct cam_isp_hw_done_event_data *done, uint32_t bubble_state, - bool verify_consumed_addr) + bool verify_consumed_addr, + bool defer_buf_done) { int rc = 0; int i, j; @@ -1085,7 +1149,32 @@ static int __cam_isp_ctx_handle_buf_done_for_request_verify_addr( continue; } - if (!req_isp->bubble_detected) { + if (defer_buf_done) { + uint32_t deferred_indx = req_isp->num_deferred_acks; + + /* + * If we are handling this BUF_DONE event for a request + * that is still in wait_list, do not signal now, + * instead mark it as done and handle it later - + * if this request is going into BUBBLE state later + * it will automatically be re-applied. If this is not + * going into BUBBLE, signal fences later. + * Note - we will come here only if the last consumed + * address matches with this ports buffer. + */ + req_isp->deferred_fence_map_index[deferred_indx] = j; + req_isp->num_deferred_acks++; + CAM_WARN(CAM_ISP, + "ctx[%d] : Deferred buf done for %llu with bubble state %d recovery %d", + ctx->ctx_id, req->request_id, bubble_state, + req_isp->bubble_report); + CAM_WARN(CAM_ISP, + "ctx[%d] : Deferred info : num_acks=%d, fence_map_index=%d, resource_handle=0x%x, sync_id=%d", + ctx->ctx_id, req_isp->num_deferred_acks, j, + req_isp->fence_map_out[j].resource_handle, + req_isp->fence_map_out[j].sync_id); + continue; + } else if (!req_isp->bubble_detected) { CAM_DBG(CAM_ISP, "Sync with success: req %lld res 0x%x fd 0x%x, ctx %u", req->request_id, @@ -1096,9 +1185,16 @@ static int __cam_isp_ctx_handle_buf_done_for_request_verify_addr( rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, CAM_SYNC_STATE_SIGNALED_SUCCESS, CAM_SYNC_COMMON_EVENT_SUCCESS); - if (rc) + if (rc) { CAM_DBG(CAM_ISP, "Sync failed with rc = %d", rc); + } else if (req_isp->num_deferred_acks) { + /* Process deferred buf_done acks */ + __cam_isp_handle_deferred_buf_done(ctx_isp, + req, false, + CAM_SYNC_STATE_SIGNALED_SUCCESS, + CAM_SYNC_COMMON_EVENT_SUCCESS); + } } else if (!req_isp->bubble_report) { CAM_DBG(CAM_ISP, "Sync with failure: req %lld res 0x%x fd 0x%x, ctx %u", @@ -1110,9 +1206,16 @@ static int __cam_isp_ctx_handle_buf_done_for_request_verify_addr( rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR, CAM_SYNC_ISP_EVENT_BUBBLE); - if (rc) + if (rc) { CAM_ERR(CAM_ISP, "Sync failed with rc = %d", rc); + } else if (req_isp->num_deferred_acks) { + /* Process deferred buf_done acks */ + __cam_isp_handle_deferred_buf_done(ctx_isp, req, + false, + CAM_SYNC_STATE_SIGNALED_ERROR, + CAM_SYNC_ISP_EVENT_BUBBLE); + } } else { /* * Ignore the buffer done if bubble detect is on @@ -1124,6 +1227,14 @@ static int __cam_isp_ctx_handle_buf_done_for_request_verify_addr( CAM_DBG(CAM_ISP, "buf done with bubble state %d recovery %d", bubble_state, req_isp->bubble_report); + /* Process deferred buf_done acks */ + + if (req_isp->num_deferred_acks) + __cam_isp_handle_deferred_buf_done(ctx_isp, req, + true, + CAM_SYNC_STATE_SIGNALED_ERROR, + CAM_SYNC_ISP_EVENT_BUBBLE); + continue; } @@ -1171,7 +1282,7 @@ static int __cam_isp_ctx_handle_buf_done( struct cam_isp_hw_done_event_data done_next_req; if (list_empty(&ctx->active_req_list)) { - CAM_DBG(CAM_ISP, "Buf done with no active request"); + CAM_WARN(CAM_ISP, "Buf done with no active request"); return 0; } @@ -1271,7 +1382,31 @@ static int __cam_isp_ctx_handle_buf_done_verify_addr( struct cam_context *ctx = ctx_isp->base; if (list_empty(&ctx->active_req_list)) { - CAM_DBG(CAM_ISP, "Buf done with no active request"); + CAM_WARN(CAM_ISP, + "Buf done with no active request bubble_state=%d", + bubble_state); + + if (!list_empty(&ctx->wait_req_list)) { + struct cam_isp_ctx_req *req_isp; + + req = list_first_entry(&ctx->wait_req_list, + struct cam_ctx_request, list); + CAM_WARN(CAM_ISP, + "Buf done with no active request but with req in wait list, req %llu", + req->request_id); + req_isp = (struct cam_isp_ctx_req *) req->req_priv; + + /* + * Verify consumed address for this request to make sure + * we are handling the buf_done for the correct + * buffer. Also defer actual buf_done handling, i.e + * do not signal the fence as this request may go into + * Bubble state eventully. + */ + rc = + __cam_isp_ctx_handle_buf_done_for_request_verify_addr( + ctx_isp, req, done, bubble_state, true, true); + } return 0; } @@ -1299,7 +1434,7 @@ static int __cam_isp_ctx_handle_buf_done_verify_addr( */ rc = __cam_isp_ctx_handle_buf_done_for_request_verify_addr( ctx_isp, req, done, bubble_state, - !irq_delay_detected); + !irq_delay_detected, false); /* * Verify the consumed address for next req all the time, @@ -1309,7 +1444,7 @@ static int __cam_isp_ctx_handle_buf_done_verify_addr( if (!rc && irq_delay_detected) rc = __cam_isp_ctx_handle_buf_done_for_request_verify_addr( ctx_isp, next_req, done, - bubble_state, true); + bubble_state, true, false); return rc; } @@ -1392,6 +1527,7 @@ static int __cam_isp_ctx_apply_req_offline( ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_APPLIED; prev_applied_req = ctx_isp->last_applied_req_id; ctx_isp->last_applied_req_id = req->request_id; + atomic_set(&ctx_isp->apply_in_progress, 1); list_del_init(&req->list); list_add_tail(&req->list, &ctx->wait_req_list); @@ -1405,12 +1541,14 @@ static int __cam_isp_ctx_apply_req_offline( ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_SOF; ctx_isp->last_applied_req_id = prev_applied_req; + atomic_set(&ctx_isp->apply_in_progress, 0); list_del_init(&req->list); list_add(&req->list, &ctx->pending_req_list); spin_unlock_bh(&ctx->lock); } else { + atomic_set(&ctx_isp->apply_in_progress, 0); CAM_DBG(CAM_ISP, "New substate state %d, applied req %lld", CAM_ISP_CTX_ACTIVATED_APPLIED, ctx_isp->last_applied_req_id); @@ -1975,6 +2113,9 @@ static int __cam_isp_ctx_sof_in_epoch(struct cam_isp_context *ctx_isp, return -EINVAL; } + if (atomic_read(&ctx_isp->apply_in_progress)) + CAM_INFO(CAM_ISP, "Apply is in progress at the time of SOF"); + ctx_isp->frame_id++; ctx_isp->sof_timestamp_val = sof_event_data->timestamp; ctx_isp->boot_timestamp = sof_event_data->boot_time; @@ -3000,6 +3141,8 @@ static int __cam_isp_ctx_apply_req_in_activated_state( cfg.reapply = req_isp->reapply; cfg.cdm_reset_before_apply = req_isp->cdm_reset_before_apply; + atomic_set(&ctx_isp->apply_in_progress, 1); + rc = ctx->hw_mgr_intf->hw_config(ctx->hw_mgr_intf->hw_mgr_priv, &cfg); if (!rc) { spin_lock_bh(&ctx->lock); @@ -3034,6 +3177,7 @@ static int __cam_isp_ctx_apply_req_in_activated_state( "ctx_id:%d ,Can not apply (req %lld) the configuration, rc %d", ctx->ctx_id, apply->request_id, rc); } + atomic_set(&ctx_isp->apply_in_progress, 0); end: return rc; } @@ -4349,6 +4493,7 @@ static int __cam_isp_ctx_config_dev_in_top_state( req_isp->num_fence_map_out = cfg.num_out_map_entries; req_isp->num_fence_map_in = cfg.num_in_map_entries; req_isp->num_acked = 0; + req_isp->num_deferred_acks = 0; req_isp->bubble_detected = false; req_isp->cdm_reset_before_apply = false; req_isp->hw_update_data.packet = packet; diff --git a/drivers/cam_isp/cam_isp_context.h b/drivers/cam_isp/cam_isp_context.h index a0c9f7bc54..7f97929261 100644 --- a/drivers/cam_isp/cam_isp_context.h +++ b/drivers/cam_isp/cam_isp_context.h @@ -148,6 +148,13 @@ struct cam_isp_ctx_irq_ops { * @num_acked: Count to track acked entried for output. * If count equals the number of fence out, it means * the request has been completed. + * @num_deferred_acks: Number of buf_dones/acks that are deferred to + * handle or signalled in special scenarios. + * Increment this count instead of num_acked and + * handle the events later where eventually + * increment num_acked. + * @deferred_fence_map_index Saves the indices of fence_map_out for which + * handling of buf_done is deferred. * @bubble_report: Flag to track if bubble report is active on * current request * @hw_update_data: HW update data for this request @@ -167,6 +174,8 @@ struct cam_isp_ctx_req { struct cam_hw_fence_map_entry fence_map_in[CAM_ISP_CTX_RES_MAX]; uint32_t num_fence_map_in; uint32_t num_acked; + uint32_t num_deferred_acks; + uint32_t deferred_fence_map_index[CAM_ISP_CTX_RES_MAX]; int32_t bubble_report; struct cam_isp_prepare_hw_update_data hw_update_data; ktime_t event_timestamp @@ -261,6 +270,7 @@ struct cam_isp_context_event_record { * @custom_enabled: Custom HW enabled for this ctx * @use_frame_header_ts: Use frame header for qtimer ts * @support_consumed_addr: Indicate whether HW has last consumed addr reg + * @apply_in_progress Whether request apply is in progress * @init_timestamp: Timestamp at which this context is initialized * @isp_device_type: ISP device type * @rxd_epoch: Indicate whether epoch has been received. Used to @@ -307,6 +317,7 @@ struct cam_isp_context { bool custom_enabled; bool use_frame_header_ts; bool support_consumed_addr; + atomic_t apply_in_progress; unsigned int init_timestamp; uint32_t isp_device_type; atomic_t rxd_epoch;