[media] vb2: retry start_streaming in case of insufficient buffers
[platform/adaptation/renesas_rcar/renesas_kernel.git] / drivers / media / v4l2-core / videobuf2-core.c
index 14a3604..0d5b84f 100644 (file)
@@ -1378,6 +1378,39 @@ int vb2_prepare_buf(struct vb2_queue *q, struct v4l2_buffer *b)
 }
 EXPORT_SYMBOL_GPL(vb2_prepare_buf);
 
+/**
+ * vb2_start_streaming() - Attempt to start streaming.
+ * @q:         videobuf2 queue
+ *
+ * If there are not enough buffers, then retry_start_streaming is set to
+ * 1 and 0 is returned. The next time a buffer is queued and
+ * retry_start_streaming is 1, this function will be called again to
+ * retry starting the DMA engine.
+ */
+static int vb2_start_streaming(struct vb2_queue *q)
+{
+       int ret;
+
+       /* Tell the driver to start streaming */
+       ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
+
+       /*
+        * If there are not enough buffers queued to start streaming, then
+        * the start_streaming operation will return -ENOBUFS and you have to
+        * retry when the next buffer is queued.
+        */
+       if (ret == -ENOBUFS) {
+               dprintk(1, "qbuf: not enough buffers, retry when more buffers are queued.\n");
+               q->retry_start_streaming = 1;
+               return 0;
+       }
+       if (ret)
+               dprintk(1, "qbuf: driver refused to start streaming\n");
+       else
+               q->retry_start_streaming = 0;
+       return ret;
+}
+
 static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
 {
        int ret = vb2_queue_or_prepare_buf(q, b, "qbuf");
@@ -1426,6 +1459,12 @@ static int vb2_internal_qbuf(struct vb2_queue *q, struct v4l2_buffer *b)
        /* Fill buffer information for the userspace */
        __fill_v4l2_buffer(vb, b);
 
+       if (q->retry_start_streaming) {
+               ret = vb2_start_streaming(q);
+               if (ret)
+                       return ret;
+       }
+
        dprintk(1, "%s() of buffer %d succeeded\n", __func__, vb->v4l2_buf.index);
        return 0;
 }
@@ -1575,7 +1614,8 @@ int vb2_wait_for_all_buffers(struct vb2_queue *q)
                return -EINVAL;
        }
 
-       wait_event(q->done_wq, !atomic_read(&q->queued_count));
+       if (!q->retry_start_streaming)
+               wait_event(q->done_wq, !atomic_read(&q->queued_count));
        return 0;
 }
 EXPORT_SYMBOL_GPL(vb2_wait_for_all_buffers);
@@ -1689,6 +1729,11 @@ static void __vb2_queue_cancel(struct vb2_queue *q)
 {
        unsigned int i;
 
+       if (q->retry_start_streaming) {
+               q->retry_start_streaming = 0;
+               q->streaming = 0;
+       }
+
        /*
         * Tell driver to stop all transactions and release all queued
         * buffers.
@@ -1738,12 +1783,9 @@ static int vb2_internal_streamon(struct vb2_queue *q, enum v4l2_buf_type type)
        list_for_each_entry(vb, &q->queued_list, queued_entry)
                __enqueue_in_driver(vb);
 
-       /*
-        * Let driver notice that streaming state has been enabled.
-        */
-       ret = call_qop(q, start_streaming, q, atomic_read(&q->queued_count));
+       /* Tell driver to start streaming. */
+       ret = vb2_start_streaming(q);
        if (ret) {
-               dprintk(1, "streamon: driver refused to start streaming\n");
                __vb2_queue_cancel(q);
                return ret;
        }
@@ -2313,15 +2355,15 @@ static int __vb2_init_fileio(struct vb2_queue *q, int read)
                                goto err_reqbufs;
                        fileio->bufs[i].queued = 1;
                }
-
-               /*
-                * Start streaming.
-                */
-               ret = vb2_streamon(q, q->type);
-               if (ret)
-                       goto err_reqbufs;
        }
 
+       /*
+        * Start streaming.
+        */
+       ret = vb2_streamon(q, q->type);
+       if (ret)
+               goto err_reqbufs;
+
        q->fileio = fileio;
 
        return ret;