media: mc: Expand MUST_CONNECT flag to always require an enabled link

The MEDIA_PAD_FL_MUST_CONNECT flag indicates that the pad requires an
enabled link to stream, but only if it has any link at all. This makes
little sense, as if a pad is part of a pipeline, there are very few use
cases for an active link to be mandatory only if links exist at all. A
review of in-tree drivers confirms they all need an enabled link for
pads marked with the MEDIA_PAD_FL_MUST_CONNECT flag.

Expand the scope of the flag by rejecting pads that have no links at
all. This requires modifying the pipeline build code to add those pads
to the pipeline.

Cc: stable@vger.kernel.org # 6.1
Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Signed-off-by: Hans Verkuil <hverkuil-cisco@xs4all.nl>
This commit is contained in:
Laurent Pinchart 2024-01-15 01:04:52 +02:00 committed by Hans Verkuil
parent 9ec9109cf9
commit b3decc5ce7
2 changed files with 48 additions and 16 deletions

View File

@ -375,12 +375,11 @@ Types and flags used to represent the media graph elements
are origins of links.
* - ``MEDIA_PAD_FL_MUST_CONNECT``
- If this flag is set and the pad is linked to any other pad, then
at least one of those links must be enabled for the entity to be
able to stream. There could be temporary reasons (e.g. device
configuration dependent) for the pad to need enabled links even
when this flag isn't set; the absence of the flag doesn't imply
there is none.
- If this flag is set, then for this pad to be able to stream, it must
be connected by at least one enabled link. There could be temporary
reasons (e.g. device configuration dependent) for the pad to need
enabled links even when this flag isn't set; the absence of the flag
doesn't imply there is none.
One and only one of ``MEDIA_PAD_FL_SINK`` and ``MEDIA_PAD_FL_SOURCE``

View File

@ -535,14 +535,15 @@ static int media_pipeline_walk_push(struct media_pipeline_walk *walk,
/*
* Move the top entry link cursor to the next link. If all links of the entry
* have been visited, pop the entry itself.
* have been visited, pop the entry itself. Return true if the entry has been
* popped.
*/
static void media_pipeline_walk_pop(struct media_pipeline_walk *walk)
static bool media_pipeline_walk_pop(struct media_pipeline_walk *walk)
{
struct media_pipeline_walk_entry *entry;
if (WARN_ON(walk->stack.top < 0))
return;
return false;
entry = media_pipeline_walk_top(walk);
@ -552,7 +553,7 @@ static void media_pipeline_walk_pop(struct media_pipeline_walk *walk)
walk->stack.top);
walk->stack.top--;
return;
return true;
}
entry->links = entry->links->next;
@ -560,6 +561,8 @@ static void media_pipeline_walk_pop(struct media_pipeline_walk *walk)
dev_dbg(walk->mdev->dev,
"media pipeline: moved entry %u to next link\n",
walk->stack.top);
return false;
}
/* Free all memory allocated while walking the pipeline. */
@ -609,11 +612,12 @@ static int media_pipeline_explore_next_link(struct media_pipeline *pipe,
struct media_link *link;
struct media_pad *local;
struct media_pad *remote;
bool last_link;
int ret;
origin = entry->pad;
link = list_entry(entry->links, typeof(*link), list);
media_pipeline_walk_pop(walk);
last_link = media_pipeline_walk_pop(walk);
dev_dbg(walk->mdev->dev,
"media pipeline: exploring link '%s':%u -> '%s':%u\n",
@ -638,7 +642,7 @@ static int media_pipeline_explore_next_link(struct media_pipeline *pipe,
local->index)) {
dev_dbg(walk->mdev->dev,
"media pipeline: skipping link (no route)\n");
return 0;
goto done;
}
/*
@ -653,13 +657,44 @@ static int media_pipeline_explore_next_link(struct media_pipeline *pipe,
if (!(link->flags & MEDIA_LNK_FL_ENABLED)) {
dev_dbg(walk->mdev->dev,
"media pipeline: skipping link (disabled)\n");
return 0;
goto done;
}
ret = media_pipeline_add_pad(pipe, walk, remote);
if (ret)
return ret;
done:
/*
* If we're done iterating over links, iterate over pads of the entity.
* This is necessary to discover pads that are not connected with any
* link. Those are dead ends from a pipeline exploration point of view,
* but are still part of the pipeline and need to be added to enable
* proper validation.
*/
if (!last_link)
return 0;
dev_dbg(walk->mdev->dev,
"media pipeline: adding unconnected pads of '%s'\n",
local->entity->name);
media_entity_for_each_pad(origin->entity, local) {
/*
* Skip the origin pad (already handled), pad that have links
* (already discovered through iterating over links) and pads
* not internally connected.
*/
if (origin == local || !local->num_links ||
!media_entity_has_pad_interdep(origin->entity, origin->index,
local->index))
continue;
ret = media_pipeline_add_pad(pipe, walk, local);
if (ret)
return ret;
}
return 0;
}
@ -771,7 +806,6 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
struct media_pad *pad = ppad->pad;
struct media_entity *entity = pad->entity;
bool has_enabled_link = false;
bool has_link = false;
struct media_link *link;
dev_dbg(mdev->dev, "Validating pad '%s':%u\n", pad->entity->name,
@ -801,7 +835,6 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
/* Record if the pad has links and enabled links. */
if (link->flags & MEDIA_LNK_FL_ENABLED)
has_enabled_link = true;
has_link = true;
/*
* Validate the link if it's enabled and has the
@ -839,7 +872,7 @@ __must_check int __media_pipeline_start(struct media_pad *pad,
* 3. If the pad has the MEDIA_PAD_FL_MUST_CONNECT flag set,
* ensure that it has either no link or an enabled link.
*/
if ((pad->flags & MEDIA_PAD_FL_MUST_CONNECT) && has_link &&
if ((pad->flags & MEDIA_PAD_FL_MUST_CONNECT) &&
!has_enabled_link) {
dev_dbg(mdev->dev,
"Pad '%s':%u must be connected by an enabled link\n",