[PATCH v12 74/86] media: ipu6: Start streaming once all queues have started, stop when not

Sakari Ailus
2026-04-09T20:15:15Z

Start streaming once all buffer queues connected via enabled routes have
been set streaming, similarly stop when the first queue is stopped.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c | 45 +++++++++++++++++++
.../media/pci/intel/ipu6/ipu6-isys-queue.c | 7 +--
2 files changed, 46 insertions(+), 6 deletions(-)

diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
index 04825cdce7c0..8deafe38be5d 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-csi2.c
@@ -12,6 +12,7 @@
#include <linux/io.h>
#include <linux/minmax.h>
#include <linux/sprintf.h>
+#include <linux/string_choices.h>

#include <media/media-entity.h>
#include <media/v4l2-ctrls.h>
@@ -347,6 +348,42 @@ static int ipu6_isys_csi2_set_stream(struct v4l2_subdev *sd,
return ret;
}

+static bool ipu6_isys_csi2_streaming_change(struct ipu6_isys_subdev *asd,
+ struct v4l2_subdev_state *state,
+ u32 pad, bool enable)
+{
+ u32 streams_enabled = 0, nodes_streaming = 0;
+ struct v4l2_subdev_route *route;
+
+ for_each_active_route(&state->routing, route) {
+ struct media_pad *video_pad =
+ media_pad_remote_pad_unique(&asd->sd.entity.pads[route->source_pad]);
+ struct ipu6_isys_video *av = !video_pad ? NULL :
+ container_of_const(video_pad,
+ struct ipu6_isys_video, pad);
+
+ if (!av) {
+ dev_dbg(asd->sd.dev,
+ "can't find source pad for \"%s\":%u\n",
+ asd->sd.entity.name, route->source_pad);
+ return false;
+ }
+
+ streams_enabled++;
+ if (av->streaming || (enable && pad == route->source_pad))
+ nodes_streaming++;
+ }
+
+ if (streams_enabled == nodes_streaming) {
+ dev_dbg(asd->sd.dev,
+ "changing streaming state to %s on \"%s\":%u\n",
+ str_enabled_disabled(enable), asd->sd.entity.name, pad);
+ return true;
+ }
+
+ return false;
+}
+
static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
u32 pad, u64 streams_mask)
@@ -364,6 +401,9 @@ static int ipu6_isys_csi2_enable_streams(struct v4l2_subdev *sd,

list_add(&av->csi2_entry, &csi2->av_head);

+ if (!ipu6_isys_csi2_streaming_change(asd, state, pad, true))
+ return 0;
+
ret = ipu6_isys_start_stream_firmware(av);
if (ret) {
dev_err(sd->dev, "start stream of firmware failed\n");
@@ -409,6 +449,7 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
struct v4l2_subdev_state *state,
u32 pad, u64 streams_mask)
{
+ struct ipu6_isys_subdev *asd = to_ipu6_isys_subdev(sd);
struct media_pad *remote_pad,
*vdev_pad = media_pad_remote_pad_unique(&sd->entity.pads[pad]);
struct ipu6_isys_video *av =
@@ -416,6 +457,9 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,
struct v4l2_subdev *remote_sd;
u64 sink_streams;

+ if (!ipu6_isys_csi2_streaming_change(asd, state, pad, false))
+ goto out_del_csi2_entry;
+
sink_streams =
v4l2_subdev_state_xlate_streams(state, pad, CSI2_PAD_SINK,
&streams_mask);
@@ -431,6 +475,7 @@ static int ipu6_isys_csi2_disable_streams(struct v4l2_subdev *sd,

ipu6_isys_close_streaming_firmware(av);

+out_del_csi2_entry:
list_del(&av->csi2_entry);

return 0;
diff --git a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
index 13d759b27ca0..7df13d330667 100644
--- a/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
+++ b/drivers/media/pci/intel/ipu6/ipu6-isys-queue.c
@@ -585,14 +585,10 @@ static int start_streaming(struct vb2_queue *q, unsigned int count)
ipu6_isys_configure_stream_watermark(av, source_pad->entity);
ipu6_isys_update_stream_watermark(av, true);

- if (stream->nr_streaming != stream->nr_queues)
- goto out;
-
ret = ipu6_isys_stream_start(av);
if (ret)
goto out_stream_start;

-out:
mutex_unlock(&stream->mutex);

return 0;
@@ -626,8 +622,7 @@ static void stop_streaming(struct vb2_queue *q)
ipu6_isys_update_stream_watermark(av, false);

mutex_lock(&av->isys->stream_mutex);
- if (stream->nr_streaming == stream->nr_queues)
- ipu6_isys_video_set_streaming(av, 0);
+ ipu6_isys_video_set_streaming(av, 0);
list_del(&aq->node);
mutex_unlock(&av->isys->stream_mutex);

--
2.47.3