Loading drivers/cam_core/cam_hw_mgr_intf.h +3 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_HW_MGR_INTF_H_ Loading Loading @@ -106,6 +107,7 @@ struct cam_hw_done_event_data { * @ctxt_to_hw_map: HW context (returned) * @custom_enabled: ctx has custom enabled * @use_frame_header_ts: Use frame header for qtimer ts * @support_consumed_addr: The platform has last consumed addr register * @acquired_hw_id: Acquired hardware mask * @acquired_hw_path: Acquired path mask for an input * if input splits into multiple paths, Loading @@ -123,6 +125,7 @@ struct cam_hw_acquire_args { void *ctxt_to_hw_map; bool custom_enabled; bool use_frame_header_ts; bool support_consumed_addr; uint32_t acquired_hw_id[CAM_MAX_ACQ_RES]; uint32_t acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT]; Loading drivers/cam_isp/cam_isp_context.c +317 −78 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/debugfs.h> Loading Loading @@ -738,6 +739,70 @@ static void __cam_isp_ctx_handle_buf_done_fail_log( } } static int __cam_isp_ctx_handle_buf_done_for_req_list( struct cam_isp_context *ctx_isp, struct cam_ctx_request *req) { int rc = 0, i; uint64_t buf_done_req_id; struct cam_isp_ctx_req *req_isp; struct cam_context *ctx = ctx_isp->base; req_isp = (struct cam_isp_ctx_req *) req->req_priv; ctx_isp->active_req_cnt--; buf_done_req_id = req->request_id; if (req_isp->bubble_detected && req_isp->bubble_report) { req_isp->num_acked = 0; req_isp->bubble_detected = false; list_del_init(&req->list); atomic_set(&ctx_isp->process_bubble, 0); if (buf_done_req_id <= ctx->last_flush_req) { for (i = 0; i < req_isp->num_fence_map_out; i++) rc = cam_sync_signal( req_isp->fence_map_out[i].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); list_add_tail(&req->list, &ctx->free_req_list); CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [flushed], ctx %u", buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); } else { list_add(&req->list, &ctx->pending_req_list); CAM_DBG(CAM_REQ, "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } } else { if (!ctx_isp->use_frame_header_ts) { if (ctx_isp->reported_req_id < buf_done_req_id) { ctx_isp->reported_req_id = buf_done_req_id; __cam_isp_ctx_send_sof_timestamp(ctx_isp, buf_done_req_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); } } list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); req_isp->reapply = false; CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); ctx_isp->req_info.last_bufdone_req_id = req->request_id; } __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); __cam_isp_ctx_update_event_record(ctx_isp, CAM_ISP_CTX_EVENT_BUFDONE, req); return rc; } static int __cam_isp_ctx_handle_buf_done_for_request( struct cam_isp_context *ctx_isp, struct cam_ctx_request *req, Loading @@ -749,7 +814,6 @@ static int __cam_isp_ctx_handle_buf_done_for_request( int i, j; struct cam_isp_ctx_req *req_isp; struct cam_context *ctx = ctx_isp->base; uint64_t buf_done_req_id; trace_cam_buf_done("ISP", ctx, req); Loading @@ -758,10 +822,8 @@ static int __cam_isp_ctx_handle_buf_done_for_request( CAM_DBG(CAM_ISP, "Enter with bubble_state %d, req_bubble_detected %d", bubble_state, req_isp->bubble_detected); if (done_next_req) { done_next_req->num_handles = 0; done_next_req->timestamp = done->timestamp; } for (i = 0; i < done->num_handles; i++) { for (j = 0; j < req_isp->num_fence_map_out; j++) { Loading @@ -771,14 +833,14 @@ static int __cam_isp_ctx_handle_buf_done_for_request( } if (j == req_isp->num_fence_map_out) { if (done_next_req) { /* * If not found in current request, it could be * belonging to next request, This can happen if * IRQ delay happens. * belonging to next request, this can happen if * IRQ delay happens. It is only valid when the * platform doesn't have last consumed address. */ CAM_WARN(CAM_ISP, "BUF_DONE for res 0x%x not found in Req %lld ", "BUF_DONE for res %s not found in Req %lld ", __cam_isp_resource_handle_id_to_type( done->resource_handle[i]), req->request_id); Loading @@ -786,13 +848,6 @@ static int __cam_isp_ctx_handle_buf_done_for_request( done_next_req->resource_handle [done_next_req->num_handles++] = done->resource_handle[i]; } else { CAM_ERR(CAM_ISP, "Can not find matching lane handle 0x%x! in Req %lld", done->resource_handle[i], req->request_id); rc = -EINVAL; } continue; } Loading @@ -807,12 +862,9 @@ static int __cam_isp_ctx_handle_buf_done_for_request( done->resource_handle[i]), req->request_id, ctx->ctx_id); if (done_next_req) { done_next_req->resource_handle [done_next_req->num_handles++] = done->resource_handle[i]; } continue; } Loading Loading @@ -885,66 +937,145 @@ static int __cam_isp_ctx_handle_buf_done_for_request( if (req_isp->num_acked != req_isp->num_fence_map_out) return rc; ctx_isp->active_req_cnt--; buf_done_req_id = req->request_id; rc = __cam_isp_ctx_handle_buf_done_for_req_list(ctx_isp, req); return rc; } if (req_isp->bubble_detected && req_isp->bubble_report) { req_isp->num_acked = 0; 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; 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) { int rc = 0; int i, j; struct cam_isp_ctx_req *req_isp; struct cam_context *ctx = ctx_isp->base; const char *handle_type; if (buf_done_req_id <= ctx->last_flush_req) { for (i = 0; i < req_isp->num_fence_map_out; i++) cam_sync_signal( req_isp->fence_map_out[i].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); trace_cam_buf_done("ISP", ctx, req); list_add_tail(&req->list, &ctx->free_req_list); CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [flushed], ctx %u", buf_done_req_id, ctx_isp->active_req_cnt, req_isp = (struct cam_isp_ctx_req *) req->req_priv; CAM_DBG(CAM_ISP, "Enter with bubble_state %d, req_bubble_detected %d", bubble_state, req_isp->bubble_detected); for (i = 0; i < done->num_handles; i++) { for (j = 0; j < req_isp->num_fence_map_out; j++) { if (verify_consumed_addr && (done->last_consumed_addr[i] != req_isp->fence_map_out[j].image_buf_addr[0])) continue; if (done->resource_handle[i] == req_isp->fence_map_out[j].resource_handle) break; } if (j == req_isp->num_fence_map_out) { /* * If not found in current request, it could be * belonging to next request, this can happen if * IRQ delay happens. It is only valid when the * platform doesn't have last consumed address. */ CAM_DBG(CAM_ISP, "BUF_DONE for res %s not found in Req %lld ", __cam_isp_resource_handle_id_to_type( done->resource_handle[i]), req->request_id); continue; } if (req_isp->fence_map_out[j].sync_id == -1) { handle_type = __cam_isp_resource_handle_id_to_type( req_isp->fence_map_out[i].resource_handle); CAM_WARN(CAM_ISP, "Duplicate BUF_DONE for req %lld : i=%d, j=%d, res=%s", req->request_id, i, j, handle_type); trace_cam_log_event("Duplicate BufDone", handle_type, req->request_id, ctx->ctx_id); continue; } 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, req_isp->fence_map_out[j].resource_handle, req_isp->fence_map_out[j].sync_id, ctx->ctx_id); } else { list_add(&req->list, &ctx->pending_req_list); ctx_isp->bubble_frame_cnt = 0; CAM_DBG(CAM_REQ, "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", req->request_id, ctx_isp->active_req_cnt, rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, CAM_SYNC_STATE_SIGNALED_SUCCESS); if (rc) CAM_DBG(CAM_ISP, "Sync failed with rc = %d", rc); } else if (!req_isp->bubble_report) { CAM_ERR(CAM_ISP, "Sync with failure: req %lld res 0x%x fd 0x%x, ctx %u", req->request_id, req_isp->fence_map_out[j].resource_handle, req_isp->fence_map_out[j].sync_id, ctx->ctx_id); } rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); if (rc) CAM_ERR(CAM_ISP, "Sync failed with rc = %d", rc); } else { /* * Ignore the buffer done if bubble detect is on * Increment the ack number here, and queue the * request back to pending list whenever all the * buffers are done. */ req_isp->num_acked++; CAM_DBG(CAM_ISP, "buf done with bubble state %d recovery %d", bubble_state, req_isp->bubble_report); continue; } if (!ctx_isp->use_frame_header_ts) { if (ctx_isp->reported_req_id < buf_done_req_id) { ctx_isp->reported_req_id = buf_done_req_id; __cam_isp_ctx_send_sof_timestamp(ctx_isp, buf_done_req_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x ctx %u", req->request_id, req_isp->fence_map_out[j].sync_id, ctx->ctx_id); if (!rc) { req_isp->num_acked++; req_isp->fence_map_out[j].sync_id = -1; } if ((ctx_isp->use_frame_header_ts) && (req_isp->hw_update_data.frame_header_res_id == req_isp->fence_map_out[j].resource_handle)) __cam_isp_ctx_send_sof_timestamp_frame_header( ctx_isp, req_isp->hw_update_data.frame_header_cpu_addr, req->request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); } 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", buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); ctx_isp->req_info.last_bufdone_req_id = req->request_id; if (req_isp->num_acked > req_isp->num_fence_map_out) { /* Should not happen */ CAM_ERR(CAM_ISP, "WARNING: req_id %lld num_acked %d > map_out %d, ctx %u", req->request_id, req_isp->num_acked, req_isp->num_fence_map_out, ctx->ctx_id); WARN_ON(req_isp->num_acked > req_isp->num_fence_map_out); } __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); if (req_isp->num_acked != req_isp->num_fence_map_out) return rc; __cam_isp_ctx_update_event_record(ctx_isp, CAM_ISP_CTX_EVENT_BUFDONE, req); rc = __cam_isp_ctx_handle_buf_done_for_req_list(ctx_isp, req); return rc; } static int __cam_isp_ctx_handle_buf_done_in_activated_state( static int __cam_isp_ctx_handle_buf_done( struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done, uint32_t bubble_state) Loading Loading @@ -1008,6 +1139,111 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( return rc; } static void __cam_isp_ctx_buf_done_match_req( struct cam_ctx_request *req, struct cam_isp_hw_done_event_data *done, bool *irq_delay_detected) { int i, j; uint32_t match_count = 0; struct cam_isp_ctx_req *req_isp; req_isp = (struct cam_isp_ctx_req *) req->req_priv; for (i = 0; i < done->num_handles; i++) { for (j = 0; j < req_isp->num_fence_map_out; j++) { if ((done->resource_handle[i] == req_isp->fence_map_out[j].resource_handle) && (done->last_consumed_addr[i] == req_isp->fence_map_out[j].image_buf_addr[0])) { match_count++; break; } } } if (match_count > 0) *irq_delay_detected = true; else *irq_delay_detected = false; CAM_DBG(CAM_ISP, "buf done num handles %d match count %d for next req:%lld", done->num_handles, match_count, req->request_id); } static int __cam_isp_ctx_handle_buf_done_verify_addr( struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done, uint32_t bubble_state) { int rc = 0; bool irq_delay_detected = false; struct cam_ctx_request *req; struct cam_ctx_request *next_req = NULL; struct cam_context *ctx = ctx_isp->base; if (list_empty(&ctx->active_req_list)) { CAM_DBG(CAM_ISP, "Buf done with no active request"); return 0; } req = list_first_entry(&ctx->active_req_list, struct cam_ctx_request, list); if (ctx_isp->active_req_cnt > 1) { next_req = list_last_entry( &ctx->active_req_list, struct cam_ctx_request, list); if (next_req->request_id != req->request_id) __cam_isp_ctx_buf_done_match_req(next_req, done, &irq_delay_detected); else CAM_WARN(CAM_ISP, "Req %lld only active request, spurious buf_done rxd", req->request_id); } /* * If irq delay isn't detected, then we need to verify * the consumed address for current req, otherwise, we * can't verify the consumed address. */ rc = __cam_isp_ctx_handle_buf_done_for_request_verify_addr( ctx_isp, req, done, bubble_state, !irq_delay_detected); /* * Verify the consumed address for next req all the time, * since the reported buf done event may belong to current * req, then we can't signal this event for next req. */ if (!rc && irq_delay_detected) rc = __cam_isp_ctx_handle_buf_done_for_request_verify_addr( ctx_isp, next_req, done, bubble_state, true); return rc; } static int __cam_isp_ctx_handle_buf_done_in_activated_state( struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done, uint32_t bubble_state) { int rc = 0; if (ctx_isp->support_consumed_addr) rc = __cam_isp_ctx_handle_buf_done_verify_addr( ctx_isp, done, bubble_state); else rc = __cam_isp_ctx_handle_buf_done( ctx_isp, done, bubble_state); return rc; } static int __cam_isp_ctx_apply_req_offline( void *priv, void *data) { Loading Loading @@ -3773,6 +4009,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, ctx_isp->reported_req_id = 0; ctx_isp->hw_acquired = false; ctx_isp->init_received = false; ctx_isp->support_consumed_addr = false; ctx_isp->req_info.last_bufdone_req_id = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); Loading Loading @@ -4450,6 +4687,8 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, */ ctx_isp->custom_enabled = param.custom_enabled; ctx_isp->use_frame_header_ts = param.use_frame_header_ts; ctx_isp->support_consumed_addr = param.support_consumed_addr; /* Query the context has rdi only resource */ hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; Loading drivers/cam_isp/cam_isp_context.h +3 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_ISP_CONTEXT_H_ Loading Loading @@ -255,6 +256,7 @@ struct cam_isp_context_event_record { * @split_acquire: Indicate whether a separate acquire is expected * @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 * @init_timestamp: Timestamp at which this context is initialized * @rxd_epoch: Indicate whether epoch has been received. Used to * decide whether to apply request in offline ctx Loading Loading @@ -299,6 +301,7 @@ struct cam_isp_context { bool split_acquire; bool custom_enabled; bool use_frame_header_ts; bool support_consumed_addr; unsigned int init_timestamp; atomic_t rxd_epoch; struct cam_req_mgr_core_workq *workq; Loading drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +36 −3 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/slab.h> Loading Loading @@ -2974,6 +2975,32 @@ static int cam_ife_mgr_acquire_get_unified_structure( return 0; } static bool cam_ife_mgr_is_consumed_addr_supported( struct cam_ife_hw_mgr_ctx *ctx) { bool support_consumed_addr = false; struct cam_ife_hw_mgr_res *isp_hw_res = NULL; struct cam_hw_intf *hw_intf = NULL; isp_hw_res = &ctx->res_list_ife_out[0]; if (!isp_hw_res || !isp_hw_res->hw_res[0]) { CAM_ERR(CAM_ISP, "Invalid ife out res."); goto end; } hw_intf = isp_hw_res->hw_res[0]->hw_intf; if (hw_intf && hw_intf->hw_ops.process_cmd) { hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, CAM_ISP_HW_CMD_IS_CONSUMED_ADDR_SUPPORT, &support_consumed_addr, sizeof(support_consumed_addr)); } end: return support_consumed_addr; } /* entry function: acquire_hw */ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) { Loading Loading @@ -3110,6 +3137,9 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) goto free_res; } acquire_args->support_consumed_addr = cam_ife_mgr_is_consumed_addr_supported(ife_ctx); acquire_args->ctxt_to_hw_map = ife_ctx; acquire_args->custom_enabled = ife_ctx->custom_enabled; acquire_args->use_frame_header_ts = ife_ctx->use_frame_header_ts; Loading Loading @@ -7447,7 +7477,7 @@ static int cam_ife_hw_mgr_handle_hw_epoch( CAM_ISP_HW_EVENT_EPOCH); if (!rc) { epoch_done_event_data.frame_id_meta = event_info->th_reg_val; event_info->reg_val; ife_hw_irq_epoch_cb(ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_EPOCH, &epoch_done_event_data); } Loading Loading @@ -7622,6 +7652,8 @@ static int cam_ife_hw_mgr_handle_hw_buf_done( buf_done_event_data.num_handles = 1; buf_done_event_data.resource_handle[0] = event_info->res_id; buf_done_event_data.last_consumed_addr[0] = event_info->reg_val; if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) return 0; Loading @@ -7632,8 +7664,9 @@ static int cam_ife_hw_mgr_handle_hw_buf_done( CAM_ISP_HW_EVENT_DONE, &buf_done_event_data); } CAM_DBG(CAM_ISP, "Buf done for VFE:%d out_res->res_id: 0x%x", event_info->hw_idx, event_info->res_id); CAM_DBG(CAM_ISP, "Buf done for VFE:%d res_id: 0x%x last consumed addr: 0x%x", event_info->hw_idx, event_info->res_id, event_info->reg_val); return 0; } Loading drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +4 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_ISP_HW_MGR_INTF_H_ Loading Loading @@ -187,6 +188,7 @@ struct cam_isp_hw_epoch_event_data { * * @num_handles: Number of resource handeles * @resource_handle: Resource handle array * @last_consumed_addr: Last consumed addr * @timestamp: Timestamp for the buf done event * */ Loading @@ -194,6 +196,8 @@ struct cam_isp_hw_done_event_data { uint32_t num_handles; uint32_t resource_handle[ CAM_NUM_OUT_PER_COMP_IRQ_MAX]; uint32_t last_consumed_addr[ CAM_NUM_OUT_PER_COMP_IRQ_MAX]; uint64_t timestamp; }; Loading Loading
drivers/cam_core/cam_hw_mgr_intf.h +3 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_HW_MGR_INTF_H_ Loading Loading @@ -106,6 +107,7 @@ struct cam_hw_done_event_data { * @ctxt_to_hw_map: HW context (returned) * @custom_enabled: ctx has custom enabled * @use_frame_header_ts: Use frame header for qtimer ts * @support_consumed_addr: The platform has last consumed addr register * @acquired_hw_id: Acquired hardware mask * @acquired_hw_path: Acquired path mask for an input * if input splits into multiple paths, Loading @@ -123,6 +125,7 @@ struct cam_hw_acquire_args { void *ctxt_to_hw_map; bool custom_enabled; bool use_frame_header_ts; bool support_consumed_addr; uint32_t acquired_hw_id[CAM_MAX_ACQ_RES]; uint32_t acquired_hw_path[CAM_MAX_ACQ_RES][CAM_MAX_HW_SPLIT]; Loading
drivers/cam_isp/cam_isp_context.c +317 −78 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/debugfs.h> Loading Loading @@ -738,6 +739,70 @@ static void __cam_isp_ctx_handle_buf_done_fail_log( } } static int __cam_isp_ctx_handle_buf_done_for_req_list( struct cam_isp_context *ctx_isp, struct cam_ctx_request *req) { int rc = 0, i; uint64_t buf_done_req_id; struct cam_isp_ctx_req *req_isp; struct cam_context *ctx = ctx_isp->base; req_isp = (struct cam_isp_ctx_req *) req->req_priv; ctx_isp->active_req_cnt--; buf_done_req_id = req->request_id; if (req_isp->bubble_detected && req_isp->bubble_report) { req_isp->num_acked = 0; req_isp->bubble_detected = false; list_del_init(&req->list); atomic_set(&ctx_isp->process_bubble, 0); if (buf_done_req_id <= ctx->last_flush_req) { for (i = 0; i < req_isp->num_fence_map_out; i++) rc = cam_sync_signal( req_isp->fence_map_out[i].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); list_add_tail(&req->list, &ctx->free_req_list); CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [flushed], ctx %u", buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); } else { list_add(&req->list, &ctx->pending_req_list); CAM_DBG(CAM_REQ, "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", req->request_id, ctx_isp->active_req_cnt, ctx->ctx_id); } } else { if (!ctx_isp->use_frame_header_ts) { if (ctx_isp->reported_req_id < buf_done_req_id) { ctx_isp->reported_req_id = buf_done_req_id; __cam_isp_ctx_send_sof_timestamp(ctx_isp, buf_done_req_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); } } list_del_init(&req->list); list_add_tail(&req->list, &ctx->free_req_list); req_isp->reapply = false; CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [all fences done], ctx %u", buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); ctx_isp->req_info.last_bufdone_req_id = req->request_id; } __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); __cam_isp_ctx_update_event_record(ctx_isp, CAM_ISP_CTX_EVENT_BUFDONE, req); return rc; } static int __cam_isp_ctx_handle_buf_done_for_request( struct cam_isp_context *ctx_isp, struct cam_ctx_request *req, Loading @@ -749,7 +814,6 @@ static int __cam_isp_ctx_handle_buf_done_for_request( int i, j; struct cam_isp_ctx_req *req_isp; struct cam_context *ctx = ctx_isp->base; uint64_t buf_done_req_id; trace_cam_buf_done("ISP", ctx, req); Loading @@ -758,10 +822,8 @@ static int __cam_isp_ctx_handle_buf_done_for_request( CAM_DBG(CAM_ISP, "Enter with bubble_state %d, req_bubble_detected %d", bubble_state, req_isp->bubble_detected); if (done_next_req) { done_next_req->num_handles = 0; done_next_req->timestamp = done->timestamp; } for (i = 0; i < done->num_handles; i++) { for (j = 0; j < req_isp->num_fence_map_out; j++) { Loading @@ -771,14 +833,14 @@ static int __cam_isp_ctx_handle_buf_done_for_request( } if (j == req_isp->num_fence_map_out) { if (done_next_req) { /* * If not found in current request, it could be * belonging to next request, This can happen if * IRQ delay happens. * belonging to next request, this can happen if * IRQ delay happens. It is only valid when the * platform doesn't have last consumed address. */ CAM_WARN(CAM_ISP, "BUF_DONE for res 0x%x not found in Req %lld ", "BUF_DONE for res %s not found in Req %lld ", __cam_isp_resource_handle_id_to_type( done->resource_handle[i]), req->request_id); Loading @@ -786,13 +848,6 @@ static int __cam_isp_ctx_handle_buf_done_for_request( done_next_req->resource_handle [done_next_req->num_handles++] = done->resource_handle[i]; } else { CAM_ERR(CAM_ISP, "Can not find matching lane handle 0x%x! in Req %lld", done->resource_handle[i], req->request_id); rc = -EINVAL; } continue; } Loading @@ -807,12 +862,9 @@ static int __cam_isp_ctx_handle_buf_done_for_request( done->resource_handle[i]), req->request_id, ctx->ctx_id); if (done_next_req) { done_next_req->resource_handle [done_next_req->num_handles++] = done->resource_handle[i]; } continue; } Loading Loading @@ -885,66 +937,145 @@ static int __cam_isp_ctx_handle_buf_done_for_request( if (req_isp->num_acked != req_isp->num_fence_map_out) return rc; ctx_isp->active_req_cnt--; buf_done_req_id = req->request_id; rc = __cam_isp_ctx_handle_buf_done_for_req_list(ctx_isp, req); return rc; } if (req_isp->bubble_detected && req_isp->bubble_report) { req_isp->num_acked = 0; 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; 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) { int rc = 0; int i, j; struct cam_isp_ctx_req *req_isp; struct cam_context *ctx = ctx_isp->base; const char *handle_type; if (buf_done_req_id <= ctx->last_flush_req) { for (i = 0; i < req_isp->num_fence_map_out; i++) cam_sync_signal( req_isp->fence_map_out[i].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); trace_cam_buf_done("ISP", ctx, req); list_add_tail(&req->list, &ctx->free_req_list); CAM_DBG(CAM_REQ, "Move active request %lld to free list(cnt = %d) [flushed], ctx %u", buf_done_req_id, ctx_isp->active_req_cnt, req_isp = (struct cam_isp_ctx_req *) req->req_priv; CAM_DBG(CAM_ISP, "Enter with bubble_state %d, req_bubble_detected %d", bubble_state, req_isp->bubble_detected); for (i = 0; i < done->num_handles; i++) { for (j = 0; j < req_isp->num_fence_map_out; j++) { if (verify_consumed_addr && (done->last_consumed_addr[i] != req_isp->fence_map_out[j].image_buf_addr[0])) continue; if (done->resource_handle[i] == req_isp->fence_map_out[j].resource_handle) break; } if (j == req_isp->num_fence_map_out) { /* * If not found in current request, it could be * belonging to next request, this can happen if * IRQ delay happens. It is only valid when the * platform doesn't have last consumed address. */ CAM_DBG(CAM_ISP, "BUF_DONE for res %s not found in Req %lld ", __cam_isp_resource_handle_id_to_type( done->resource_handle[i]), req->request_id); continue; } if (req_isp->fence_map_out[j].sync_id == -1) { handle_type = __cam_isp_resource_handle_id_to_type( req_isp->fence_map_out[i].resource_handle); CAM_WARN(CAM_ISP, "Duplicate BUF_DONE for req %lld : i=%d, j=%d, res=%s", req->request_id, i, j, handle_type); trace_cam_log_event("Duplicate BufDone", handle_type, req->request_id, ctx->ctx_id); continue; } 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, req_isp->fence_map_out[j].resource_handle, req_isp->fence_map_out[j].sync_id, ctx->ctx_id); } else { list_add(&req->list, &ctx->pending_req_list); ctx_isp->bubble_frame_cnt = 0; CAM_DBG(CAM_REQ, "Move active request %lld to pending list(cnt = %d) [bubble recovery], ctx %u", req->request_id, ctx_isp->active_req_cnt, rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, CAM_SYNC_STATE_SIGNALED_SUCCESS); if (rc) CAM_DBG(CAM_ISP, "Sync failed with rc = %d", rc); } else if (!req_isp->bubble_report) { CAM_ERR(CAM_ISP, "Sync with failure: req %lld res 0x%x fd 0x%x, ctx %u", req->request_id, req_isp->fence_map_out[j].resource_handle, req_isp->fence_map_out[j].sync_id, ctx->ctx_id); } rc = cam_sync_signal(req_isp->fence_map_out[j].sync_id, CAM_SYNC_STATE_SIGNALED_ERROR); if (rc) CAM_ERR(CAM_ISP, "Sync failed with rc = %d", rc); } else { /* * Ignore the buffer done if bubble detect is on * Increment the ack number here, and queue the * request back to pending list whenever all the * buffers are done. */ req_isp->num_acked++; CAM_DBG(CAM_ISP, "buf done with bubble state %d recovery %d", bubble_state, req_isp->bubble_report); continue; } if (!ctx_isp->use_frame_header_ts) { if (ctx_isp->reported_req_id < buf_done_req_id) { ctx_isp->reported_req_id = buf_done_req_id; __cam_isp_ctx_send_sof_timestamp(ctx_isp, buf_done_req_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); CAM_DBG(CAM_ISP, "req %lld, reset sync id 0x%x ctx %u", req->request_id, req_isp->fence_map_out[j].sync_id, ctx->ctx_id); if (!rc) { req_isp->num_acked++; req_isp->fence_map_out[j].sync_id = -1; } if ((ctx_isp->use_frame_header_ts) && (req_isp->hw_update_data.frame_header_res_id == req_isp->fence_map_out[j].resource_handle)) __cam_isp_ctx_send_sof_timestamp_frame_header( ctx_isp, req_isp->hw_update_data.frame_header_cpu_addr, req->request_id, CAM_REQ_MGR_SOF_EVENT_SUCCESS); } 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", buf_done_req_id, ctx_isp->active_req_cnt, ctx->ctx_id); ctx_isp->req_info.last_bufdone_req_id = req->request_id; if (req_isp->num_acked > req_isp->num_fence_map_out) { /* Should not happen */ CAM_ERR(CAM_ISP, "WARNING: req_id %lld num_acked %d > map_out %d, ctx %u", req->request_id, req_isp->num_acked, req_isp->num_fence_map_out, ctx->ctx_id); WARN_ON(req_isp->num_acked > req_isp->num_fence_map_out); } __cam_isp_ctx_update_state_monitor_array(ctx_isp, CAM_ISP_STATE_CHANGE_TRIGGER_DONE, buf_done_req_id); if (req_isp->num_acked != req_isp->num_fence_map_out) return rc; __cam_isp_ctx_update_event_record(ctx_isp, CAM_ISP_CTX_EVENT_BUFDONE, req); rc = __cam_isp_ctx_handle_buf_done_for_req_list(ctx_isp, req); return rc; } static int __cam_isp_ctx_handle_buf_done_in_activated_state( static int __cam_isp_ctx_handle_buf_done( struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done, uint32_t bubble_state) Loading Loading @@ -1008,6 +1139,111 @@ static int __cam_isp_ctx_handle_buf_done_in_activated_state( return rc; } static void __cam_isp_ctx_buf_done_match_req( struct cam_ctx_request *req, struct cam_isp_hw_done_event_data *done, bool *irq_delay_detected) { int i, j; uint32_t match_count = 0; struct cam_isp_ctx_req *req_isp; req_isp = (struct cam_isp_ctx_req *) req->req_priv; for (i = 0; i < done->num_handles; i++) { for (j = 0; j < req_isp->num_fence_map_out; j++) { if ((done->resource_handle[i] == req_isp->fence_map_out[j].resource_handle) && (done->last_consumed_addr[i] == req_isp->fence_map_out[j].image_buf_addr[0])) { match_count++; break; } } } if (match_count > 0) *irq_delay_detected = true; else *irq_delay_detected = false; CAM_DBG(CAM_ISP, "buf done num handles %d match count %d for next req:%lld", done->num_handles, match_count, req->request_id); } static int __cam_isp_ctx_handle_buf_done_verify_addr( struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done, uint32_t bubble_state) { int rc = 0; bool irq_delay_detected = false; struct cam_ctx_request *req; struct cam_ctx_request *next_req = NULL; struct cam_context *ctx = ctx_isp->base; if (list_empty(&ctx->active_req_list)) { CAM_DBG(CAM_ISP, "Buf done with no active request"); return 0; } req = list_first_entry(&ctx->active_req_list, struct cam_ctx_request, list); if (ctx_isp->active_req_cnt > 1) { next_req = list_last_entry( &ctx->active_req_list, struct cam_ctx_request, list); if (next_req->request_id != req->request_id) __cam_isp_ctx_buf_done_match_req(next_req, done, &irq_delay_detected); else CAM_WARN(CAM_ISP, "Req %lld only active request, spurious buf_done rxd", req->request_id); } /* * If irq delay isn't detected, then we need to verify * the consumed address for current req, otherwise, we * can't verify the consumed address. */ rc = __cam_isp_ctx_handle_buf_done_for_request_verify_addr( ctx_isp, req, done, bubble_state, !irq_delay_detected); /* * Verify the consumed address for next req all the time, * since the reported buf done event may belong to current * req, then we can't signal this event for next req. */ if (!rc && irq_delay_detected) rc = __cam_isp_ctx_handle_buf_done_for_request_verify_addr( ctx_isp, next_req, done, bubble_state, true); return rc; } static int __cam_isp_ctx_handle_buf_done_in_activated_state( struct cam_isp_context *ctx_isp, struct cam_isp_hw_done_event_data *done, uint32_t bubble_state) { int rc = 0; if (ctx_isp->support_consumed_addr) rc = __cam_isp_ctx_handle_buf_done_verify_addr( ctx_isp, done, bubble_state); else rc = __cam_isp_ctx_handle_buf_done( ctx_isp, done, bubble_state); return rc; } static int __cam_isp_ctx_apply_req_offline( void *priv, void *data) { Loading Loading @@ -3773,6 +4009,7 @@ static int __cam_isp_ctx_release_hw_in_top_state(struct cam_context *ctx, ctx_isp->reported_req_id = 0; ctx_isp->hw_acquired = false; ctx_isp->init_received = false; ctx_isp->support_consumed_addr = false; ctx_isp->req_info.last_bufdone_req_id = 0; atomic64_set(&ctx_isp->state_monitor_head, -1); Loading Loading @@ -4450,6 +4687,8 @@ static int __cam_isp_ctx_acquire_hw_v2(struct cam_context *ctx, */ ctx_isp->custom_enabled = param.custom_enabled; ctx_isp->use_frame_header_ts = param.use_frame_header_ts; ctx_isp->support_consumed_addr = param.support_consumed_addr; /* Query the context has rdi only resource */ hw_cmd_args.ctxt_to_hw_map = param.ctxt_to_hw_map; Loading
drivers/cam_isp/cam_isp_context.h +3 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_ISP_CONTEXT_H_ Loading Loading @@ -255,6 +256,7 @@ struct cam_isp_context_event_record { * @split_acquire: Indicate whether a separate acquire is expected * @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 * @init_timestamp: Timestamp at which this context is initialized * @rxd_epoch: Indicate whether epoch has been received. Used to * decide whether to apply request in offline ctx Loading Loading @@ -299,6 +301,7 @@ struct cam_isp_context { bool split_acquire; bool custom_enabled; bool use_frame_header_ts; bool support_consumed_addr; unsigned int init_timestamp; atomic_t rxd_epoch; struct cam_req_mgr_core_workq *workq; Loading
drivers/cam_isp/isp_hw_mgr/cam_ife_hw_mgr.c +36 −3 Original line number Diff line number Diff line // SPDX-License-Identifier: GPL-2.0-only /* * Copyright (c) 2017-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #include <linux/slab.h> Loading Loading @@ -2974,6 +2975,32 @@ static int cam_ife_mgr_acquire_get_unified_structure( return 0; } static bool cam_ife_mgr_is_consumed_addr_supported( struct cam_ife_hw_mgr_ctx *ctx) { bool support_consumed_addr = false; struct cam_ife_hw_mgr_res *isp_hw_res = NULL; struct cam_hw_intf *hw_intf = NULL; isp_hw_res = &ctx->res_list_ife_out[0]; if (!isp_hw_res || !isp_hw_res->hw_res[0]) { CAM_ERR(CAM_ISP, "Invalid ife out res."); goto end; } hw_intf = isp_hw_res->hw_res[0]->hw_intf; if (hw_intf && hw_intf->hw_ops.process_cmd) { hw_intf->hw_ops.process_cmd(hw_intf->hw_priv, CAM_ISP_HW_CMD_IS_CONSUMED_ADDR_SUPPORT, &support_consumed_addr, sizeof(support_consumed_addr)); } end: return support_consumed_addr; } /* entry function: acquire_hw */ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) { Loading Loading @@ -3110,6 +3137,9 @@ static int cam_ife_mgr_acquire_hw(void *hw_mgr_priv, void *acquire_hw_args) goto free_res; } acquire_args->support_consumed_addr = cam_ife_mgr_is_consumed_addr_supported(ife_ctx); acquire_args->ctxt_to_hw_map = ife_ctx; acquire_args->custom_enabled = ife_ctx->custom_enabled; acquire_args->use_frame_header_ts = ife_ctx->use_frame_header_ts; Loading Loading @@ -7447,7 +7477,7 @@ static int cam_ife_hw_mgr_handle_hw_epoch( CAM_ISP_HW_EVENT_EPOCH); if (!rc) { epoch_done_event_data.frame_id_meta = event_info->th_reg_val; event_info->reg_val; ife_hw_irq_epoch_cb(ife_hw_mgr_ctx->common.cb_priv, CAM_ISP_HW_EVENT_EPOCH, &epoch_done_event_data); } Loading Loading @@ -7622,6 +7652,8 @@ static int cam_ife_hw_mgr_handle_hw_buf_done( buf_done_event_data.num_handles = 1; buf_done_event_data.resource_handle[0] = event_info->res_id; buf_done_event_data.last_consumed_addr[0] = event_info->reg_val; if (atomic_read(&ife_hw_mgr_ctx->overflow_pending)) return 0; Loading @@ -7632,8 +7664,9 @@ static int cam_ife_hw_mgr_handle_hw_buf_done( CAM_ISP_HW_EVENT_DONE, &buf_done_event_data); } CAM_DBG(CAM_ISP, "Buf done for VFE:%d out_res->res_id: 0x%x", event_info->hw_idx, event_info->res_id); CAM_DBG(CAM_ISP, "Buf done for VFE:%d res_id: 0x%x last consumed addr: 0x%x", event_info->hw_idx, event_info->res_id, event_info->reg_val); return 0; } Loading
drivers/cam_isp/isp_hw_mgr/include/cam_isp_hw_mgr_intf.h +4 −0 Original line number Diff line number Diff line /* SPDX-License-Identifier: GPL-2.0-only */ /* * Copyright (c) 2016-2021, The Linux Foundation. All rights reserved. * Copyright (c) 2022 Qualcomm Innovation Center, Inc. All rights reserved. */ #ifndef _CAM_ISP_HW_MGR_INTF_H_ Loading Loading @@ -187,6 +188,7 @@ struct cam_isp_hw_epoch_event_data { * * @num_handles: Number of resource handeles * @resource_handle: Resource handle array * @last_consumed_addr: Last consumed addr * @timestamp: Timestamp for the buf done event * */ Loading @@ -194,6 +196,8 @@ struct cam_isp_hw_done_event_data { uint32_t num_handles; uint32_t resource_handle[ CAM_NUM_OUT_PER_COMP_IRQ_MAX]; uint32_t last_consumed_addr[ CAM_NUM_OUT_PER_COMP_IRQ_MAX]; uint64_t timestamp; }; Loading