diff options
Diffstat (limited to 'target/linux/bcm27xx/patches-5.4/950-0487-media-v4l2-mem2mem-support-held-capture-buffers.patch')
-rw-r--r-- | target/linux/bcm27xx/patches-5.4/950-0487-media-v4l2-mem2mem-support-held-capture-buffers.patch | 260 |
1 files changed, 0 insertions, 260 deletions
diff --git a/target/linux/bcm27xx/patches-5.4/950-0487-media-v4l2-mem2mem-support-held-capture-buffers.patch b/target/linux/bcm27xx/patches-5.4/950-0487-media-v4l2-mem2mem-support-held-capture-buffers.patch deleted file mode 100644 index bb66baf07d..0000000000 --- a/target/linux/bcm27xx/patches-5.4/950-0487-media-v4l2-mem2mem-support-held-capture-buffers.patch +++ /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) - { |