]> git.karo-electronics.de Git - karo-tx-linux.git/commitdiff
[media] v4l2-mem2mem: clear m2m context from job_queue before ctx streamoff
authorShaik Ameer Basha <shaik.ameer@samsung.com>
Tue, 13 Aug 2013 05:58:07 +0000 (02:58 -0300)
committerMauro Carvalho Chehab <m.chehab@samsung.com>
Sat, 24 Aug 2013 07:04:41 +0000 (04:04 -0300)
When streamoff is called on the context and the context
is added to the job_queue,
1] sometimes device_run receives the empty vb2 buffers (as
   v4l2_m2m_streamoff is dropping the ready queue).
2] sometimes v4l2_m2m_job_finish may not succeed as the m2m_dev->curr_ctx
   is made NULL in the v4l2_m2m_streamoff()
The above points may stop the execution of the other queued contexts.
This patch makes sure that before streamoff is executed on any context,
that context should "not be running" or "not queued" in the job_queue.
1] If the current context is running, then abort job will be called.
2] If the current context is queued, then the context will be removed from
   the job_queue.

Signed-off-by: Shaik Ameer Basha <shaik.ameer@samsung.com>
Signed-off-by: Kamil Debski <k.debski@samsung.com>
Signed-off-by: Mauro Carvalho Chehab <m.chehab@samsung.com>
drivers/media/v4l2-core/v4l2-mem2mem.c

index 89b90672088c7473bd80bd09ce1c47df4fc7bc2c..7c43712882158787e951ba9a923fa86d1eb67f90 100644 (file)
@@ -265,6 +265,39 @@ static void v4l2_m2m_try_schedule(struct v4l2_m2m_ctx *m2m_ctx)
        v4l2_m2m_try_run(m2m_dev);
 }
 
+/**
+ * v4l2_m2m_cancel_job() - cancel pending jobs for the context
+ *
+ * In case of streamoff or release called on any context,
+ * 1] If the context is currently running, then abort job will be called
+ * 2] If the context is queued, then the context will be removed from
+ *    the job_queue
+ */
+static void v4l2_m2m_cancel_job(struct v4l2_m2m_ctx *m2m_ctx)
+{
+       struct v4l2_m2m_dev *m2m_dev;
+       unsigned long flags;
+
+       m2m_dev = m2m_ctx->m2m_dev;
+       spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
+       if (m2m_ctx->job_flags & TRANS_RUNNING) {
+               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+               m2m_dev->m2m_ops->job_abort(m2m_ctx->priv);
+               dprintk("m2m_ctx %p running, will wait to complete", m2m_ctx);
+               wait_event(m2m_ctx->finished,
+                               !(m2m_ctx->job_flags & TRANS_RUNNING));
+       } else if (m2m_ctx->job_flags & TRANS_QUEUED) {
+               list_del(&m2m_ctx->queue);
+               m2m_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
+               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+               dprintk("m2m_ctx: %p had been on queue and was removed\n",
+                       m2m_ctx);
+       } else {
+               /* Do nothing, was not on queue/running */
+               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+       }
+}
+
 /**
  * v4l2_m2m_job_finish() - inform the framework that a job has been finished
  * and have it clean up
@@ -436,6 +469,9 @@ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
        unsigned long flags_job, flags;
        int ret;
 
+       /* wait until the current context is dequeued from job_queue */
+       v4l2_m2m_cancel_job(m2m_ctx);
+
        q_ctx = get_queue_ctx(m2m_ctx, type);
        ret = vb2_streamoff(&q_ctx->q, type);
        if (ret)
@@ -658,27 +694,8 @@ EXPORT_SYMBOL_GPL(v4l2_m2m_ctx_init);
  */
 void v4l2_m2m_ctx_release(struct v4l2_m2m_ctx *m2m_ctx)
 {
-       struct v4l2_m2m_dev *m2m_dev;
-       unsigned long flags;
-
-       m2m_dev = m2m_ctx->m2m_dev;
-
-       spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
-       if (m2m_ctx->job_flags & TRANS_RUNNING) {
-               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
-               m2m_dev->m2m_ops->job_abort(m2m_ctx->priv);
-               dprintk("m2m_ctx %p running, will wait to complete", m2m_ctx);
-               wait_event(m2m_ctx->finished, !(m2m_ctx->job_flags & TRANS_RUNNING));
-       } else if (m2m_ctx->job_flags & TRANS_QUEUED) {
-               list_del(&m2m_ctx->queue);
-               m2m_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
-               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
-               dprintk("m2m_ctx: %p had been on queue and was removed\n",
-                       m2m_ctx);
-       } else {
-               /* Do nothing, was not on queue/running */
-               spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
-       }
+       /* wait until the current context is dequeued from job_queue */
+       v4l2_m2m_cancel_job(m2m_ctx);
 
        vb2_queue_release(&m2m_ctx->cap_q_ctx.q);
        vb2_queue_release(&m2m_ctx->out_q_ctx.q);