summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorKen Chang <kenc@nvidia.com>2021-12-13 00:04:12 -0500
committermobile promotions <svcmobile_promotions@nvidia.com>2022-01-07 09:10:42 -0500
commit643a51e0eb2b3eb2c3cecc6777e20ff040e2483b (patch)
tree54d0e8d0218b09d170a843a817bb25e8e3adbbb1
parentaead036da110062df01a7a4f92592e95f3970a18 (diff)
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 <kenc@nvidia.com> Reviewed-on: https://git-master.nvidia.com/r/c/linux-nvidia/+/2645502 Reviewed-by: Frank Chen <frankc@nvidia.com> Reviewed-by: Jerry Chang <jerchang@nvidia.com> Reviewed-by: Anubhav Rai <arai@nvidia.com> Reviewed-by: Bibek Basu <bbasu@nvidia.com> Reviewed-by: mobile promotions <svcmobile_promotions@nvidia.com> Tested-by: mobile promotions <svcmobile_promotions@nvidia.com> GVS: Gerrit_Virtual_Submit
-rw-r--r--drivers/media/platform/tegra/camera/vi/vi2_fops.c93
1 files changed, 23 insertions, 70 deletions
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 @@
1/* 1/*
2 * Tegra Video Input 2 device common APIs 2 * Tegra Video Input 2 device common APIs
3 * 3 *
4 * Copyright (c) 2016-2019, NVIDIA CORPORATION. All rights reserved. 4 * Copyright (c) 2016-2022, NVIDIA CORPORATION. All rights reserved.
5 * 5 *
6 * Author: Bryan Wu <pengw@nvidia.com> 6 * Author: Bryan Wu <pengw@nvidia.com>
7 * 7 *
@@ -480,18 +480,14 @@ static int tegra_channel_capture_frame_multi_thread(
480{ 480{
481 struct timespec ts = {0, 0}; 481 struct timespec ts = {0, 0};
482 int err = 0; 482 int err = 0;
483 u32 val, frame_start, mw_ack_done; 483 u32 val, mw_ack_done;
484 int bytes_per_line = chan->format.bytesperline; 484 int bytes_per_line = chan->format.bytesperline;
485 int index = 0; 485 int index = 0;
486 u32 thresh[TEGRA_CSI_BLOCKS] = { 0 };
487 u32 release_thresh[TEGRA_CSI_BLOCKS] = { 0 }; 486 u32 release_thresh[TEGRA_CSI_BLOCKS] = { 0 };
488 int valid_ports = chan->valid_ports; 487 int valid_ports = chan->valid_ports;
489 int restart_version = 0; 488 int restart_version = 0;
490 bool is_streaming = atomic_read(&chan->is_streaming); 489 bool is_streaming = atomic_read(&chan->is_streaming);
491 490
492 if (!is_streaming)
493 tegra_channel_ec_recover(chan);
494
495 /* The fifo depth of PP_FRAME_START and MW_ACK_DONE is 2 */ 491 /* The fifo depth of PP_FRAME_START and MW_ACK_DONE is 2 */
496 down_read(&chan->reset_lock); 492 down_read(&chan->reset_lock);
497 /* The fifo depth of syncpt event PP_FRAME_START and MW_ACK_DONE is 2 */ 493 /* 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(
535 } 531 }
536 532
537 /* Program syncpoints */ 533 /* Program syncpoints */
538 thresh[index] = nvhost_syncpt_incr_max_ext(chan->vi->ndev,
539 chan->syncpt[index][0], 1);
540
541 frame_start = VI_CSI_PP_FRAME_START(chan->port[index]);
542 val = VI_CFG_VI_INCR_SYNCPT_COND(frame_start) |
543 chan->syncpt[index][0];
544 tegra_channel_write(chan,
545 TEGRA_VI_CFG_VI_INCR_SYNCPT, val);
546
547 release_thresh[index] = 534 release_thresh[index] =
548 nvhost_syncpt_incr_max_ext(chan->vi->ndev, 535 nvhost_syncpt_incr_max_ext(chan->vi->ndev,
549 chan->syncpt[index][1], 1); 536 chan->syncpt[index][1], 1);
@@ -564,10 +551,8 @@ static int tegra_channel_capture_frame_multi_thread(
564 dev_err(&chan->video->dev, 551 dev_err(&chan->video->dev,
565 "failed to enable stream. ERROR: %d\n", err); 552 "failed to enable stream. ERROR: %d\n", err);
566 553
567 buf->state = VB2_BUF_STATE_REQUEUEING;
568 chan->capture_state = CAPTURE_ERROR; 554 chan->capture_state = CAPTURE_ERROR;
569 release_buffer(chan, buf); 555 goto capture_fail;
570 return err;
571 } 556 }
572 /* Bit controls VI memory write, enable after all regs */ 557 /* Bit controls VI memory write, enable after all regs */
573 for (index = 0; index < valid_ports; index++) { 558 for (index = 0; index < valid_ports; index++) {
@@ -584,52 +569,23 @@ static int tegra_channel_capture_frame_multi_thread(
584 for (index = 0; index < valid_ports; index++) 569 for (index = 0; index < valid_ports; index++)
585 csi_write(chan, index, 570 csi_write(chan, index,
586 TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE); 571 TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE);
572
587 up_read(&chan->reset_lock); 573 up_read(&chan->reset_lock);
588 574
589 chan->capture_state = CAPTURE_GOOD; 575 chan->capture_state = CAPTURE_GOOD;
590 for (index = 0; index < valid_ports; index++) {
591 err = nvhost_syncpt_wait_timeout_ext(chan->vi->ndev,
592 chan->syncpt[index][0], thresh[index],
593 chan->timeout, NULL, &ts);
594 if (err) {
595 dev_err(&chan->video->dev,
596 "frame start syncpt timeout!%d\n", index);
597 buf->state = VB2_BUF_STATE_REQUEUEING;
598 /* perform error recovery for timeout */
599 tegra_channel_ec_recover(chan);
600 chan->capture_state = CAPTURE_TIMEOUT;
601 break;
602 }
603
604 dev_dbg(&chan->video->dev,
605 "%s: vi2 got SOF syncpt buf[%p]\n", __func__, buf);
606 }
607
608 getrawmonotonic(&ts); 576 getrawmonotonic(&ts);
609
610 if (!err && !chan->pg_mode) {
611 /* Marking error frames and resume capture */
612 /* TODO: TPG has frame height short error always set */
613 err = tegra_channel_error_status(chan);
614 if (err) {
615 buf->state = VB2_BUF_STATE_REQUEUEING;
616 chan->capture_state = CAPTURE_ERROR;
617 tegra_channel_ec_recover(chan);
618 }
619 }
620
621 set_timestamp(buf, &ts); 577 set_timestamp(buf, &ts);
622 578
623 if (chan->capture_state == CAPTURE_GOOD) { 579 /* Set buffer version to match current capture version */
624 /* Set buffer version to match current capture version */ 580 buf->version = chan->capture_version;
625 buf->version = chan->capture_version; 581 enqueue_inflight(chan, buf);
626 enqueue_inflight(chan, buf);
627 } else {
628 buf->state = VB2_BUF_STATE_REQUEUEING;
629 release_buffer(chan, buf);
630 }
631
632 return 0; 582 return 0;
583
584capture_fail:
585 buf->state = VB2_BUF_STATE_REQUEUEING;
586 release_buffer(chan, buf);
587 atomic_dec(&chan->syncpt_depth);
588 return err;
633} 589}
634 590
635static int tegra_channel_capture_frame(struct tegra_channel *chan, 591static int tegra_channel_capture_frame(struct tegra_channel *chan,
@@ -858,8 +814,6 @@ static int tegra_channel_kthread_capture_start(void *data)
858 814
859static void tegra_channel_stop_kthreads(struct tegra_channel *chan) 815static void tegra_channel_stop_kthreads(struct tegra_channel *chan)
860{ 816{
861 struct tegra_channel_buffer *buf = NULL;
862
863 mutex_lock(&chan->stop_kthread_lock); 817 mutex_lock(&chan->stop_kthread_lock);
864 /* Stop the kthread for capture */ 818 /* Stop the kthread for capture */
865 if (chan->kthread_capture_start) { 819 if (chan->kthread_capture_start) {
@@ -870,11 +824,6 @@ static void tegra_channel_stop_kthreads(struct tegra_channel *chan)
870 if (chan->low_latency) { 824 if (chan->low_latency) {
871 /* Stop the kthread for release frame */ 825 /* Stop the kthread for release frame */
872 if (chan->kthread_release) { 826 if (chan->kthread_release) {
873 if (!list_empty(&chan->release)) {
874 buf = dequeue_inflight(chan);
875 if (buf)
876 tegra_channel_release_frame(chan, buf);
877 }
878 kthread_stop(chan->kthread_release); 827 kthread_stop(chan->kthread_release);
879 chan->kthread_release = NULL; 828 chan->kthread_release = NULL;
880 } 829 }
@@ -894,8 +843,6 @@ static int vi2_channel_start_streaming(struct vb2_queue *vq, u32 count)
894 struct tegra_csi_channel *csi_chan = NULL; 843 struct tegra_csi_channel *csi_chan = NULL;
895 struct tegra_csi_device *csi = chan->vi->csi; 844 struct tegra_csi_device *csi = chan->vi->csi;
896 845
897 vi_channel_syncpt_init(chan);
898
899 tegra_channel_ec_init(chan); 846 tegra_channel_ec_init(chan);
900 847
901#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) 848#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)
927 /* ensure sync point state is clean */ 874 /* ensure sync point state is clean */
928 nvhost_syncpt_set_min_eq_max_ext(chan->vi->ndev, 875 nvhost_syncpt_set_min_eq_max_ext(chan->vi->ndev,
929 chan->syncpt[i][0]); 876 chan->syncpt[i][0]);
877 if (chan->low_latency) {
878 nvhost_syncpt_set_min_eq_max_ext(chan->vi->ndev,
879 chan->syncpt[i][1]);
880 }
930 } 881 }
931 882
932 /* Note: Program VI registers after TPG, sensors and CSI streaming */ 883 /* 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)
938 if (!chan->low_latency) 889 if (!chan->low_latency)
939 tegra_channel_init_ring_buffer(chan); 890 tegra_channel_init_ring_buffer(chan);
940 891
892 /* reset syncpt depth to 0 */
893 atomic_set(&chan->syncpt_depth, 0);
894
941 /* Start kthread to capture data to buffer */ 895 /* Start kthread to capture data to buffer */
942 chan->kthread_capture_start = kthread_run( 896 chan->kthread_capture_start = kthread_run(
943 tegra_channel_kthread_capture_start, 897 tegra_channel_kthread_capture_start,
@@ -978,7 +932,6 @@ error_pipeline_start:
978 vq->start_streaming_called = 0; 932 vq->start_streaming_called = 0;
979 tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_QUEUED, 933 tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_QUEUED,
980 chan->low_latency); 934 chan->low_latency);
981
982 return ret; 935 return ret;
983} 936}
984 937
@@ -994,7 +947,7 @@ static int vi2_channel_stop_streaming(struct vb2_queue *vq)
994 if (!chan->bypass) { 947 if (!chan->bypass) {
995 tegra_channel_stop_kthreads(chan); 948 tegra_channel_stop_kthreads(chan);
996 /* wait for last frame memory write ack */ 949 /* wait for last frame memory write ack */
997 if (is_streaming && chan->capture_state == CAPTURE_GOOD) 950 if (!chan->low_latency && is_streaming && chan->capture_state == CAPTURE_GOOD)
998 tegra_channel_capture_done(chan); 951 tegra_channel_capture_done(chan);
999 if (!chan->low_latency) { 952 if (!chan->low_latency) {
1000 /* free all the ring buffers */ 953 /* free all the ring buffers */
@@ -1028,8 +981,6 @@ static int vi2_channel_stop_streaming(struct vb2_queue *vq)
1028#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0) 981#if LINUX_VERSION_CODE < KERNEL_VERSION(4, 9, 0)
1029 media_entity_pipeline_stop(&chan->video->entity); 982 media_entity_pipeline_stop(&chan->video->entity);
1030#endif 983#endif
1031
1032 vi_channel_syncpt_free(chan);
1033 return 0; 984 return 0;
1034} 985}
1035 986
@@ -1101,6 +1052,7 @@ static int vi2_power_on(struct tegra_channel *chan)
1101 if (ret) 1052 if (ret)
1102 return ret; 1053 return ret;
1103 1054
1055 vi_channel_syncpt_init(chan);
1104 if (atomic_add_return(1, &vi->power_on_refcnt) == 1) { 1056 if (atomic_add_return(1, &vi->power_on_refcnt) == 1) {
1105 tegra_vi2_power_on(vi); 1057 tegra_vi2_power_on(vi);
1106 if (chan->pg_mode) 1058 if (chan->pg_mode)
@@ -1140,6 +1092,7 @@ static void vi2_power_off(struct tegra_channel *chan)
1140 else 1092 else
1141 tegra_vi->sensor_opened = false; 1093 tegra_vi->sensor_opened = false;
1142 } 1094 }
1095 vi_channel_syncpt_free(chan);
1143 nvhost_module_remove_client(vi->ndev, &chan->video); 1096 nvhost_module_remove_client(vi->ndev, &chan->video);
1144} 1097}
1145 1098