msm: camera: isp: Stop HW immediately in flush

When the userspace issues flush, ISP driver needs to ensure that
wait and active list requests are flushed and corresponding
buffer fences are signaled with error. For active and wait lists
IFE hardware is stopped immediately. Therefore IFE must also be
reset to ensure that VFE BUS FIFOs are cleared. Start IFE HW
after receiving init packet again.

CRs-Fixed: 2513939
Change-Id: I9a35ce05c24d6b63016e264a870d376eabb2b56f
Signed-off-by: Venkat Chinta <vchinta@codeaurora.org>
This commit is contained in:
Venkat Chinta
2019-08-02 16:03:51 -07:00
committed by Gerrit - the friendly Code Review server
parent a5dc6c6cac
commit aaab1ef87e
9 changed files with 216 additions and 30 deletions

View File

@@ -31,6 +31,9 @@ static struct cam_isp_ctx_debug isp_ctx_debug;
static int cam_isp_context_dump_active_request(void *data, unsigned long iova,
uint32_t buf_info);
static int __cam_isp_ctx_start_dev_in_ready(struct cam_context *ctx,
struct cam_start_stop_dev_cmd *cmd);
static void __cam_isp_ctx_update_state_monitor_array(
struct cam_isp_context *ctx_isp,
enum cam_isp_state_change_trigger trigger_type,
@@ -2072,13 +2075,15 @@ static int __cam_isp_ctx_flush_req(struct cam_context *ctx,
}
static int __cam_isp_ctx_flush_req_in_top_state(
struct cam_context *ctx,
struct cam_context *ctx,
struct cam_req_mgr_flush_request *flush_req)
{
int rc = 0;
struct cam_isp_context *ctx_isp;
struct cam_hw_cmd_args hw_cmd_args;
int rc = 0;
struct cam_isp_context *ctx_isp;
struct cam_isp_stop_args stop_isp;
struct cam_hw_stop_args stop_args;
struct cam_hw_reset_args reset_args;
struct cam_hw_cmd_args hw_cmd_args;
ctx_isp = (struct cam_isp_context *) ctx->ctx_priv;
if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) {
@@ -2087,7 +2092,7 @@ static int __cam_isp_ctx_flush_req_in_top_state(
ctx->last_flush_req = flush_req->req_id;
}
CAM_DBG(CAM_ISP, "try to flush pending list");
CAM_DBG(CAM_ISP, "Flush pending list");
spin_lock_bh(&ctx->lock);
rc = __cam_isp_ctx_flush_req(ctx, &ctx->pending_req_list, flush_req);
spin_unlock_bh(&ctx->lock);
@@ -2102,6 +2107,47 @@ static int __cam_isp_ctx_flush_req_in_top_state(
rc = 0;
}
if (flush_req->type == CAM_REQ_MGR_FLUSH_TYPE_ALL) {
if (ctx->state <= CAM_CTX_READY) {
ctx->state = CAM_CTX_ACQUIRED;
goto end;
}
stop_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
stop_isp.hw_stop_cmd = CAM_ISP_HW_STOP_IMMEDIATELY;
stop_isp.stop_only = true;
stop_args.args = (void *)&stop_isp;
rc = ctx->hw_mgr_intf->hw_stop(ctx->hw_mgr_intf->hw_mgr_priv,
&stop_args);
if (rc)
CAM_ERR(CAM_ISP, "Failed to stop HW in Flush rc: %d",
rc);
CAM_DBG(CAM_ISP, "Flush wait and active lists");
spin_lock_bh(&ctx->lock);
if (!list_empty(&ctx->wait_req_list))
rc = __cam_isp_ctx_flush_req(ctx, &ctx->wait_req_list,
flush_req);
if (!list_empty(&ctx->active_req_list))
rc = __cam_isp_ctx_flush_req(ctx, &ctx->active_req_list,
flush_req);
ctx_isp->active_req_cnt = 0;
spin_unlock_bh(&ctx->lock);
reset_args.ctxt_to_hw_map = ctx_isp->hw_ctx;
rc = ctx->hw_mgr_intf->hw_reset(ctx->hw_mgr_intf->hw_mgr_priv,
&reset_args);
if (rc)
CAM_ERR(CAM_ISP, "Failed to reset HW rc: %d", rc);
ctx->state = CAM_CTX_FLUSHED;
ctx_isp->substate_activated = CAM_ISP_CTX_ACTIVATED_HALT;
ctx_isp->init_received = false;
}
end:
atomic_set(&ctx_isp->process_bubble, 0);
return rc;
}
@@ -3454,6 +3500,55 @@ static int __cam_isp_ctx_config_dev_in_acquired(struct cam_context *ctx,
return rc;
}
static int __cam_isp_ctx_config_dev_in_flushed(struct cam_context *ctx,
struct cam_config_dev_cmd *cmd)
{
int rc = 0;
struct cam_start_stop_dev_cmd start_cmd;
struct cam_hw_cmd_args hw_cmd_args;
struct cam_isp_hw_cmd_args isp_hw_cmd_args;
struct cam_isp_context *ctx_isp =
(struct cam_isp_context *) ctx->ctx_priv;
if (!ctx_isp->hw_acquired) {
CAM_ERR(CAM_ISP, "HW is not acquired, reject packet");
return -EINVAL;
}
rc = __cam_isp_ctx_config_dev_in_top_state(ctx, cmd);
if (rc)
return rc;
if (!ctx_isp->init_received) {
CAM_WARN(CAM_ISP,
"Received update packet in flushed state, skip start");
goto end;
}
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_CMD_RESUME_HW;
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, "Failed to resume HW rc: %d", rc);
return rc;
}
start_cmd.dev_handle = cmd->dev_handle;
start_cmd.session_handle = cmd->session_handle;
rc = __cam_isp_ctx_start_dev_in_ready(ctx, &start_cmd);
if (rc)
CAM_ERR(CAM_ISP,
"Failed to re-start HW after flush rc: %d", rc);
end:
CAM_DBG(CAM_ISP, "next state %d sub_state:%d", ctx->state,
ctx_isp->substate_activated);
return rc;
}
static int __cam_isp_ctx_link_in_acquired(struct cam_context *ctx,
struct cam_req_mgr_core_dev_link_setup *link)
{
@@ -3543,7 +3638,11 @@ 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.start_only = false;
if (ctx->state == CAM_CTX_FLUSHED)
start_isp.start_only = true;
else
start_isp.start_only = false;
atomic_set(&ctx_isp->process_bubble, 0);
ctx_isp->frame_id = 0;
@@ -3966,6 +4065,22 @@ static struct cam_ctx_ops
.pagefault_ops = cam_isp_context_dump_active_request,
.dumpinfo_ops = cam_isp_context_info_dump,
},
/* Flushed */
{
.ioctl_ops = {
.stop_dev = __cam_isp_ctx_stop_dev_in_activated,
.release_dev = __cam_isp_ctx_release_dev_in_activated,
.config_dev = __cam_isp_ctx_config_dev_in_flushed,
.release_hw = __cam_isp_ctx_release_hw_in_activated,
},
.crm_ops = {
.unlink = __cam_isp_ctx_unlink_in_ready,
.process_evt = __cam_isp_ctx_process_evt,
},
.irq_ops = NULL,
.pagefault_ops = cam_isp_context_dump_active_request,
.dumpinfo_ops = cam_isp_context_info_dump,
},
/* Activated */
{
.ioctl_ops = {