]> git.ipfire.org Git - thirdparty/kernel/stable.git/commitdiff
media: subdev: Improve v4l2_subdev_enable/disable_streams_fallback
authorTomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Wed, 24 Apr 2024 15:39:08 +0000 (18:39 +0300)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 2 May 2025 05:50:37 +0000 (07:50 +0200)
[ Upstream commit 61d6c8c896c1ccde350c281817847a32b0c6b83b ]

v4l2_subdev_enable/disable_streams_fallback() supports falling back to
.s_stream() for subdevs with a single source pad. It also tracks the
enabled streams for that one pad in the sd->enabled_streams field.

Tracking the enabled streams with sd->enabled_streams does not make
sense, as with .s_stream() there can only be a single stream per pad.
Thus, as the v4l2_subdev_enable/disable_streams_fallback() only supports
a single source pad, all we really need is a boolean which tells whether
streaming has been enabled on this pad or not.

However, as we only need a true/false state for a pad (instead of
tracking which streams have been enabled for a pad), we can easily
extend the fallback mechanism to support multiple source pads as we only
need to keep track of which pads have been enabled.

Change the sd->enabled_streams field to sd->enabled_pads, which is a
64-bit bitmask tracking the enabled source pads. With this change we can
remove the restriction that
v4l2_subdev_enable/disable_streams_fallback() only supports a single
source pad.

Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Tested-by: Umang Jain <umang.jain@ideasonboard.com>
Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
Stable-dep-of: 36cef585e2a3 ("media: vimc: skip .s_stream() for stopped entities")
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/media/v4l2-core/v4l2-subdev.c
include/media/v4l2-subdev.h

index 8bfbe9d5fe3c4469ac19fc9a6cb207c8e7a82f28..f555fd3c4b76dc2f0aa02a0521583804c60f437f 100644 (file)
@@ -1925,37 +1925,43 @@ static int v4l2_subdev_enable_streams_fallback(struct v4l2_subdev *sd, u32 pad,
                                               u64 streams_mask)
 {
        struct device *dev = sd->entity.graph_obj.mdev->dev;
-       unsigned int i;
        int ret;
 
        /*
         * The subdev doesn't implement pad-based stream enable, fall back
-        * on the .s_stream() operation. This can only be done for subdevs that
-        * have a single source pad, as sd->enabled_streams is global to the
-        * subdev.
+        * to the .s_stream() operation.
         */
        if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
                return -EOPNOTSUPP;
 
-       for (i = 0; i < sd->entity.num_pads; ++i) {
-               if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE)
-                       return -EOPNOTSUPP;
-       }
+       /*
+        * .s_stream() means there is no streams support, so the only allowed
+        * stream is the implicit stream 0.
+        */
+       if (streams_mask != BIT_ULL(0))
+               return -EOPNOTSUPP;
+
+       /*
+        * We use a 64-bit bitmask for tracking enabled pads, so only subdevices
+        * with 64 pads or less can be supported.
+        */
+       if (pad >= sizeof(sd->enabled_pads) * BITS_PER_BYTE)
+               return -EOPNOTSUPP;
 
-       if (sd->enabled_streams & streams_mask) {
-               dev_dbg(dev, "set of streams %#llx already enabled on %s:%u\n",
-                       streams_mask, sd->entity.name, pad);
+       if (sd->enabled_pads & BIT_ULL(pad)) {
+               dev_dbg(dev, "pad %u already enabled on %s\n",
+                       pad, sd->entity.name);
                return -EALREADY;
        }
 
-       /* Start streaming when the first streams are enabled. */
-       if (!sd->enabled_streams) {
+       /* Start streaming when the first pad is enabled. */
+       if (!sd->enabled_pads) {
                ret = v4l2_subdev_call(sd, video, s_stream, 1);
                if (ret)
                        return ret;
        }
 
-       sd->enabled_streams |= streams_mask;
+       sd->enabled_pads |= BIT_ULL(pad);
 
        return 0;
 }
@@ -2042,37 +2048,43 @@ static int v4l2_subdev_disable_streams_fallback(struct v4l2_subdev *sd, u32 pad,
                                                u64 streams_mask)
 {
        struct device *dev = sd->entity.graph_obj.mdev->dev;
-       unsigned int i;
        int ret;
 
        /*
-        * If the subdev doesn't implement pad-based stream enable, fall  back
-        * on the .s_stream() operation. This can only be done for subdevs that
-        * have a single source pad, as sd->enabled_streams is global to the
-        * subdev.
+        * If the subdev doesn't implement pad-based stream enable, fall back
+        * to the .s_stream() operation.
         */
        if (!(sd->entity.pads[pad].flags & MEDIA_PAD_FL_SOURCE))
                return -EOPNOTSUPP;
 
-       for (i = 0; i < sd->entity.num_pads; ++i) {
-               if (i != pad && sd->entity.pads[i].flags & MEDIA_PAD_FL_SOURCE)
-                       return -EOPNOTSUPP;
-       }
+       /*
+        * .s_stream() means there is no streams support, so the only allowed
+        * stream is the implicit stream 0.
+        */
+       if (streams_mask != BIT_ULL(0))
+               return -EOPNOTSUPP;
+
+       /*
+        * We use a 64-bit bitmask for tracking enabled pads, so only subdevices
+        * with 64 pads or less can be supported.
+        */
+       if (pad >= sizeof(sd->enabled_pads) * BITS_PER_BYTE)
+               return -EOPNOTSUPP;
 
-       if ((sd->enabled_streams & streams_mask) != streams_mask) {
-               dev_dbg(dev, "set of streams %#llx already disabled on %s:%u\n",
-                       streams_mask, sd->entity.name, pad);
+       if (!(sd->enabled_pads & BIT_ULL(pad))) {
+               dev_dbg(dev, "pad %u already disabled on %s\n",
+                       pad, sd->entity.name);
                return -EALREADY;
        }
 
        /* Stop streaming when the last streams are disabled. */
-       if (!(sd->enabled_streams & ~streams_mask)) {
+       if (!(sd->enabled_pads & ~BIT_ULL(pad))) {
                ret = v4l2_subdev_call(sd, video, s_stream, 0);
                if (ret)
                        return ret;
        }
 
-       sd->enabled_streams &= ~streams_mask;
+       sd->enabled_pads &= ~BIT_ULL(pad);
 
        return 0;
 }
index ee570dfbd791daff2a120033a35063425ee222d8..0a8d75b009ea2cda3e790542763ff6be88d26de7 100644 (file)
@@ -1038,10 +1038,9 @@ struct v4l2_subdev_platform_data {
  * @active_state: Active state for the subdev (NULL for subdevs tracking the
  *               state internally). Initialized by calling
  *               v4l2_subdev_init_finalize().
- * @enabled_streams: Bitmask of enabled streams used by
- *                  v4l2_subdev_enable_streams() and
- *                  v4l2_subdev_disable_streams() helper functions for fallback
- *                  cases.
+ * @enabled_pads: Bitmask of enabled pads used by v4l2_subdev_enable_streams()
+ *               and v4l2_subdev_disable_streams() helper functions for
+ *               fallback cases.
  * @s_stream_enabled: Tracks whether streaming has been enabled with s_stream.
  *                    This is only for call_s_stream() internal use.
  *
@@ -1091,7 +1090,7 @@ struct v4l2_subdev {
         * doesn't support it.
         */
        struct v4l2_subdev_state *active_state;
-       u64 enabled_streams;
+       u64 enabled_pads;
        bool s_stream_enabled;
 };