bcm27xx: update to latest patches from RPi foundation
[openwrt/openwrt.git] / target / linux / bcm27xx / patches-5.4 / 950-0495-media-v4l2-mem2mem-support-held-capture-buffers.patch
diff --git a/target/linux/bcm27xx/patches-5.4/950-0495-media-v4l2-mem2mem-support-held-capture-buffers.patch b/target/linux/bcm27xx/patches-5.4/950-0495-media-v4l2-mem2mem-support-held-capture-buffers.patch
deleted file mode 100644 (file)
index bb66baf..0000000
+++ /dev/null
@@ -1,260 +0,0 @@
-From dc9b786e4b9a1262b536b3c9d0fa88e34a2b3f8f Mon Sep 17 00:00:00 2001
-From: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-Date: Fri, 11 Oct 2019 06:32:41 -0300
-Subject: [PATCH] media: v4l2-mem2mem: support held capture buffers
-
-Commit f8cca8c97a63d77f48334cde81d15014f43530ef upstream.
-
-Check for held buffers that are ready to be returned to vb2 in
-__v4l2_m2m_try_queue(). This avoids drivers having to handle this
-case.
-
-Add v4l2_m2m_buf_done_and_job_finish() to correctly return source
-and destination buffers and mark the job as finished while taking
-a held destination buffer into account (i.e. that buffer won't be
-returned). This has to be done while job_spinlock is held to avoid
-race conditions.
-
-Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
-Signed-off-by: Mauro Carvalho Chehab <mchehab+samsung@kernel.org>
----
- drivers/media/v4l2-core/v4l2-mem2mem.c | 130 ++++++++++++++++++-------
- include/media/v4l2-mem2mem.h           |  33 ++++++-
- 2 files changed, 128 insertions(+), 35 deletions(-)
-
---- a/drivers/media/v4l2-core/v4l2-mem2mem.c
-+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
-@@ -284,7 +284,8 @@ static void v4l2_m2m_try_run(struct v4l2
- static void __v4l2_m2m_try_queue(struct v4l2_m2m_dev *m2m_dev,
-                                struct v4l2_m2m_ctx *m2m_ctx)
- {
--      unsigned long flags_job, flags_out, flags_cap;
-+      unsigned long flags_job;
-+      struct vb2_v4l2_buffer *dst, *src;
-       dprintk("Trying to schedule a job for m2m_ctx: %p\n", m2m_ctx);
-@@ -307,20 +308,30 @@ static void __v4l2_m2m_try_queue(struct
-               goto job_unlock;
-       }
--      spin_lock_irqsave(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out);
--      if (list_empty(&m2m_ctx->out_q_ctx.rdy_queue)
--          && !m2m_ctx->out_q_ctx.buffered) {
-+      src = v4l2_m2m_next_src_buf(m2m_ctx);
-+      dst = v4l2_m2m_next_dst_buf(m2m_ctx);
-+      if (!src && !m2m_ctx->out_q_ctx.buffered) {
-               dprintk("No input buffers available\n");
--              goto out_unlock;
-+              goto job_unlock;
-       }
--      spin_lock_irqsave(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap);
--      if (list_empty(&m2m_ctx->cap_q_ctx.rdy_queue)
--          && !m2m_ctx->cap_q_ctx.buffered) {
-+      if (!dst && !m2m_ctx->cap_q_ctx.buffered) {
-               dprintk("No output buffers available\n");
--              goto cap_unlock;
-+              goto job_unlock;
-+      }
-+
-+      if (src && dst &&
-+          dst->is_held && dst->vb2_buf.copied_timestamp &&
-+          dst->vb2_buf.timestamp != src->vb2_buf.timestamp) {
-+              dst->is_held = false;
-+              v4l2_m2m_dst_buf_remove(m2m_ctx);
-+              v4l2_m2m_buf_done(dst, VB2_BUF_STATE_DONE);
-+              dst = v4l2_m2m_next_dst_buf(m2m_ctx);
-+
-+              if (!dst && !m2m_ctx->cap_q_ctx.buffered) {
-+                      dprintk("No output buffers available after returning held buffer\n");
-+                      goto job_unlock;
-+              }
-       }
--      spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap);
--      spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out);
-       if (m2m_dev->m2m_ops->job_ready
-               && (!m2m_dev->m2m_ops->job_ready(m2m_ctx->priv))) {
-@@ -331,13 +342,6 @@ static void __v4l2_m2m_try_queue(struct
-       list_add_tail(&m2m_ctx->queue, &m2m_dev->job_queue);
-       m2m_ctx->job_flags |= TRANS_QUEUED;
--      spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
--      return;
--
--cap_unlock:
--      spin_unlock_irqrestore(&m2m_ctx->cap_q_ctx.rdy_spinlock, flags_cap);
--out_unlock:
--      spin_unlock_irqrestore(&m2m_ctx->out_q_ctx.rdy_spinlock, flags_out);
- job_unlock:
-       spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
- }
-@@ -412,37 +416,97 @@ static void v4l2_m2m_cancel_job(struct v
-       }
- }
--void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
--                       struct v4l2_m2m_ctx *m2m_ctx)
-+/*
-+ * Schedule the next job, called from v4l2_m2m_job_finish() or
-+ * v4l2_m2m_buf_done_and_job_finish().
-+ */
-+static void v4l2_m2m_schedule_next_job(struct v4l2_m2m_dev *m2m_dev,
-+                                     struct v4l2_m2m_ctx *m2m_ctx)
- {
--      unsigned long flags;
-+      /*
-+       * This instance might have more buffers ready, but since we do not
-+       * allow more than one job on the job_queue per instance, each has
-+       * to be scheduled separately after the previous one finishes.
-+       */
-+      __v4l2_m2m_try_queue(m2m_dev, m2m_ctx);
--      spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
-+      /*
-+       * We might be running in atomic context,
-+       * but the job must be run in non-atomic context.
-+       */
-+      schedule_work(&m2m_dev->job_work);
-+}
-+
-+/*
-+ * Assumes job_spinlock is held, called from v4l2_m2m_job_finish() or
-+ * v4l2_m2m_buf_done_and_job_finish().
-+ */
-+static bool _v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
-+                               struct v4l2_m2m_ctx *m2m_ctx)
-+{
-       if (!m2m_dev->curr_ctx || m2m_dev->curr_ctx != m2m_ctx) {
--              spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
-               dprintk("Called by an instance not currently running\n");
--              return;
-+              return false;
-       }
-       list_del(&m2m_dev->curr_ctx->queue);
-       m2m_dev->curr_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
-       wake_up(&m2m_dev->curr_ctx->finished);
-       m2m_dev->curr_ctx = NULL;
-+      return true;
-+}
--      spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
--
--      /* This instance might have more buffers ready, but since we do not
--       * allow more than one job on the job_queue per instance, each has
--       * to be scheduled separately after the previous one finishes. */
--      __v4l2_m2m_try_queue(m2m_dev, m2m_ctx);
-+void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
-+                       struct v4l2_m2m_ctx *m2m_ctx)
-+{
-+      unsigned long flags;
-+      bool schedule_next;
--      /* We might be running in atomic context,
--       * but the job must be run in non-atomic context.
-+      /*
-+       * This function should not be used for drivers that support
-+       * holding capture buffers. Those should use
-+       * v4l2_m2m_buf_done_and_job_finish() instead.
-        */
--      schedule_work(&m2m_dev->job_work);
-+      WARN_ON(m2m_ctx->cap_q_ctx.q.subsystem_flags &
-+              VB2_V4L2_FL_SUPPORTS_M2M_HOLD_CAPTURE_BUF);
-+      spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
-+      schedule_next = _v4l2_m2m_job_finish(m2m_dev, m2m_ctx);
-+      spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
-+
-+      if (schedule_next)
-+              v4l2_m2m_schedule_next_job(m2m_dev, m2m_ctx);
- }
- EXPORT_SYMBOL(v4l2_m2m_job_finish);
-+void v4l2_m2m_buf_done_and_job_finish(struct v4l2_m2m_dev *m2m_dev,
-+                                    struct v4l2_m2m_ctx *m2m_ctx,
-+                                    enum vb2_buffer_state state)
-+{
-+      struct vb2_v4l2_buffer *src_buf, *dst_buf;
-+      bool schedule_next = false;
-+      unsigned long flags;
-+
-+      spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
-+      src_buf = v4l2_m2m_src_buf_remove(m2m_ctx);
-+      dst_buf = v4l2_m2m_next_dst_buf(m2m_ctx);
-+
-+      if (WARN_ON(!src_buf || !dst_buf))
-+              goto unlock;
-+      v4l2_m2m_buf_done(src_buf, state);
-+      dst_buf->is_held = src_buf->flags & V4L2_BUF_FLAG_M2M_HOLD_CAPTURE_BUF;
-+      if (!dst_buf->is_held) {
-+              v4l2_m2m_dst_buf_remove(m2m_ctx);
-+              v4l2_m2m_buf_done(dst_buf, state);
-+      }
-+      schedule_next = _v4l2_m2m_job_finish(m2m_dev, m2m_ctx);
-+unlock:
-+      spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
-+
-+      if (schedule_next)
-+              v4l2_m2m_schedule_next_job(m2m_dev, m2m_ctx);
-+}
-+EXPORT_SYMBOL(v4l2_m2m_buf_done_and_job_finish);
-+
- int v4l2_m2m_reqbufs(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
-                    struct v4l2_requestbuffers *reqbufs)
- {
---- a/include/media/v4l2-mem2mem.h
-+++ b/include/media/v4l2-mem2mem.h
-@@ -21,7 +21,8 @@
-  *            callback.
-  *            The job does NOT have to end before this callback returns
-  *            (and it will be the usual case). When the job finishes,
-- *            v4l2_m2m_job_finish() has to be called.
-+ *            v4l2_m2m_job_finish() or v4l2_m2m_buf_done_and_job_finish()
-+ *            has to be called.
-  * @job_ready:        optional. Should return 0 if the driver does not have a job
-  *            fully prepared to run yet (i.e. it will not be able to finish a
-  *            transaction without sleeping). If not provided, it will be
-@@ -33,7 +34,8 @@
-  *            stop the device safely; e.g. in the next interrupt handler),
-  *            even if the transaction would not have been finished by then.
-  *            After the driver performs the necessary steps, it has to call
-- *            v4l2_m2m_job_finish() (as if the transaction ended normally).
-+ *            v4l2_m2m_job_finish() or v4l2_m2m_buf_done_and_job_finish() as
-+ *            if the transaction ended normally.
-  *            This function does not have to (and will usually not) wait
-  *            until the device enters a state when it can be stopped.
-  */
-@@ -173,6 +175,33 @@ void v4l2_m2m_try_schedule(struct v4l2_m
- void v4l2_m2m_job_finish(struct v4l2_m2m_dev *m2m_dev,
-                        struct v4l2_m2m_ctx *m2m_ctx);
-+/**
-+ * v4l2_m2m_buf_done_and_job_finish() - return source/destination buffers with
-+ * state and inform the framework that a job has been finished and have it
-+ * clean up
-+ *
-+ * @m2m_dev: opaque pointer to the internal data to handle M2M context
-+ * @m2m_ctx: m2m context assigned to the instance given by struct &v4l2_m2m_ctx
-+ * @state: vb2 buffer state passed to v4l2_m2m_buf_done().
-+ *
-+ * Drivers that set V4L2_BUF_CAP_SUPPORTS_M2M_HOLD_CAPTURE_BUF must use this
-+ * function instead of job_finish() to take held buffers into account. It is
-+ * optional for other drivers.
-+ *
-+ * This function removes the source buffer from the ready list and returns
-+ * it with the given state. The same is done for the destination buffer, unless
-+ * it is marked 'held'. In that case the buffer is kept on the ready list.
-+ *
-+ * After that the job is finished (see job_finish()).
-+ *
-+ * This allows for multiple output buffers to be used to fill in a single
-+ * capture buffer. This is typically used by stateless decoders where
-+ * multiple e.g. H.264 slices contribute to a single decoded frame.
-+ */
-+void v4l2_m2m_buf_done_and_job_finish(struct v4l2_m2m_dev *m2m_dev,
-+                                    struct v4l2_m2m_ctx *m2m_ctx,
-+                                    enum vb2_buffer_state state);
-+
- static inline void
- v4l2_m2m_buf_done(struct vb2_v4l2_buffer *buf, enum vb2_buffer_state state)
- {