staging: bcm2835-camera: Ensure all buffers are returned on disable [Linux 5.2.1]

staging: bcm2835-camera: Ensure all buffers are returned on disable [Linux 5.2.1]

This Linux kernel change "staging: bcm2835-camera: Ensure all buffers are returned on disable" is included in the Linux 5.2.1 release. This change is authored by Dave Stevenson <dave.stevenson [at] raspberrypi.org> on Sat Jun 29 14:13:29 2019 +0200. The commit for this change in Linux stable tree is 4b28ea4 (patch) which is from upstream commit 70ec64c. The same Linux upstream change may have been applied to various maintained Linux releases and you can find all Linux releases containing changes from upstream 70ec64c.

staging: bcm2835-camera: Ensure all buffers are returned on disable

commit 70ec64ccdaac5d8f634338e33b016c1c99831499 upstream.

With the recent change to match MMAL and V4L2 buffers there
is a need to wait for all MMAL buffers to be returned during
stop_streaming.

Fixes: 938416707071 ("staging: bcm2835-camera: Remove V4L2/MMAL buffer remapping")
Signed-off-by: Dave Stevenson <[email protected]>
Signed-off-by: Stefan Wahren <[email protected]>
Acked-by: Hans Verkuil <[email protected]>
Acked-by: Mauro Carvalho Chehab <[email protected]>
Signed-off-by: Greg Kroah-Hartman <[email protected]>

There are 29 lines of Linux source code added/deleted in this change. Code changes to Linux kernel are as follows.

 .../vc04_services/bcm2835-camera/bcm2835-camera.c  | 22 ++++++++++++++++------
 .../vc04_services/bcm2835-camera/mmal-vchiq.c      |  4 ++++
 .../vc04_services/bcm2835-camera/mmal-vchiq.h      |  3 +++
 3 files changed, 23 insertions(+), 6 deletions(-)

diff --git a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
index 68f08dc..bc6ff83 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/bcm2835-camera.c
@@ -576,6 +576,7 @@ static void stop_streaming(struct vb2_queue *vq)
    int ret;
    unsigned long timeout;
    struct bm2835_mmal_dev *dev = vb2_get_drv_priv(vq);
+   struct vchiq_mmal_port *port = dev->capture.port;

    v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev, "%s: dev:%p\n",
         __func__, dev);
@@ -599,12 +600,6 @@ static void stop_streaming(struct vb2_queue *vq)
                      &dev->capture.frame_count,
                      sizeof(dev->capture.frame_count));

-   /* wait for last frame to complete */
-   timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt, HZ);
-   if (timeout == 0)
-       v4l2_err(&dev->v4l2_dev,
-            "timed out waiting for frame completion\n");
-
    v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
         "disabling connection\n");

@@ -619,6 +614,21 @@ static void stop_streaming(struct vb2_queue *vq)
             ret);
    }

+   /* wait for all buffers to be returned */
+   while (atomic_read(&port->buffers_with_vpu)) {
+       v4l2_dbg(1, bcm2835_v4l2_debug, &dev->v4l2_dev,
+            "%s: Waiting for buffers to be returned - %d outstanding\n",
+            __func__, atomic_read(&port->buffers_with_vpu));
+       timeout = wait_for_completion_timeout(&dev->capture.frame_cmplt,
+                             HZ);
+       if (timeout == 0) {
+           v4l2_err(&dev->v4l2_dev, "%s: Timeout waiting for buffers to be returned - %d outstanding\n",
+                __func__,
+                atomic_read(&port->buffers_with_vpu));
+           break;
+       }
+   }
+
    if (disable_camera(dev) < 0)
        v4l2_err(&dev->v4l2_dev, "Failed to disable camera\n");
 }
diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
index f1bb900..c62625b8 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.c
@@ -240,6 +240,8 @@ static void buffer_work_cb(struct work_struct *work)
    struct mmal_msg_context *msg_context =
        container_of(work, struct mmal_msg_context, u.bulk.work);

+   atomic_dec(&msg_context->u.bulk.port->buffers_with_vpu);
+
    msg_context->u.bulk.port->buffer_cb(msg_context->u.bulk.instance,
                        msg_context->u.bulk.port,
                        msg_context->u.bulk.status,
@@ -380,6 +382,8 @@ static int inline_receive(struct vchiq_mmal_instance *instance,
    /* initialise work structure ready to schedule callback */
    INIT_WORK(&msg_context->u.bulk.work, buffer_work_cb);

+   atomic_inc(&port->buffers_with_vpu);
+
    /* prep the buffer from host message */
    memset(&m, 0xbc, sizeof(m));    /* just to make debug clearer */

diff --git a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
index 22b839e..b0ee171 100644
--- a/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
+++ b/drivers/staging/vc04_services/bcm2835-camera/mmal-vchiq.h
@@ -71,6 +71,9 @@ struct vchiq_mmal_port {
    struct list_head buffers;
    /* lock to serialise adding and removing buffers from list */
    spinlock_t slock;
+
+   /* Count of buffers the VPU has yet to return */
+   atomic_t buffers_with_vpu;
    /* callback on buffer completion */
    vchiq_mmal_buffer_cb buffer_cb;
    /* callback context */

Leave a Reply

Your email address will not be published. Required fields are marked *