Re: [PATCH 3/4] media: subdev: Improve v4l2_subdev_enable/disable_streams_fallback

Tomi Valkeinen
2024-04-04T12:38:51Z

On 04/04/2024 15:18, Sakari Ailus wrote:
> Moi,
>
> Thanks for the patch.
>
> 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.
>>
>> Signed-off-by: Tomi Valkeinen <tomi.valkeinen@ideasonboard.com>
>> ---
>> 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.
>> */
>> 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)
>
> 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.

Tomi

>
>> + 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)) {
>> + 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;
>> };
>>
>>
>