From 28e17c1f65059cb0608003f30bdfaf9ecf3cf8f7 Mon Sep 17 00:00:00 2001 From: Srikanth Uyyala Date: Fri, 22 Mar 2019 10:41:46 +0530 Subject: [PATCH 1/3] msm: camera_v2: isp: handle frame drop due to scheduling latency There is possibility that due to scheduling latency of tasklet, user threads VFE hardware could not be updated intime resulting in fatal error, invalid memory access. Added logic to track and gracefully handle the scheduling issues. Change-Id: I29acde4fe23a59e6ff0e5190e1c4b9c59f6ae08f Signed-off-by: Srikanth Uyyala Signed-off-by: Sumalatha Malothu --- .../platform/msm/camera_v2/isp/msm_isp.h | 6 ++- .../platform/msm/camera_v2/isp/msm_isp47.c | 6 ++- .../msm/camera_v2/isp/msm_isp_axi_util.c | 49 ++++++++++++++++--- .../platform/msm/camera_v2/isp/msm_isp_util.c | 5 +- 4 files changed, 53 insertions(+), 13 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index 9bc6fde36774..cef2cd9ffcf1 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -746,6 +746,7 @@ struct msm_vfe_common_dev_data { /* Irq debug Info */ struct msm_vfe_irq_dump vfe_irq_dump; struct msm_vfe_tasklet tasklets[MAX_VFE + 1]; + uint32_t drop_reconfig; }; struct msm_vfe_common_subdev { @@ -848,6 +849,9 @@ struct vfe_device { /* total bandwidth per vfe */ uint64_t total_bandwidth; struct isp_kstate *isp_page; + + /* irq info */ + uint32_t irq_sof_id; }; struct vfe_parent_device { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c index a8341a7ff3e6..cf9e7547d4e2 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp47.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -714,8 +714,10 @@ void msm_isp47_preprocess_camif_irq(struct vfe_device *vfe_dev, { if (irq_status0 & BIT(3)) vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = false; - if (irq_status0 & BIT(0)) + if (irq_status0 & BIT(0)) { vfe_dev->axi_data.src_info[VFE_PIX_0].accept_frame = true; + vfe_dev->irq_sof_id++; + } } void msm_vfe47_reg_update(struct vfe_device *vfe_dev, diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 79b45b6678b0..011a1d4019eb 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -662,9 +662,11 @@ void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev, __msm_isp_axi_stream_update(stream_info, ts); break; case MSM_ISP_COMP_IRQ_EPOCH: - if (stream_info->state == ACTIVE) + if (stream_info->state == ACTIVE) { msm_isp_update_framedrop_reg(stream_info, - vfe_dev->isp_page->drop_reconfig); + vfe_dev->common_data->drop_reconfig); + vfe_dev->common_data->drop_reconfig = 0; + } break; default: WARN(1, "Invalid irq %d\n", irq); @@ -2739,6 +2741,7 @@ int msm_isp_axi_reset(struct vfe_device *vfe_dev, axi_data->src_info[SRC_TO_INTF(stream_info-> stream_src)].frame_id = reset_cmd->frame_id; + temp_vfe_dev->irq_sof_id = reset_cmd->frame_id; } msm_isp_reset_burst_count_and_frame_drop( vfe_dev, stream_info); @@ -3011,6 +3014,7 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, msm_isp_cfg_stream_scratch(stream_info, VFE_PING_FLAG); msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); stream_info->undelivered_request_cnt = 0; + vfe_dev->irq_sof_id = 0; for (k = 0; k < stream_info->num_isp; k++) { vfe_dev = stream_info->vfe_dev[k]; if (stream_info->num_planes > 1) @@ -3174,7 +3178,6 @@ static int msm_isp_start_axi_stream(struct vfe_device *vfe_dev_ioctl, mutex_unlock(&vfe_dev_ioctl->buf_mgr->lock); goto error; } - msm_isp_calculate_bandwidth(stream_info); for (k = 0; k < stream_info->num_isp; k++) { msm_isp_get_stream_wm_mask(stream_info->vfe_dev[k], @@ -3520,16 +3523,25 @@ static int msm_isp_request_frame(struct vfe_device *vfe_dev, */ if (vfe_dev->axi_data.src_info[frame_src].active && frame_src == VFE_PIX_0 && - vfe_dev->axi_data.src_info[frame_src].accept_frame == false) { + vfe_dev->axi_data.src_info[frame_src].accept_frame == false && + (stream_info->undelivered_request_cnt <= + MAX_BUFFERS_IN_HW) + ) { pr_debug("%s:%d invalid time to request frame %d\n", __func__, __LINE__, frame_id); vfe_dev->isp_page->drop_reconfig = 1; + /*keep it in vfe_dev variable also to avoid skip pattern + * programming the variable in page can be overwritten by MCT + */ + vfe_dev->common_data->drop_reconfig = 1; } else if ((vfe_dev->axi_data.src_info[frame_src].active) && - (frame_id == - vfe_dev->axi_data.src_info[frame_src].frame_id) && + ((frame_id == + vfe_dev->axi_data.src_info[frame_src].frame_id) || + (frame_id == vfe_dev->irq_sof_id)) && (stream_info->undelivered_request_cnt <= MAX_BUFFERS_IN_HW)) { vfe_dev->isp_page->drop_reconfig = 1; + vfe_dev->common_data->drop_reconfig = 1; pr_debug("%s: vfe_%d request_frame %d cur frame id %d pix %d\n", __func__, vfe_dev->pdev->id, frame_id, vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, @@ -4263,9 +4275,25 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, ISP_DBG("%s: Error configuring ping_pong\n", __func__); } else if (done_buf && (done_buf->is_drop_reconfig != 1)) { + int32_t frame_id_diff; + /* irq_sof should be always >= tasklet SOF id + * For dual camera usecase irq_sof could be behind + * as software frameid sync logic epoch event could + * update slave frame id so update if irqsof < tasklet sof + */ + if (vfe_dev->irq_sof_id < frame_id) + vfe_dev->irq_sof_id = frame_id; + + frame_id_diff = vfe_dev->irq_sof_id - frame_id; + if (stream_info->controllable_output && frame_id_diff > 1) { + /*scheduling problem need to do recovery*/ + spin_unlock_irqrestore(&stream_info->lock, flags); + msm_isp_halt_send_error(vfe_dev, + ISP_EVENT_PING_PONG_MISMATCH); + return; + } msm_isp_cfg_stream_scratch(stream_info, pingpong_status); } - if (!done_buf) { if (stream_info->buf_divert) { vfe_dev->error_info.stream_framedrop_count[ @@ -4314,6 +4342,11 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, * then dont issue buf-done for current buffer */ done_buf->is_drop_reconfig = 0; + if (!stream_info->buf[pingpong_bit]) { + /*samebuffer is not re-programeed so program scratch*/ + msm_isp_cfg_stream_scratch(stream_info, + pingpong_status); + } spin_unlock_irqrestore(&stream_info->lock, flags); } else { spin_unlock_irqrestore(&stream_info->lock, flags); diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 684b331d9ac4..05c955ac7cd5 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -1,4 +1,4 @@ -/* Copyright (c) 2013-2018, The Linux Foundation. All rights reserved. +/* Copyright (c) 2013-2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -2291,7 +2291,8 @@ int msm_isp_open_node(struct v4l2_subdev *sd, struct v4l2_subdev_fh *fh) vfe_dev->isp_raw0_debug = 0; vfe_dev->isp_raw1_debug = 0; vfe_dev->isp_raw2_debug = 0; - + vfe_dev->irq_sof_id = 0; + vfe_dev->common_data->drop_reconfig = 0; if (vfe_dev->hw_info->vfe_ops.core_ops.init_hw(vfe_dev) < 0) { pr_err("%s: init hardware failed\n", __func__); vfe_dev->vfe_open_cnt--; From 5974bd4025eab2158a28039d29a35d4afe2ec6bd Mon Sep 17 00:00:00 2001 From: Lokesh Kumar Aakulu Date: Mon, 11 Mar 2019 17:27:09 +0530 Subject: [PATCH 2/3] msm: camera_v2: Fix page fault issue in camera ISP Fix page fault in ISP when there is no reg update for two consecutive request frame time. Change-Id: Ie246f146c1ec0785e0e6fa0671dd2ff28fbe6b38 Signed-off-by: Lokesh Kumar Aakulu Signed-off-by: Sumalatha Malothu --- .../platform/msm/camera_v2/isp/msm_isp.h | 7 ++ .../msm/camera_v2/isp/msm_isp_axi_util.c | 67 ++++++++++++++++++- 2 files changed, 72 insertions(+), 2 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h index cef2cd9ffcf1..a6fbb4102c2c 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp.h +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp.h @@ -416,6 +416,12 @@ enum msm_isp_comp_irq_types { #define MSM_VFE_REQUESTQ_SIZE 8 +struct msm_isp_pending_buf_info { + uint32_t is_buf_done_pending; + struct msm_isp_buffer *buf; + uint32_t frame_id; +}; + struct msm_vfe_axi_stream { uint32_t frame_id; enum msm_vfe_axi_state state; @@ -472,6 +478,7 @@ struct msm_vfe_axi_stream { uint32_t vfe_mask; uint32_t composite_irq[MSM_ISP_COMP_IRQ_MAX]; int lpm_mode; + struct msm_isp_pending_buf_info pending_buf_info; }; struct msm_vfe_axi_composite_info { diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index 011a1d4019eb..d498ef0ae7a6 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -27,6 +27,13 @@ static void __msm_isp_axi_stream_update( struct msm_vfe_axi_stream *stream_info, struct msm_isp_timestamp *ts); +static int msm_isp_process_done_buf(struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, struct msm_isp_buffer *buf, + struct timeval *time_stamp, uint32_t frame_id); +static void msm_isp_free_pending_buffer( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + struct msm_isp_timestamp *ts); static int msm_isp_update_stream_bandwidth( struct msm_vfe_axi_stream *stream_info, int enable); @@ -659,6 +666,10 @@ void msm_isp_process_reg_upd_epoch_irq(struct vfe_device *vfe_dev, case MSM_ISP_COMP_IRQ_REG_UPD: stream_info->activated_framedrop_period = stream_info->requested_framedrop_period; + /* Free Pending Buffers which are backed-up due to + * delay in RUP from userspace to Avoid pageFault + */ + msm_isp_free_pending_buffer(vfe_dev, stream_info, ts); __msm_isp_axi_stream_update(stream_info, ts); break; case MSM_ISP_COMP_IRQ_EPOCH: @@ -1523,6 +1534,40 @@ static void msm_isp_axi_stream_enable_cfg( } } +static void msm_isp_free_pending_buffer( + struct vfe_device *vfe_dev, + struct msm_vfe_axi_stream *stream_info, + struct msm_isp_timestamp *ts) +{ + struct timeval *time_stamp; + struct msm_isp_buffer *done_buf = NULL; + uint32_t frame_id; + int rc; + + if (!stream_info->controllable_output || + !stream_info->pending_buf_info.is_buf_done_pending) { + return; + } + + if (vfe_dev->vt_enable) { + msm_isp_get_avtimer_ts(ts); + time_stamp = &ts->vt_time; + } else { + time_stamp = &ts->buf_time; + } + + done_buf = stream_info->pending_buf_info.buf; + frame_id = stream_info->pending_buf_info.frame_id; + if (done_buf) { + rc = msm_isp_process_done_buf(vfe_dev, stream_info, + done_buf, time_stamp, frame_id); + if (rc == 0) { + stream_info->pending_buf_info.buf = NULL; + stream_info->pending_buf_info.is_buf_done_pending = 0; + } + } +} + static void __msm_isp_axi_stream_update( struct msm_vfe_axi_stream *stream_info, struct msm_isp_timestamp *ts) @@ -3015,6 +3060,12 @@ static void __msm_isp_stop_axi_streams(struct vfe_device *vfe_dev, msm_isp_cfg_stream_scratch(stream_info, VFE_PONG_FLAG); stream_info->undelivered_request_cnt = 0; vfe_dev->irq_sof_id = 0; + if (stream_info->controllable_output && + stream_info->pending_buf_info.is_buf_done_pending) { + msm_isp_free_pending_buffer(vfe_dev, stream_info, + ×tamp); + stream_info->pending_buf_info.is_buf_done_pending = 0; + } for (k = 0; k < stream_info->num_isp; k++) { vfe_dev = stream_info->vfe_dev[k]; if (stream_info->num_planes > 1) @@ -4349,9 +4400,21 @@ void msm_isp_process_axi_irq_stream(struct vfe_device *vfe_dev, } spin_unlock_irqrestore(&stream_info->lock, flags); } else { + /* If there is no regupdate from userspace then dont + * free buffer immediately, delegate it to RegUpdateAck + */ + if (stream_info->controllable_output && + !(vfe_dev->reg_update_requested & + BIT((uint32_t)VFE_PIX_0))) { + stream_info->pending_buf_info.is_buf_done_pending = 1; + stream_info->pending_buf_info.buf = done_buf; + stream_info->pending_buf_info.frame_id = frame_id; + } spin_unlock_irqrestore(&stream_info->lock, flags); - msm_isp_process_done_buf(vfe_dev, stream_info, - done_buf, time_stamp, frame_id); + if (stream_info->pending_buf_info.is_buf_done_pending != 1) { + msm_isp_process_done_buf(vfe_dev, stream_info, + done_buf, time_stamp, frame_id); + } } } From 45b4ac208b7bbea82bd9f5123c416cedfc991307 Mon Sep 17 00:00:00 2001 From: Srikanth Uyyala Date: Tue, 7 May 2019 16:27:36 +0530 Subject: [PATCH 3/3] msm:camera: add trace log support for VFE events trace log support added for important VFE events, these traces can be enabled with camera trace event. Change-Id: I1e5c043ad3b69df632ff63130ff8eea10ab2097c Signed-off-by: Srikanth Uyyala Signed-off-by: Sumalatha Malothu --- .../msm/camera_v2/isp/msm_isp_axi_util.c | 9 ++++-- .../platform/msm/camera_v2/isp/msm_isp_util.c | 7 +++++ include/trace/events/msm_cam.h | 30 ++++++++++++++++++- 3 files changed, 43 insertions(+), 3 deletions(-) diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c index d498ef0ae7a6..2245cca4f8c7 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c @@ -16,6 +16,7 @@ #include "msm_isp_stats_util.h" #include "msm_isp_axi_util.h" #include "msm_isp48.h" +#include "trace/events/msm_cam.h" #define HANDLE_TO_IDX(handle) (handle & 0xFF) #define ISP_SOF_DEBUG_COUNT 0 @@ -1048,8 +1049,12 @@ void msm_isp_notify(struct vfe_device *vfe_dev, uint32_t event_type, vfe_dev->isp_raw2_debug++; } - ISP_DBG("%s: vfe %d frame_src %d\n", __func__, - vfe_dev->pdev->id, frame_src); + ISP_DBG("%s: vfe %d frame_src %d frameid %d\n", __func__, + vfe_dev->pdev->id, frame_src, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id); + trace_msm_cam_isp_status_dump("SOFNOTIFY:", vfe_dev->pdev->id, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, + 0, 0); /* * Cannot support dual_cam and framedrop same time in union. diff --git a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c index 05c955ac7cd5..260d546c76ce 100644 --- a/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c +++ b/drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c @@ -2090,6 +2090,10 @@ static void msm_isp_enqueue_tasklet_cmd(struct vfe_device *vfe_dev, } else { atomic_add(1, &vfe_dev->irq_cnt); } + atomic_add(1, &vfe_dev->irq_cnt); + trace_msm_cam_isp_status_dump("VFE_IRQ:", vfe_dev->pdev->id, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, + irq_status0, irq_status1); queue_cmd->vfeInterruptStatus0 = irq_status0; queue_cmd->vfeInterruptStatus1 = irq_status1; queue_cmd->vfe_pingpong_status = ping_pong_status; @@ -2189,6 +2193,9 @@ void msm_isp_do_tasklet(unsigned long data) atomic_sub(1, &vfe_dev->irq_cnt); msm_isp_prepare_tasklet_debug_info(vfe_dev, irq_status0, irq_status1, ts); + trace_msm_cam_isp_status_dump("VFE_TASKLET:", vfe_dev->pdev->id, + vfe_dev->axi_data.src_info[VFE_PIX_0].frame_id, + irq_status0, irq_status1); irq_ops = &vfe_dev->hw_info->vfe_ops.irq_ops; irq_ops->process_reset_irq(vfe_dev, irq_status0, irq_status1); diff --git a/include/trace/events/msm_cam.h b/include/trace/events/msm_cam.h index b52845407ef0..b0dc7eac8b7a 100644 --- a/include/trace/events/msm_cam.h +++ b/include/trace/events/msm_cam.h @@ -1,4 +1,4 @@ -/* Copyright (c) 2016, The Linux Foundation. All rights reserved. +/* Copyright (c) 2016, 2019, The Linux Foundation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 and @@ -131,6 +131,34 @@ TRACE_EVENT(msm_cam_ping_pong_debug_dump, ) ); +TRACE_EVENT(msm_cam_isp_status_dump, + TP_PROTO(char *event, uint32_t vfe_id, uint32_t frame_id, + uint32_t irq_status0, uint32_t irq_status1), + TP_ARGS(event, vfe_id, frame_id, irq_status0, + irq_status1), + TP_STRUCT__entry( + __field(char *, event) + __field(unsigned int, vfe_id) + __field(unsigned int, frame_id) + __field(unsigned int, irq_status0) + __field(unsigned int, irq_status1) + ), + TP_fast_assign( + __entry->event = event; + __entry->vfe_id = vfe_id; + __entry->frame_id = frame_id; + __entry->irq_status0 = irq_status0; + __entry->irq_status1 = irq_status1; + ), + TP_printk("%s vfe %d, frame %d, irq_st0 %x, irq_st1 %x\n", + __entry->event, + __entry->vfe_id, + __entry->frame_id, + __entry->irq_status0, + __entry->irq_status1 + ) +); + #endif /* _MSM_CAM_TRACE_H */ /* This part must be outside protection */ #include