OSDN Git Service

msm: camera_v2: isp: handle frame drop due to scheduling latency
authorSrikanth Uyyala <suyyala@codeaurora.org>
Fri, 22 Mar 2019 05:11:46 +0000 (10:41 +0530)
committerSumalatha Malothu <smalot@codeaurora.org>
Thu, 4 Jul 2019 06:23:12 +0000 (11:53 +0530)
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 <suyyala@codeaurora.org>
Signed-off-by: Sumalatha Malothu <smalot@codeaurora.org>
drivers/media/platform/msm/camera_v2/isp/msm_isp.h
drivers/media/platform/msm/camera_v2/isp/msm_isp47.c
drivers/media/platform/msm/camera_v2/isp/msm_isp_axi_util.c
drivers/media/platform/msm/camera_v2/isp/msm_isp_util.c

index 9bc6fde..cef2cd9 100644 (file)
@@ -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 {
index a8341a7..cf9e754 100644 (file)
@@ -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,
index 79b45b6..011a1d4 100644 (file)
@@ -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);
index 684b331..05c955a 100644 (file)
@@ -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--;