It’s could be a large work to revert this ring buffer logic.
Please use the source_sync.sh to get the source code. And find the below change and try to revert it.
commit be2cc397bf47414522def4f54360daab5bd43e23
Author: Bhanu Murthy V bmurthyv@nvidia.com
Date: Fri Apr 15 19:54:08 2016 -0700
drivers: media: camera: Ring buffer management
Implement ring buffer which holds two buffers
before delivering frames from VI. This is to
ensure there is no performance impact using
single thread and memory write of the buffer
is complete.
Add logic to store buffers at the start,
release one buffer every frame once the queue
has only one free slot left.
Free all buffers once the stop streaming
is signalled.
Clean up for two thread implementation and
improve state mechanism in single thread
Bug 200092604
Bug 1736471
Change-Id: Ia9784ee0c7925b5ec4dd6ca5f0b3354af8323662
Signed-off-by: Bhanu Murthy V <bmurthyv@nvidia.com>
Reviewed-on: http://git-master/r/1127760
(cherry picked from commit 39a3d10573140a98aea3b67044f056772fa2be9f)
Reviewed-on: http://git-master/r/1161371
diff --git a/drivers/media/platform/tegra/camera/channel.c b/drivers/media/platform/tegra/camera/channel.c
index d9a7a5f50…25397380b 100644
— a/drivers/media/platform/tegra/camera/channel.c
+++ b/drivers/media/platform/tegra/camera/channel.c
@@ -44,6 +44,9 @@
#define BPP_MEM 2
extern int _vb2_fop_release(struct file *file, struct mutex *lock);
+static void tegra_channel_queued_buf_done(struct tegra_channel *chan,
+static void tegra_channel_stop_kthreads(struct tegra_channel *chan);
static void tegra_channel_write(struct tegra_channel *chan,
unsigned int addr, u32 val)
@@ -258,15 +261,51 @@ static void tegra_channel_capture_error(struct tegra_channel *chan)
}
}
+static void free_ring_buffers(struct tegra_channel *chan, int frames)
+{
-
struct vb2_buffer *vb;
-
-
while (frames--) {
-
vb = chan->buffers[chan->free_index];
-
-
/* release one frame */
-
vb->v4l2_buf.sequence = chan->sequence++;
-
vb->v4l2_buf.field = V4L2_FIELD_NONE;
-
vb2_set_plane_payload(vb, 0, chan->format.sizeimage);
-
vb2_buffer_done(vb, chan->buffer_state[chan->free_index++]);
-
-
if (chan->free_index >= QUEUED_BUFFERS)
-
chan->free_index = 0;
-
chan->num_buffers--;
-
}
+}
+
+static void tegra_channel_ring_buffer(struct tegra_channel *chan,
+{
-
/* save the buffer to the ring first */
-
chan->buffer_state[chan->save_index] = state;
-
chan->buffers[chan->save_index++] = vb;
-
if (chan->save_index >= QUEUED_BUFFERS)
-
chan->save_index = 0;
-
chan->num_buffers++;
-
-
/* release one buffer when only one free slot is present */
-
if (chan->num_buffers >= (QUEUED_BUFFERS - 1))
-
free_ring_buffers(chan, 1);
+}
+
static void tegra_channel_capture_frame(struct tegra_channel *chan,
struct tegra_channel_buffer *buf)
{
-
u32 val, frame_start, mw_ack_done;
int bytes_per_line = chan->format.bytesperline;
int index = 0;
u32 thresh[TEGRA_CSI_BLOCKS] = { 0 };
int valid_ports = chan->valid_ports;
-
int state = VB2_BUF_STATE_DONE;
for (index = 0; index < valid_ports; index++) {
/* Program buffer address by using surface 0 */
@@ -285,6 +324,15 @@ static void tegra_channel_capture_frame(struct tegra_channel *chan,
chan->syncpt[index];
tegra_channel_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, val);
-
/* Program syncpoint */
-
chan->thresh[index] = nvhost_syncpt_incr_max_ext(chan->vi->ndev,
-
chan->syncpt[index], 1);
-
-
mw_ack_done = VI_CSI_MW_ACK_DONE(chan->port[index]);
-
val = VI_CFG_VI_INCR_SYNCPT_COND(mw_ack_done) |
-
chan->syncpt[index];
-
tegra_channel_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, val);
-
csi_write(chan, index,
TEGRA_VI_CSI_SINGLE_SHOT, SINGLE_SHOT_CAPTURE);
}
@@ -299,47 +347,28 @@ static void tegra_channel_capture_frame(struct tegra_channel *chan,
dev_err(&chan->video.dev,
“frame start syncpt timeout!%d\n”, index);
tegra_channel_capture_error(chan);
-
if (atomic_read(&chan->is_hdmiin_unplug)) {
-
vb2_buffer_done(&buf->buf.vb2_buf, VB2_BUF_STATE_ERROR);
-
complete(&chan->capture_comp);
-
} else {
-
/* Move buffer to capture done queue */
-
spin_lock(&chan->done_lock);
-
list_add_tail(&buf->queue, &chan->done);
-
spin_unlock(&chan->done_lock);
-
/* update time stamp and add buffer to queue */
-
v4l2_get_timestamp(&vb->v4l2_buf.timestamp);
-
tegra_channel_ring_buffer(chan, vb, state);
}
-static void tegra_channel_capture_done(struct tegra_channel *chan,
+static void tegra_channel_capture_done(struct tegra_channel *chan)
{
-
struct vb2_v4l2_buffer *vb = &buf->buf;
-
int err = 0;
-
u32 val, mw_ack_done;
-
int index = 0;
-
u32 thresh[TEGRA_CSI_BLOCKS] = { 0 };
-
int valid_ports = chan->valid_ports;
-
-
for (index = 0; index < valid_ports; index++) {
-
/* Program syncpoint */
-
thresh[index] = nvhost_syncpt_incr_max_ext(chan->vi->ndev,
-
chan->syncpt[index], 1);
-
mw_ack_done = VI_CSI_MW_ACK_DONE(chan->port[index]);
-
val = VI_CFG_VI_INCR_SYNCPT_COND(mw_ack_done) |
-
chan->syncpt[index];
-
tegra_channel_write(chan, TEGRA_VI_CFG_VI_INCR_SYNCPT, val);
-
}
-
for (index = 0; index < valid_ports; index++) {
-
err = nvhost_syncpt_wait_timeout_ext(chan->vi->ndev,
-
chan->syncpt[index], thresh[index],
-
for (index = 0; index < chan->valid_ports; index++) {
-
int err = nvhost_syncpt_wait_timeout_ext(chan->vi->ndev,
-
chan->syncpt[index], chan->thresh[index],
TEGRA_VI_SYNCPT_WAIT_TIMEOUT,
NULL,
NULL);
@@ -347,20 +376,6 @@ static void tegra_channel_capture_done(struct tegra_channel *chan,
dev_err(&chan->video.dev,
“MW_ACK_DONE syncpoint time out!%d\n”, index);
}
-
if (atomic_read(&chan->is_hdmiin_unplug)) {
-
vb2_buffer_done(&vb->vb2_buf, err < 0 ? VB2_BUF_STATE_ERROR :
-
VB2_BUF_STATE_DONE);
-
complete(&chan->done_comp);
-
} else {
-
/* Captured one frame */
-
vb->sequence = chan->sequence++;
-
vb->field = V4L2_FIELD_NONE;
-
v4l2_get_timestamp(&vb->timestamp);
-
vb2_set_plane_payload(&vb->vb2_buf, 0, chan->format.sizeimage);
-
vb2_buffer_done(&vb->vb2_buf, err < 0 ? VB2_BUF_STATE_ERROR
-
: VB2_BUF_STATE_DONE);
-
}
}
static int tegra_channel_kthread_capture_start(void *data)
@@ -370,17 +385,17 @@ static int tegra_channel_kthread_capture_start(void *data)
set_freezable();
-
while (!atomic_read(&chan->is_hdmiin_unplug)) {
-
try_to_freeze();
-
wait_event_interruptible(chan->start_wait,
!list_empty(&chan->capture) ||
kthread_should_stop() ||
atomic_read(&chan->is_hdmiin_unplug));
if (kthread_should_stop() ||
@@ -396,58 +411,13 @@ static int tegra_channel_kthread_capture_start(void *data)
tegra_channel_capture_frame(chan, buf);
}
-}
-static int tegra_channel_kthread_capture_done(void *data)
-{
-
struct tegra_channel *chan = data;
-
struct tegra_channel_buffer *buf;
-
-
set_freezable();
-
-
while (1) {
-
try_to_freeze();
-
wait_event_interruptible(chan->done_wait,
-
!list_empty(&chan->done) ||
-
kthread_should_stop() ||
-
atomic_read(&chan->is_hdmiin_unplug));
-
-
if ((chan->vi->pg_mode &&
-
kthread_should_stop()) ||
-
atomic_read(&chan->is_hdmiin_unplug)) {
-
complete(&chan->done_comp);
-
break;
-
} else if (kthread_should_stop() &&
-
list_empty(&chan->done)) {
-
complete(&chan->done_comp);
-
break;
-
}
-
-
spin_lock(&chan->done_lock);
-
if (list_empty(&chan->done)) {
-
spin_unlock(&chan->done_lock);
-
continue;
-
}
-
-
buf = list_entry(chan->done.next,
-
struct tegra_channel_buffer, queue);
-
list_del_init(&buf->queue);
-
spin_unlock(&chan->done_lock);
-
-
tegra_channel_capture_done(chan, buf);
-
}
}
-static void tegra_channel_queued_buf_done(struct tegra_channel *chan,
static void tegra_channel_stop_kthreads(struct tegra_channel *chan)
{
mutex_lock(&chan->stop_kthread_lock);
/* Stop the kthread for capture */
if (chan->kthread_capture_start) {
@@ -455,13 +425,6 @@ static void tegra_channel_stop_kthreads(struct tegra_channel *chan)
wait_for_completion(&chan->capture_comp);
chan->kthread_capture_start = NULL;
}
-
if (chan->kthread_capture_done) {
-
kthread_stop(chan->kthread_capture_done);
-
wait_for_completion(&chan->done_comp);
-
chan->kthread_capture_done = NULL;
-
}
-
tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_ERROR, 1);
-
tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_ERROR, 0);
mutex_unlock(&chan->stop_kthread_lock);
}
@@ -504,14 +467,10 @@ void tegra_channel_query_hdmiin_unplug(struct tegra_channel *chan,
return;
atomic_set(&chan->is_hdmiin_unplug, 1);
@@ -583,12 +542,11 @@ static void tegra_channel_buffer_queue(struct vb2_buffer *vb)
/* Return all queued buffers back to videobuf2 */
static void tegra_channel_queued_buf_done(struct tegra_channel *chan,
{
struct tegra_channel_buffer *buf, *nbuf;
-
spinlock_t *lock = &chan->start_lock;
-
struct list_head *q = &chan->capture;
spin_lock(lock);
list_for_each_entry_safe(buf, nbuf, q, queue) {
@@ -675,6 +633,14 @@ static void tegra_channel_update_clknbw(struct tegra_channel *chan, u8 on)
mutex_unlock(&chan->vi->bw_update_lock);
}
+static void tegra_channel_init_ring_buffer(struct tegra_channel *chan)
+{
-
chan->num_buffers = 0;
-
chan->save_index = 0;
-
chan->free_index = 0;
-
chan->sequence = 0;
+}
+
static int tegra_channel_start_streaming(struct vb2_queue *vq, u32 count)
{
struct tegra_channel *chan = vb2_get_drv_priv(vq);
@@ -711,9 +677,13 @@ static int tegra_channel_start_streaming(struct vb2_queue *vq, u32 count)
if (ret < 0)
goto error_capture_setup;
-
tegra_channel_init_ring_buffer(chan);
atomic_set(&chan->is_hdmiin_unplug, 0);
-
/* Update clock and bandwidth based on the format */
-
/* perform calibration as sensor started streaming */
-
tegra_channel_update_clknbw(chan, 1);
-
/* Start kthread to capture data to buffer */
chan->kthread_capture_start = kthread_run(
tegra_channel_kthread_capture_start,
@@ -725,17 +695,6 @@ static int tegra_channel_start_streaming(struct vb2_queue *vq, u32 count)
goto error_capture_setup;
}
-
chan->kthread_capture_done = kthread_run(
-
tegra_channel_kthread_capture_done,
-
chan, chan->video.name);
-
if (IS_ERR(chan->kthread_capture_done)) {
-
dev_err(&chan->video.dev,
-
"failed to run kthread for capture done\n");
-
ret = PTR_ERR(chan->kthread_capture_done);
-
goto error_capture_setup;
-
}
-
tegra_channel_update_clknbw(chan, 1);
-
return 0;
error_capture_setup:
@@ -746,7 +705,7 @@ error_set_stream:
media_entity_pipeline_stop(&chan->video.entity);
error_pipeline_start:
vq->start_streaming_called = 0;
}
@@ -758,6 +717,12 @@ static void tegra_channel_stop_streaming(struct vb2_queue *vq)
if (!chan->bypass) {
tegra_channel_stop_kthreads(chan);
-
/* wait for last frame memory write ack */
-
tegra_channel_capture_done(chan);
-
/* free all the ring buffers */
-
free_ring_buffers(chan, chan->num_buffers);
-
/* dequeue buffers back to app which are in capture queue */
-
tegra_channel_queued_buf_done(chan, VB2_BUF_STATE_ERROR);
if (atomic_read(&chan->is_hdmiin_unplug)) {
tegra_channel_write(chan, TEGRA_VI_CFG_CG_CTRL, 0);
@@ -1626,14 +1591,10 @@ static int tegra_channel_init(struct tegra_mc_vi *vi, unsigned int index)
chan->num_subdevs = 0;
mutex_init(&chan->video_lock);
INIT_LIST_HEAD(&chan->capture);
-
INIT_LIST_HEAD(&chan->done);
init_waitqueue_head(&chan->start_wait);
-
init_waitqueue_head(&chan->done_wait);
spin_lock_init(&chan->start_lock);
-
spin_lock_init(&chan->done_lock);
mutex_init(&chan->stop_kthread_lock);
init_completion(&chan->capture_comp);
-
init_completion(&chan->done_comp);
atomic_set(&chan->is_hdmiin_unplug, 0);
/* Init video format */
diff --git a/drivers/media/platform/tegra/camera/mc_common.h b/drivers/media/platform/tegra/camera/mc_common.h
index 0bb8073b3…ecb3705f2 100644
— a/drivers/media/platform/tegra/camera/mc_common.h
+++ b/drivers/media/platform/tegra/camera/mc_common.h
@@ -34,6 +34,7 @@
#define MAX_FORMAT_NUM 64
#define MAX_SUBDEVICES 4
+#define QUEUED_BUFFERS 4
/**
-
struct tegra_channel_buffer - video channel buffer
@@ -118,20 +119,21 @@ struct tegra_channel {
unsigned char port[TEGRA_CSI_BLOCKS];
unsigned int syncpt[TEGRA_CSI_BLOCKS];
-
unsigned int thresh[TEGRA_CSI_BLOCKS];
unsigned int buffer_offset[TEGRA_CSI_BLOCKS];
-
unsigned int buffer_state[QUEUED_BUFFERS];
-
struct vb2_buffer *buffers[QUEUED_BUFFERS];
-
unsigned int save_index;
-
unsigned int free_index;
-
unsigned int num_buffers;
struct task_struct *kthread_capture_start;
wait_queue_head_t start_wait;
-
struct task_struct *kthread_capture_done;
-
wait_queue_head_t done_wait;
struct vb2_queue queue;
void *alloc_ctx;
struct list_head capture;
spinlock_t start_lock;
-
struct list_head done;
-
spinlock_t done_lock;
struct completion capture_comp;
-
struct completion done_comp;
void __iomem *csibase[TEGRA_CSI_BLOCKS];
unsigned int align;