On Thu, Apr 04, 2024 at 03:38:45PM +0300, Tomi Valkeinen wrote: > On 04/04/2024 15:18, Sakari Ailus wrote: > > On Thu, Apr 04, 2024 at 01:50:02PM +0300, Tomi Valkeinen wrote: > >> 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 > >> soruce pad. s/soruce/source/ > >> > >> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@xxxxxxxxxxxxxxxx> > >> --- > >> drivers/media/v4l2-core/v4l2-subdev.c | 68 ++++++++++++++++++++--------------- > >> include/media/v4l2-subdev.h | 9 +++-- > >> 2 files changed, 44 insertions(+), 33 deletions(-) > >> > >> diff --git a/drivers/media/v4l2-core/v4l2-subdev.c b/drivers/media/v4l2-core/v4l2-subdev.c > >> index 3b3310bce5d4..91298bb84e6b 100644 > >> --- a/drivers/media/v4l2-core/v4l2-subdev.c > >> +++ b/drivers/media/v4l2-core/v4l2-subdev.c > >> @@ -2090,37 +2090,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. > >> + * on the .s_stream() operation. While at it, s/on/to/ Same below. > >> */ > >> 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 only allowed stream > >> + * is the imlicit stream 0. s/imlicit/implicit/ Same below. > >> + */ > >> + 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) * 8) > > > > s/8/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; > >> } > >> @@ -2207,37 +2213,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 > >> + * on 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 only allowed stream > >> + * is the imlicit 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) * 8) > > > > Ditto. > > > > How much of the code of the two functions is the same? Could some of this > > be put to a common function both would call? They look (almost) exactly the > > same. > > v4l2_subdev_enable_streams_fallback and v4l2_subdev_enable_streams? They > have similar parts, but I don't right away see how combining them or > making some common functions would help. You could move the three checks to a v4l2_subdev_streams_fallback_check() function (bikeshedding the name is allowed). > >> + 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)) != BIT_ULL(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; > >> } > >> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h > >> index 8bd1e3c96d2b..7077aec3176c 100644 > >> --- a/include/media/v4l2-subdev.h > >> +++ b/include/media/v4l2-subdev.h > >> @@ -1039,10 +1039,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. > >> * @streaming_enabled: Tracks whether streaming has been enabled with s_stream. > >> * > >> * Each instance of a subdev driver should create this struct, either > >> @@ -1091,7 +1090,7 @@ struct v4l2_subdev { > >> * doesn't support it. > >> */ > >> struct v4l2_subdev_state *active_state; > >> - u64 enabled_streams; > >> + u64 enabled_pads; > >> bool streaming_enabled; > >> }; > >> -- Regards, Laurent Pinchart