diff options
author | Ken Chang <kenc@nvidia.com> | 2021-12-13 00:04:12 -0500 |
---|---|---|
committer | mobile promotions <svcmobile_promotions@nvidia.com> | 2022-01-07 09:10:42 -0500 |
commit | 643a51e0eb2b3eb2c3cecc6777e20ff040e2483b (patch) | |
tree | 54d0e8d0218b09d170a843a817bb25e8e3adbbb1 /drivers | |
parent | aead036da110062df01a7a4f92592e95f3970a18 (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
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/media/platform/tegra/camera/vi/vi2_fops.c | 93 |
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 | |||
584 | capture_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 | ||
635 | static int tegra_channel_capture_frame(struct tegra_channel *chan, | 591 | static int tegra_channel_capture_frame(struct tegra_channel *chan, |
@@ -858,8 +814,6 @@ static int tegra_channel_kthread_capture_start(void *data) | |||
858 | 814 | ||
859 | static void tegra_channel_stop_kthreads(struct tegra_channel *chan) | 815 | static 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 | ||