ionvideo: fix latency and crash [1/1]
authorjintao xu <jintao.xu@amlogic.com>
Tue, 7 May 2019 03:09:04 +0000 (11:09 +0800)
committerJianxin Pan <jianxin.pan@amlogic.com>
Fri, 21 Jun 2019 08:47:34 +0000 (01:47 -0700)
PD#SWPL-8069

Problem:
1.about 2ms latency due to sleep
2.crash while poll ionvideo

Solution:
1.use semaphore instead of sleep
2.fix poll function
3.add trace info for ionvideo

Verify:
U212

Change-Id: Idde64151541d826ba6a6cd1abcc901e80f0e4b45
Signed-off-by: jintao xu <jintao.xu@amlogic.com>
drivers/amlogic/debug/meson_atrace.c
drivers/amlogic/media/video_processor/ionvideo/ionvideo.c
drivers/amlogic/media/video_processor/ionvideo/ionvideo.h
include/trace/events/meson_atrace.h

index 0127977..2e67dc6 100644 (file)
@@ -32,6 +32,7 @@ struct {
        TAG_INFO(CODEC_MM),
        TAG_INFO(VDEC),
        TAG_INFO(TSYNC),
+       TAG_INFO(IONVIDEO),
        { NULL, 0 }
 };
 
index c89143c..a06190f 100644 (file)
@@ -25,7 +25,8 @@
 #include <media/videobuf2-v4l2.h>
 #include <linux/platform_device.h>
 #include <linux/amlogic/major.h>
-
+#define KERNEL_ATRACE_TAG KERNEL_ATRACE_TAG_IONVIDEO
+#include <trace/events/meson_atrace.h>
 #define IONVIDEO_MODULE_NAME "ionvideo"
 
 #define IONVIDEO_VERSION "1.0"
@@ -389,8 +390,6 @@ static void ionvideo_thread_tick(struct ionvideo_dev *dev)
        vf = vf_peek(dev->vf_receiver_name);
        if (!vf) {
                dev->vf_wait_cnt++;
-               /* msleep(5); */
-               usleep_range(1000, 2000);
                return;
        }
        dev->ppmgr2_dev.dst_width = dev->width;
@@ -407,7 +406,7 @@ static void ionvideo_thread_tick(struct ionvideo_dev *dev)
        }
        if (dev->freerun_mode == 0 && ionvideo_size_changed(dev, w, h)) {
                /* msleep(10); */
-               usleep_range(4000, 5000);
+               /*usleep_range(4000, 5000);*/
                return;
        }
        mutex_lock(&dev->mutex_input);
@@ -415,7 +414,6 @@ static void ionvideo_thread_tick(struct ionvideo_dev *dev)
        if (buf == NULL) {
                dprintk(dev, 3, "No active queue to serve\n");
                mutex_unlock(&dev->mutex_input);
-               schedule_timeout_interruptible(msecs_to_jiffies(20));
                return;
        }
        mutex_unlock(&dev->mutex_input);
@@ -431,6 +429,8 @@ static void ionvideo_thread_tick(struct ionvideo_dev *dev)
        v4l2q_push(&dev->output_queue, buf);
        dma_q->vb_ready++;
        mutex_unlock(&dev->mutex_output);
+       ATRACE_COUNTER(dev->v4l2_dev.name, dma_q->vb_ready);
+       wake_up_interruptible(&dma_q->wq_poll);
        dprintk(dev, 4, "[%p/%d] done\n", buf, buf->index);
 }
 
@@ -441,22 +441,33 @@ static void ionvideo_sleep(struct ionvideo_dev *dev)
 {
        struct ionvideo_dmaqueue *dma_q = &dev->vidq;
        /* int timeout; */
-       DECLARE_WAITQUEUE(wait, current);
+       /*DECLARE_WAITQUEUE(wait, current);*/
 
        dprintk(dev, 4, "%s dma_q=0x%08lx\n", __func__, (unsigned long)dma_q);
 
-       add_wait_queue(&dma_q->wq, &wait);
+       /*add_wait_queue(&dma_q->wq, &wait);*/
        if (kthread_should_stop())
                goto stop_task;
 
        /* Calculate time to wake up */
        /* timeout = msecs_to_jiffies(frames_to_ms(1)); */
 
+       if (vf_peek(dev->vf_receiver_name) == NULL
+               || v4l2q_peek(&dev->input_queue) == NULL) {
+               wait_event_interruptible_timeout(
+                               dma_q->wq,
+                               (vf_peek(dev->vf_receiver_name) != NULL)
+                               && (v4l2q_peek(&dev->input_queue) != NULL),
+                               msecs_to_jiffies(5));
+       }
+       ATRACE_BEGIN("ionvideo_thread_tick");
        ionvideo_thread_tick(dev);
+       ATRACE_END();
 
        /* schedule_timeout_interruptible(timeout); */
 
-stop_task: remove_wait_queue(&dma_q->wq, &wait);
+stop_task:
+       /*remove_wait_queue(&dma_q->wq, &wait);*/
        try_to_freeze();
 }
 
