Skip to content

Commit ffa51fe

Browse files
Sakari Ailusrkhuangtao
authored andcommitted
FROMLIST: v4l: async: Ensure only unique fwnodes are registered to notifiers
While registering a notifier, check that each newly added fwnode is unique, and return an error if it is not. Also check that a newly added notifier does not have the same fwnodes twice. Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com> (cherry picked from commit cbd39508810ec530137a0c631d16e8a772d315b8) https://git.linuxtv.org/sailus/media_tree.git/log/?h=010f7f4393fd http://www.spinics.net/lists/linux-media/msg122688.html Signed-off-by: Marc Herbert <marc.herbert@intel.com> BUG=b:64133998 TEST=media device topology shows subdevs registered successfully TEST=no camera regression Change-Id: I02fe494594780d57a7bd536d4132ed633069351c Reviewed-on: https://chromium-review.googlesource.com/693696 Commit-Ready: Tomasz Figa <tfiga@chromium.org> Tested-by: Hyungwoo Yang <hyungwoo.yang@intel.com> Reviewed-by: Tomasz Figa <tfiga@chromium.org> Signed-off-by: Jacob Chen <jacob2.chen@rock-chips.com>
1 parent 276604c commit ffa51fe

1 file changed

Lines changed: 80 additions & 10 deletions

File tree

drivers/media/v4l2-core/v4l2-async.c

Lines changed: 80 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -311,8 +311,71 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
311311
sd->dev = NULL;
312312
}
313313

314+
/* See if an fwnode can be found in a notifier's lists. */
315+
static bool __v4l2_async_notifier_fwnode_has_async_subdev(
316+
struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
317+
{
318+
struct v4l2_async_subdev *asd;
319+
struct v4l2_subdev *sd;
320+
321+
list_for_each_entry(asd, &notifier->waiting, list) {
322+
if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
323+
continue;
324+
325+
if (asd->match.fwnode.fwnode == fwnode)
326+
return true;
327+
}
328+
329+
list_for_each_entry(sd, &notifier->done, async_list) {
330+
if (WARN_ON(!sd->asd))
331+
continue;
332+
333+
if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
334+
continue;
335+
336+
if (sd->asd->match.fwnode.fwnode == fwnode)
337+
return true;
338+
}
339+
340+
return false;
341+
}
342+
343+
/*
344+
* Find out whether an async sub-device was set up for an fwnode already or
345+
* whether it exists in a given notifier before @this_index.
346+
*/
347+
static bool v4l2_async_notifier_fwnode_has_async_subdev(
348+
struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
349+
unsigned int this_index)
350+
{
351+
unsigned int j;
352+
353+
lockdep_assert_held(&list_lock);
354+
355+
/* Check that an fwnode is not being added more than once. */
356+
for (j = 0; j < this_index; j++) {
357+
struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
358+
struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
359+
360+
if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
361+
asd->match.fwnode.fwnode ==
362+
other_asd->match.fwnode.fwnode)
363+
return true;
364+
}
365+
366+
/* Check than an fwnode did not exist in other notifiers. */
367+
list_for_each_entry(notifier, &notifier_list, list)
368+
if (__v4l2_async_notifier_fwnode_has_async_subdev(
369+
notifier, fwnode))
370+
return true;
371+
372+
return false;
373+
}
374+
314375
static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
315376
{
377+
struct device *dev =
378+
notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
316379
struct v4l2_async_subdev *asd;
317380
int ret;
318381
int i;
@@ -333,40 +396,47 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
333396
return ret;
334397
}
335398

399+
mutex_lock(&list_lock);
400+
336401
for (i = 0; i < notifier->num_subdevs; i++) {
337402
asd = notifier->subdevs[i];
338403

339404
switch (asd->match_type) {
340405
case V4L2_ASYNC_MATCH_CUSTOM:
341406
case V4L2_ASYNC_MATCH_DEVNAME:
342407
case V4L2_ASYNC_MATCH_I2C:
408+
break;
343409
case V4L2_ASYNC_MATCH_FWNODE:
410+
if (v4l2_async_notifier_fwnode_has_async_subdev(
411+
notifier, asd->match.fwnode.fwnode, i)) {
412+
dev_err(dev,
413+
"fwnode has already been registered or in notifier's subdev list\n");
414+
ret = -EEXIST;
415+
goto out_unlock;
416+
}
344417
break;
345418
default:
346-
dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
347-
"Invalid match type %u on %p\n",
419+
dev_err(dev, "Invalid match type %u on %p\n",
348420
asd->match_type, asd);
349-
return -EINVAL;
421+
ret = -EINVAL;
422+
goto out_unlock;
350423
}
351424
list_add_tail(&asd->list, &notifier->waiting);
352425
}
353426

354-
mutex_lock(&list_lock);
355-
356427
ret = v4l2_async_notifier_try_all_subdevs(notifier);
357-
if (ret) {
358-
mutex_unlock(&list_lock);
359-
return ret;
360-
}
428+
if (ret)
429+
goto out_unlock;
361430

362431
ret = v4l2_async_notifier_try_complete(notifier);
363432

364433
/* Keep also completed notifiers on the list */
365434
list_add(&notifier->list, &notifier_list);
366435

436+
out_unlock:
367437
mutex_unlock(&list_lock);
368438

369-
return 0;
439+
return ret;
370440
}
371441

372442
int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,

0 commit comments

Comments
 (0)