[PATCH v2 06/17] media: v4l2-mem2mem: drop curr_ctx member from v4l2_m2m_dev struct
From: Sven Püschel
Date: Wed Sep 16 2026 - 11:19:00 EST
Drop the curr_ctx member from the v4l2_m2m_dev struct in preparation of
adding support for running multiple jobs in parallel.
The curr_ctx member of a v4l2_m2m_dev was used to track the
currently running context. But the currently running context will always
be at the top of the job_queue. As the TRANS_RUNNING flag can be used to
check if the queue head is already running, the curr_ctx member can be
completely dropped.
By eliminating the struct member the code is mostly agnostic whenever
only one job is running at a time or multiple run at the same time. The
main exception is the v4l2_m2m_get_curr_priv function, which is by it's
design incompatible with running multiple jobs in parallel.
Signed-off-by: Sven Püschel <s.pueschel@xxxxxxxxxxxxxx>
---
v2:
- split curr_ctx removal into a separate commit
- add WARN_ON to _v4l2_m2m_job_finish to prevent mismatching context to
device (and an unused m2m_dev argument)
- rewrite v4l2_m2m_get_curr_priv to get private data inside the spinlock
(https://sashiko.dev/#/patchset/20260606-spu-rga3multicore-v1-0-3ec2b15675f7%40pengutronix.de?part=5)
---
drivers/media/v4l2-core/v4l2-mem2mem.c | 61 ++++++++++++++++++----------------
1 file changed, 33 insertions(+), 28 deletions(-)
diff --git a/drivers/media/v4l2-core/v4l2-mem2mem.c b/drivers/media/v4l2-core/v4l2-mem2mem.c
index a65cbb124cfe0..60cca94195166 100644
--- a/drivers/media/v4l2-core/v4l2-mem2mem.c
+++ b/drivers/media/v4l2-core/v4l2-mem2mem.c
@@ -84,7 +84,6 @@ static const char * const m2m_entity_name[] = {
* v4l2_m2m_unregister_media_controller().
* @intf_devnode: &struct media_intf devnode pointer with the interface
* with controls the M2M device.
- * @curr_ctx: currently running instance
* @job_queue: instances queued to run
* @job_spinlock: protects job_queue
* @job_work: worker to run queued jobs.
@@ -93,7 +92,6 @@ static const char * const m2m_entity_name[] = {
* @kref: device reference count
*/
struct v4l2_m2m_dev {
- struct v4l2_m2m_ctx *curr_ctx;
#ifdef CONFIG_MEDIA_CONTROLLER
struct media_entity *source;
struct media_pad source_pad;
@@ -232,8 +230,14 @@ void *v4l2_m2m_get_curr_priv(struct v4l2_m2m_dev *m2m_dev)
void *ret = NULL;
spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
- if (m2m_dev->curr_ctx)
- ret = m2m_dev->curr_ctx->priv;
+ if (!list_empty(&m2m_dev->job_queue)) {
+ struct v4l2_m2m_ctx *first_ctx =
+ list_first_entry(&m2m_dev->job_queue,
+ struct v4l2_m2m_ctx, queue);
+
+ if (first_ctx->job_flags & TRANS_RUNNING)
+ ret = first_ctx->priv;
+ }
spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
return ret;
@@ -252,14 +256,9 @@ EXPORT_SYMBOL(v4l2_m2m_get_curr_priv);
static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev)
{
unsigned long flags;
+ struct v4l2_m2m_ctx *chosen_ctx;
spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
- if (NULL != m2m_dev->curr_ctx) {
- spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
- dprintk("Another instance is running, won't run now\n");
- return;
- }
-
if (list_empty(&m2m_dev->job_queue)) {
spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
dprintk("No job pending\n");
@@ -272,13 +271,18 @@ static void v4l2_m2m_try_run(struct v4l2_m2m_dev *m2m_dev)
return;
}
- m2m_dev->curr_ctx = list_first_entry(&m2m_dev->job_queue,
- struct v4l2_m2m_ctx, queue);
- m2m_dev->curr_ctx->job_flags |= TRANS_RUNNING;
+ chosen_ctx = list_first_entry(&m2m_dev->job_queue, struct v4l2_m2m_ctx, queue);
+ if (chosen_ctx->job_flags & TRANS_RUNNING) {
+ spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+ dprintk("Another instance is running, won't run now\n");
+ return;
+ }
+
+ chosen_ctx->job_flags |= TRANS_RUNNING;
spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
- dprintk("Running job on m2m_ctx: %p\n", m2m_dev->curr_ctx);
- m2m_dev->m2m_ops->device_run(m2m_dev->curr_ctx->priv);
+ dprintk("Running job on m2m_ctx: %p\n", chosen_ctx);
+ m2m_dev->m2m_ops->device_run(chosen_ctx->priv);
}
/*
@@ -469,15 +473,16 @@ static void v4l2_m2m_schedule_next_job(struct v4l2_m2m_dev *m2m_dev,
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) {
+ if (!m2m_ctx || !(m2m_ctx->job_flags & TRANS_RUNNING)) {
dprintk("Called by an instance not currently running\n");
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;
+ WARN_ON(m2m_dev != m2m_ctx->m2m_dev);
+
+ list_del(&m2m_ctx->queue);
+ m2m_ctx->job_flags &= ~(TRANS_QUEUED | TRANS_RUNNING);
+ wake_up(&m2m_ctx->finished);
return true;
}
@@ -548,12 +553,15 @@ void v4l2_m2m_suspend(struct v4l2_m2m_dev *m2m_dev)
spin_lock_irqsave(&m2m_dev->job_spinlock, flags);
m2m_dev->job_queue_flags |= QUEUE_PAUSED;
- curr_ctx = m2m_dev->curr_ctx;
+ if (list_empty(&m2m_dev->job_queue)) {
+ spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
+ return;
+ }
+
+ curr_ctx = list_first_entry(&m2m_dev->job_queue, struct v4l2_m2m_ctx, queue);
spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags);
- if (curr_ctx)
- wait_event(curr_ctx->finished,
- !(curr_ctx->job_flags & TRANS_RUNNING));
+ wait_event(curr_ctx->finished, !(curr_ctx->job_flags & TRANS_RUNNING));
}
EXPORT_SYMBOL(v4l2_m2m_suspend);
@@ -896,10 +904,8 @@ int v4l2_m2m_streamoff(struct file *file, struct v4l2_m2m_ctx *m2m_ctx,
q_ctx->num_rdy = 0;
spin_unlock_irqrestore(&q_ctx->rdy_spinlock, flags);
- if (m2m_dev->curr_ctx == m2m_ctx) {
- m2m_dev->curr_ctx = NULL;
+ if (m2m_ctx->job_flags & TRANS_RUNNING)
wake_up(&m2m_ctx->finished);
- }
spin_unlock_irqrestore(&m2m_dev->job_spinlock, flags_job);
return 0;
@@ -1194,7 +1200,6 @@ struct v4l2_m2m_dev *v4l2_m2m_init(const struct v4l2_m2m_ops *m2m_ops)
if (!m2m_dev)
return ERR_PTR(-ENOMEM);
- m2m_dev->curr_ctx = NULL;
m2m_dev->m2m_ops = m2m_ops;
INIT_LIST_HEAD(&m2m_dev->job_queue);
spin_lock_init(&m2m_dev->job_spinlock);
--
2.55.0