]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
media: rzv2h-ivc: Replace workqueue with direct function call
authorJacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
Wed, 11 Mar 2026 13:41:56 +0000 (14:41 +0100)
committerHans Verkuil <hverkuil+cisco@kernel.org>
Tue, 24 Mar 2026 15:13:09 +0000 (16:13 +0100)
Scheduling of work items with an async workqueue opens the door to
potential races between multiple instances of a work item.

While the frame transfer function is now protected against races, using
a workqueue doesn't provide much benefit considering the limited cost of
creating a job transfer.

Replace the usage of the work queue with direct function calls.

Reviewed-by: Daniel Scally <dan.scally@ideasonboard.com>
Signed-off-by: Jacopo Mondi <jacopo.mondi+renesas@ideasonboard.com>
Signed-off-by: Hans Verkuil <hverkuil+cisco@kernel.org>
drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-dev.c
drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc-video.c
drivers/media/platform/renesas/rzv2h-ivc/rzv2h-ivc.h

index e9857eb5b51a629bc51e976764b7dce3d1eb97ee..355842abb24b8dac5308aeac0df06adc2ba33daf 100644 (file)
@@ -119,7 +119,7 @@ static irqreturn_t rzv2h_ivc_isr(int irq, void *context)
         * The second interrupt indicates that the post-frame transfer VBLANK
         * has completed, we can now schedule a new frame transfer, if any.
         */
-       queue_work(ivc->buffers.async_wq, &ivc->buffers.work);
+       rzv2h_ivc_transfer_buffer(ivc);
 
        return IRQ_HANDLED;
 }
index 3580a57738a67f4b091274a21a8f1c42397795d3..b167f1bab7ef2736eca6fed91e82d3e47342207d 100644 (file)
@@ -143,13 +143,11 @@ void rzv2h_ivc_buffer_done(struct rzv2h_ivc *ivc)
        vb2_buffer_done(&buf->vb.vb2_buf, VB2_BUF_STATE_DONE);
 }
 
-static void rzv2h_ivc_transfer_buffer(struct work_struct *work)
+void rzv2h_ivc_transfer_buffer(struct rzv2h_ivc *ivc)
 {
-       struct rzv2h_ivc *ivc = container_of(work, struct rzv2h_ivc,
-                                            buffers.work);
        struct rzv2h_ivc_buf *buf;
 
-       guard(spinlock_irqsave)(&ivc->spinlock);
+       lockdep_assert_held(&ivc->spinlock);
 
        if (ivc->vvalid_ifp)
                return;
@@ -204,7 +202,7 @@ static void rzv2h_ivc_buf_queue(struct vb2_buffer *vb)
 
        scoped_guard(spinlock_irq, &ivc->spinlock) {
                if (vb2_is_streaming(vb->vb2_queue))
-                       queue_work(ivc->buffers.async_wq, &ivc->buffers.work);
+                       rzv2h_ivc_transfer_buffer(ivc);
        }
 }
 
@@ -282,7 +280,9 @@ static int rzv2h_ivc_start_streaming(struct vb2_queue *q, unsigned int count)
 
        rzv2h_ivc_format_configure(ivc);
 
-       queue_work(ivc->buffers.async_wq, &ivc->buffers.work);
+       scoped_guard(spinlock_irq, &ivc->spinlock) {
+               rzv2h_ivc_transfer_buffer(ivc);
+       }
 
        return 0;
 
@@ -449,11 +449,6 @@ int rzv2h_ivc_init_vdev(struct rzv2h_ivc *ivc, struct v4l2_device *v4l2_dev)
 
        spin_lock_init(&ivc->buffers.lock);
        INIT_LIST_HEAD(&ivc->buffers.queue);
-       INIT_WORK(&ivc->buffers.work, rzv2h_ivc_transfer_buffer);
-
-       ivc->buffers.async_wq = alloc_workqueue("rzv2h-ivc", 0, 0);
-       if (!ivc->buffers.async_wq)
-               return -EINVAL;
 
        /* Initialise vb2 queue */
        vb2q = &ivc->vdev.vb2q;
@@ -471,7 +466,7 @@ int rzv2h_ivc_init_vdev(struct rzv2h_ivc *ivc, struct v4l2_device *v4l2_dev)
        ret = vb2_queue_init(vb2q);
        if (ret) {
                dev_err(ivc->dev, "vb2 queue init failed\n");
-               goto err_destroy_workqueue;
+               return ret;
        }
 
        /* Initialise Video Device */
@@ -520,8 +515,6 @@ err_cleanup_vdev_entity:
        media_entity_cleanup(&vdev->entity);
 err_release_vb2q:
        vb2_queue_release(vb2q);
-err_destroy_workqueue:
-       destroy_workqueue(ivc->buffers.async_wq);
 
        return ret;
 }
index 049f223200e395963aab013631b9b797c1be7362..6f644ba796a942822aca4447fa0d385deba7b93c 100644 (file)
@@ -104,8 +104,6 @@ struct rzv2h_ivc {
        struct {
                /* Spinlock to guard buffer queue */
                spinlock_t lock;
-               struct workqueue_struct *async_wq;
-               struct work_struct work;
                struct list_head queue;
                struct rzv2h_ivc_buf *curr;
                unsigned int sequence;
@@ -130,3 +128,4 @@ void rzv2h_ivc_deinit_subdevice(struct rzv2h_ivc *ivc);
 void rzv2h_ivc_write(struct rzv2h_ivc *ivc, u32 addr, u32 val);
 void rzv2h_ivc_update_bits(struct rzv2h_ivc *ivc, unsigned int addr,
                           u32 mask, u32 val);
+void rzv2h_ivc_transfer_buffer(struct rzv2h_ivc *ivc);