From 643a51e0eb2b3eb2c3cecc6777e20ff040e2483b Mon Sep 17 00:00:00 2001 From: Ken Chang Date: Mon, 13 Dec 2021 13:04:12 +0800 Subject: media: tegra: camera: vi2: refactor low-latency mode code A frame capture may fail somewhere between the frame start and the frame end,e.g., the below error prints: 2021-11-04T10:11:31.561+00:00 kernel: [ 794.777229] tc358840 1-001f: event: resolution change (EQ_BYPS=1): 3840x2160p29.94 (4400x2250) 2021-11-04T10:11:32.167+00:00 kernel: [ 795.379917] video4linux video0: TEGRA_VI_CSI_ERROR_STATUS 0x00000000 2021-11-04T10:11:32.167+00:00 kernel: [ 795.386292] video4linux video0: TEGRA_VI_CSI_ERROR_STATUS 0x00000000 2021-11-04T10:11:32.191+00:00 kernel: [ 795.404274] vi 54080000.vi: tegra_channel_error_status:error 20022 frame 0 This means checking SOF in the capture thread doesn't help avoid a failure in the release thread. Hence we can simplify the capture thread to program only the capture released settings, skip the checking of SOF and leave the checking of vi/csi status and the recovery process to be done in the release thread. Also simplify vi2_channel_stop_streaming() to not invoke tegra_channel_capture_done() as the buffers shall be well handled in tegra_channel_queued_buf_done() with VB2_BUF_STATE_ERROR state. In the original implementation, chan->syncpt[index][] will be re-allocated for every single stop_streaming()/start_streaming() pair, so the syncpt IDs may change. This is causing the problem: the syncpt IDs armed for the previous failing capture are still queued in the FIFO and will be used for the next successfull frame capture, however new syncpt IDs are allocated for the new coming frames, e.g, the below error prints: 2021-11-23T08:12:59.038+00:00 kernel: [ 590.029312] tegra_channel_capture_frame_multi_thread[570]: rv 4, cv 3, stm Y 2021-11-23T08:12:59.038+00:00 kernel: [ 590.036865] tegra_channel_enable_stream[212] -- begin 2021-11-23T08:12:59.044+00:00 kernel: [ 590.042437] tegra_channel_enable_stream[221] -- end 2021-11-23T08:12:59.263+00:00 kernel: [ 590.251676] video4linux video0: frame start syncpt timeout!0 2021-11-23T08:12:59.263+00:00 kernel: [ 590.257419] tegra_channel_ec_recover[337] -- begin 2021-12-03T11:14:36.763+00:00 kernel: [ 1049.109289] vi2_channel_start_streaming[912] -- begin 2021-12-03T11:14:36.763+00:00 kernel: [ 1049.115121] vi2_channel_start_streaming[949]: syncpt id 24, max 5064, min 5064 2021-12-03T11:14:36.771+00:00 kernel: [ 1049.123116] vi2_channel_start_streaming[949]: syncpt id 28, max 1614, min 1614 --> the syncpt id being used for this streaming are 24/28, these two syncpts are used since the first streaming ... 2021-12-03T11:14:39.244+00:00 kernel: [ 1051.597885] tegra_channel_capture_frame_multi_thread[624] -- end: release_thresh 5101 2021-12-03T11:14:39.303+00:00 kernel: [ 1051.663550] tegra_channel_release_frame[701] -- end: buf->thresh 5101 2021-12-03T11:14:39.350+00:00 kernel: [ 1051.703617] vi2_channel_stop_streaming[1065] -- end --> no problem observed, and capture cancelled due to stop_streaming ... 2021-12-03T11:15:09.524+00:00 kernel: [ 1081.871259] vi2_channel_start_streaming[912] -- begin 2021-12-03T11:15:09.524+00:00 kernel: [ 1081.876860] vi2_channel_start_streaming[949]: syncpt id 36, max 0, min 0 2021-12-03T11:15:09.524+00:00 kernel: [ 1081.884187] vi2_channel_start_streaming[949]: syncpt id 38, max 0, min 0 --> the syncpt id being used now are changed to 36/38 ... 2021-12-03T11:15:09.534+00:00 kernel: [ 1081.891728] tegra_channel_capture_frame_multi_thread[514] -- begin 2021-12-03T11:15:09.534+00:00 kernel: [ 1081.891771] vi2_channel_start_streaming[992] -- end 2021-12-03T11:15:09.552+00:00 kernel: [ 1081.904384] tegra_channel_capture_frame_multi_thread[569]: rv 119, cv 119, stm N 2021-12-03T11:15:09.606+00:00 kernel: [ 1081.958030] tegra_channel_capture_frame_multi_thread[624] -- end: release_thresh 1 2021-12-03T11:15:09.606+00:00 kernel: [ 1081.958086] tegra_channel_release_frame[669] -- begin 2021-12-03T11:15:09.817+00:00 kernel: [ 1082.162133] video4linux video0: tegra_channel_release_frame: MW_ACK_DONE syncpoint time out!0 2021-12-03T11:15:09.817+00:00 kernel: [ 1082.170683] tegra_channel_release_frame[680]: buf->thresh[0] 1 2021-12-03T11:15:09.817+00:00 kernel: [ 1082.176972] tegra_channel_release_frame[683]: syncpt 36, hw val 0 2021-12-03T11:15:09.829+00:00 kernel: [ 1082.183715] tegra_channel_ec_recover[337] -- begin Given Hw doesn't support SYNCPT FIFO reset per stream, reuse the same syncpt IDs until the channel is powered off. Also skip invoking tegra_channel_capture_done() from vi2_channel_stop_streaming() and tegra_channel_release_frame() from tegra_channel_stop_kthreads() as streaming shall be stoped immediately and the queued buffers shall be well handled in tegra_channel_queued_buf_done() with the VB2_BUF_STATE_ERROR state. Bug 3423623 Change-Id: I53280bc9b1b3c33054d766aa920eb082b3311d92 Signed-off-by: Ken Chang Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2645502 Reviewed-by: Frank Chen Reviewed-by: Jerry Chang Reviewed-by: Anubhav Rai Reviewed-by: Bibek Basu Reviewed-by: mobile promotions Tested-by: mobile promotions GVS: Gerrit_Virtual_Submit --- drivers/media/platform/tegra/camera/vi/vi2_fops.c | 93 ++++++----------------- 1 file changed, 23 insertions(+), 70 deletions(-) (limited to 'drivers') diff --git a/drivers/media/platform/tegra/camera/vi/vi2_fops.c b/drivers/media/platform/tegra/camera/vi/vi2_fops.c index 6afd16ef8..09d84b59e 100644 --- a/drivers/media/platform/tegra/camera/vi/vi2_fops.c +++ b/drivers/media/platform/tegra/camera/vi/vi2_fops.c @@ -1,7 +1,7 @@ /* * Tegra Video Input 2 device common APIs * - * Copyright (c) 2016-2019, NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved. * * Author: Bryan Wu * @@ -480,18 +480,14 @@ static int tegra_channel_capture_frame_multi_thread( { struct timespec ts = {0, 0}; int err = 0; - u32 val, frame_start, mw_ack_done; + u32 val, mw_ack_done; int bytes_per_line = chan->format.bytesperline; int index = 0; - u32 thresh[TEGRA_CSI_BLOCKS] = { 0 }; u32 release_thresh[TEGRA_CSI_BLOCKS] = { 0 }; int valid_ports = chan->valid_ports; int restart_version = 0; bool is_streaming = atomic_read(&chan->is_streaming); - if (!is_streaming) - tegra_channel_ec_recover(chan); - /* The fifo depth of PP_FRAME_START and MW_ACK_DONE is 2 */ down_read(&chan->reset_lock); /* The fifo depth of syncpt event PP_FRAME_START and MW_ACK_DONE is 2 */ @@ -535,15 +531,6 @@ static int tegra_channel_capture_frame_multi_thread( } /* Program syncpoints */ - thresh[index] = nvhost_syncpt_incr_max_ext(chan->vi->ndev, - chan->syncpt[index][0], 1); - - frame_start = VI_CSI_PP_FRAME_START(chan->port[index]); - val = VI_CFG_VI_INCR_SYNCPT_COND(frame_start) | - chan->syncpt[index][0]; - tegra_channel_write(chan, - TEGRA_VI_CFG_VI_INCR_SYNCPT, val); - release_thresh[index] = nvhost_syncpt_incr_max_ext(chan->vi->ndev, chan->syncpt[index][1], 1); @@ -564,10 +551,8 @@ static int tegra_channel_capture_frame_multi_thread( dev_err(&chan->video->dev, "failed to enable stream. ERROR: %d\n", err); - buf->state = VB2_BUF_STATE_REQUEUEING; chan->capture_state = CAPTURE_ERROR; - release_buffer(chan, buf); - return err; + goto capture_fail; } /* Bit controls VI memory write, enable after all regs */ for (index = 0; index < valid_ports; index++) { @@ -584,52 +569,23 @@ static int tegra_channel_capture_frame_multi_thread( for (index = 0; index < valid_ports; index++) csi_write(chan, index, TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE); + up_read(&chan->reset_lock); chan->capture_state = CAPTURE_GOOD; - for (index = 0; index < valid_ports; index++) { - err = nvhost_syncpt_wait_timeout_ext(chan->vi->ndev, - chan->syncpt[index][0], thresh[index], - chan->timeout, NULL, &ts); - if (err) { - dev_err(&chan->video->dev, - "frame start syncpt timeout!%d\n", index); - buf->state = VB2_BUF_STATE_REQUEUEING; - /* perform error recovery for timeout */ - tegra_channel_ec_recover(chan); - chan->capture_state = CAPTURE_TIMEOUT; - break; - } - - dev_dbg(&chan->video->dev, - "%s: vi2 got SOF syncpt buf[%p]\n", __func__, buf); - } - getrawmonotonic(&ts); - - if (!err && !chan->pg_mode) { - /* Marking error frames and resume capture */ - /* TODO: TPG has frame height short error always set */ - err = tegra_channel_error_status(chan); - if (err) { - buf->state = VB2_BUF_STATE_REQUEUEING; - chan->capture_state = CAPTURE_ERROR; - tegra_channel_ec_recover(chan); - } - } - set_timestamp(buf, &ts); - if (chan->capture_state == CAPTURE_GOOD) { - /* Set buffer version to match current capture version */ - buf->version = chan->capture_version; - enqueue_inflight(chan, buf); - } else { - buf->state = VB2_BUF_STATE_REQUEUEING; - release_buffer(chan, buf); - } - + /* Set buffer version to match current capture version */ + buf->version = chan->capture_version; + enqueue_inflight(chan, buf); return 0; + +capture_fail: + buf->state = VB2_BUF_STATE_REQUEUEING; + release_buffer(chan, buf); + atomic_dec(&chan->syncpt_depth); + return err; } static int tegra_channel_capture_frame(struct tegra_channel *chan, @@ -858,8 +814,6 @@ static int tegra_channel_kthread_capture_start(void *data) static void tegra_channel_stop_kthreads(struct tegra_channel *chan) { - struct tegra_channel_buffer *buf = NULL; - mutex_lock(&chan->stop_kthread_lock); /* Stop the kthread for capture */ if (chan->kthread_capture_start) { @@ -870,11 +824,6 @@ static void tegra_channel_stop_kthreads(struct tegra_channel *chan) if (chan->low_latency) { /* Stop the kthread for release frame */ if (chan->kthread_release) { - if (!list_empty(&chan->release)) { - buf = dequeue_inflight(chan); - if (buf) - tegra_channel_release_frame(chan, buf); - } kthread_stop(chan->kthread_release); chan->kthread_release = NULL; } @@ -894,8 +843,6 @@ static int vi2_channel_start_streaming(struct vb2_queue *vq, u32 count) struct tegra_csi_channel *csi_chan = NULL; struct tegra_csi_device *csi = chan->vi->csi; - vi_channel_syncpt_init(chan); - tegra_channel_ec_init(chan); #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) @@ -927,6 +874,10 @@ static int vi2_channel_start_streaming(struct vb2_queue *vq, u32 count) /* ensure sync point state is clean */ nvhost_syncpt_set_min_eq_max_ext(chan->vi->ndev, chan->syncpt[i][0]); + if (chan->low_latency) { + nvhost_syncpt_set_min_eq_max_ext(chan->vi->ndev, + chan->syncpt[i][1]); + } } /* Note: Program VI registers after TPG, sensors and CSI streaming */ @@ -938,6 +889,9 @@ static int vi2_channel_start_streaming(struct vb2_queue *vq, u32 count) if (!chan->low_latency) tegra_channel_init_ring_buffer(chan); + /* reset syncpt depth to 0 */ + atomic_set(&chan->syncpt_depth, 0); + /* Start kthread to capture data to buffer */ chan->kthread_capture_start = kthread_run( tegra_channel_kthread_capture_start, @@ -978,7 +932,6 @@ error_pipeline_start: vq->start_streaming_called = 0; tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_QUEUED, chan->low_latency); - return ret; } @@ -994,7 +947,7 @@ static int vi2_channel_stop_streaming(struct vb2_queue *vq) if (!chan->bypass) { tegra_channel_stop_kthreads(chan); /* wait for last frame memory write ack */ - if (is_streaming && chan->capture_state == CAPTURE_GOOD) + if (!chan->low_latency && is_streaming && chan->capture_state == CAPTURE_GOOD) tegra_channel_capture_done(chan); if (!chan->low_latency) { /* free all the ring buffers */ @@ -1028,8 +981,6 @@ static int vi2_channel_stop_streaming(struct vb2_queue *vq) #if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) media_entity_pipeline_stop(&chan->video->entity); #endif - - vi_channel_syncpt_free(chan); return 0; } @@ -1101,6 +1052,7 @@ static int vi2_power_on(struct tegra_channel *chan) if (ret) return ret; + vi_channel_syncpt_init(chan); if (atomic_add_return(1, &vi->power_on_refcnt) == 1) { tegra_vi2_power_on(vi); if (chan->pg_mode) @@ -1140,6 +1092,7 @@ static void vi2_power_off(struct tegra_channel *chan) else tegra_vi->sensor_opened = false; } + vi_channel_syncpt_free(chan); nvhost_module_remove_client(vi->ndev, &chan->video); } -- cgit v1.2.2