@@ -476,7 +487,6 @@ static int ionvideo_thread(void *data)
                        break;
        }
        dev->thread_stopped = 1;
-       wake_up_interruptible(&dev->wq);
        dprintk(dev, 2, "thread: exit\n");
        return 0;
 }
@@ -695,6 +705,21 @@ static int vidioc_s_fmt_vid_cap(struct file *file, void *priv,
        return 0;
 }
 
+static unsigned int vidioc_poll(struct file *file,
+                               struct poll_table_struct *wait)
+{
+       struct ionvideo_dev *dev = video_drvdata(file);
+       struct ionvideo_dmaqueue *dma_q = &dev->vidq;
+
+       if (dma_q->vb_ready > 0)
+               return POLL_IN | POLLRDNORM;
+       poll_wait(file, &dma_q->wq_poll, wait);
+       if (dma_q->vb_ready > 0)
+               return POLL_IN | POLLRDNORM;
+       else
+               return 0;
+}
+
 static int vidioc_qbuf(struct file *file, void *priv, struct v4l2_buffer *p)
 {
        struct ionvideo_dev *dev = video_drvdata(file);
@@ -868,6 +893,7 @@ static int vidioc_dqbuf(struct file *file, void *priv, struct v4l2_buffer *p)
        if (out_put != NULL) {
                dma_q->vb_ready--;
                *p = *out_put;
+               ATRACE_COUNTER(dev->v4l2_dev.name, dma_q->vb_ready);
        } else {
                mutex_unlock(&dev->mutex_output);
                return -EAGAIN;
@@ -887,7 +913,7 @@ static const struct v4l2_file_operations ionvideo_v4l2_fops = {
        .open = vidioc_open,
        .release = vidioc_close,
        .read = vb2_fop_read,
-       .poll = vb2_fop_poll,
+       .poll = vidioc_poll,
        .unlocked_ioctl = video_ioctl2,/* V4L2 ioctl handler */
        .mmap = vb2_fop_mmap,
 };
@@ -951,6 +977,7 @@ static int ionvideo_v4l2_release(void)
 static int video_receiver_event_fun(int type, void *data, void *private_data)
 {
        struct ionvideo_dev *dev = (struct ionvideo_dev *)private_data;
+       struct ionvideo_dmaqueue *dma_q = &dev->vidq;
        int timeout = 0;
        if (type == VFRAME_EVENT_PROVIDER_UNREG) {
                dev->receiver_register = 0;
@@ -992,8 +1019,13 @@ static int video_receiver_event_fun(int type, void *data, void *private_data)
                        set_vframe_rate_end_hint();
                }
 #endif
+       } else if (type == VFRAME_EVENT_PROVIDER_VFRAME_READY) {
+               wake_up_interruptible(&dma_q->wq);
+               return 0;
+       } else if (type == VFRAME_EVENT_PROVIDER_RESET) {
+               wake_up_interruptible(&dma_q->wq);
+               return 0;
        }
-
        return 0;
 }
 
@@ -1034,6 +1066,7 @@ static int __init ionvideo_create_instance(int inst)
        /* init video dma queues */
        INIT_LIST_HEAD(&dev->vidq.active);
        init_waitqueue_head(&dev->vidq.wq);
+       init_waitqueue_head(&dev->vidq.wq_poll);
        dev->vidq.pdev = dev;
 
        vfd = &dev->vdev;
index edbfffe..f754d21 100644 (file)
@@ -195,6 +195,7 @@ struct ionvideo_dmaqueue {
        /* thread for generating video stream*/
        struct task_struct *kthread;
        wait_queue_head_t wq;
+       wait_queue_head_t wq_poll;
        /* Counters to control fps rate */
        int vb_ready;
        struct ionvideo_dev *pdev;
index d6f2196..1baade7 100644 (file)
@@ -42,6 +42,7 @@ enum {
        KERNEL_ATRACE_TAG_CODEC_MM,
        KERNEL_ATRACE_TAG_VDEC,
        KERNEL_ATRACE_TAG_TSYNC,
+       KERNEL_ATRACE_TAG_IONVIDEO,
        KERNEL_ATRACE_TAG_MAX = 64,
        KERNEL_ATRACE_TAG_ALL
 };
@@ -96,7 +97,7 @@ void meson_atrace(int tag, const char *name, unsigned int flags,
 #define ATRACE_BEGIN(name) \
        meson_atrace(KERNEL_ATRACE_TAG, name, \
                (1 << KERNEL_ATRACE_BEGIN), 0)
-#define ATRACE_END(name) \
+#define ATRACE_END() \
        meson_atrace(KERNEL_ATRACE_TAG, "", \
                (1 << KERNEL_ATRACE_END), 1)
 #define ATRACE_ASYNC_BEGIN(name, cookie) \