All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v16 00/32] Unified fwnode endpoint parser, async sub-device notifier support, N9 flash DTS
@ 2017-10-26  7:53 ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi folks,

	I've dropped the full set from devicetree and linux-acpi lists;
	let me know if you want it back. The entire set is posted to
	linux-media list.

We have a large influx of new, unmerged, drivers that are now parsing
fwnode endpoints and each one of them is doing this a little bit
differently. The needs are still exactly the same for the graph data
structure is device independent. This is still a non-trivial task and the
majority of the driver implementations are buggy, just buggy in different
ways.

Facilitate parsing endpoints by adding a convenience function for parsing
the endpoints, and make the omap3isp and rcar-vin drivers use them as an
example.

To show where we're getting with this, I've added support for async
sub-device notifier support that is notifiers that can be registered by
sub-device drivers as well as V4L2 fwnode improvements to make use of them
and the DTS changes for the Nokia N9. Some of these patches I've posted
previously in this set here:

<URL:http://www.spinics.net/lists/linux-media/msg118764.html>

Since that, the complete callback of the master notifier registering the
V4L2 device is only called once all sub-notifiers have been completed as
well. This way the device node creation can be postponed until all devices
have been successfully initialised.

With this, the as3645a driver successfully registers a sub-device to the
media device created by the omap3isp driver. The kernel also has the
information it's related to the sensor driven by the smiapp driver but we
don't have a way to expose that information yet.

The patches have a dependency to the as3645a driver fixes:

<URL:https://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git/log/?h=fixes-4.14-rc3>

since v15:

- Remove complete callback support from sub-device notifiers. There's no
  need for these now and likely we wish to get rid of the complete
  callback in the long run.

- Document fwnode argument and add examples and improved description
  v4l2_fwnode_reference_get_int_prop.

- Fix over 80 characters per line issue for
  v4l2_fwnode_reference_parse_int_props, as well as constify string
  arrays.

- Fix vep argument documentation for v4l2_fwnode_endpoint_free.

since v14:

- Patch "v4l: fwnode: Support generic parsing of graph endpoints in a
  device" depends on another patch "device property: preserve usecount for
  node passed to of_fwnode_graph_get_port_parent()". Add Depends-on tag.

- Add patch "v4l: async: fix unbind error in
  v4l2_async_notifier_unregister()" by Niklas. Effectively the notifier's
  unbind callback is called before v4l2_async_cleanup(), not after it.

- Fix complete callback error handling (patch "v4l: async: Fix notifier
  complete callback error handling").

- Rework error handling in in v4l2_async_match_notify() and add comments.
  No functional changes there.

- Don't assign sd->dev to NULL in v4l2_async_cleanup() (patch "v4l: async:
  Don't set sd->dev NULL in v4l2_async_cleanup").

- Introduce a function to unbind sub-devices from a notifier. This is a
  common operation so a common implementation is beneficial.

- Assign notifier's v4l2_dev (or sd for sub-device notifiers) NULL on
  failure.

- Make v4l2_async_notifier_unregister() safe to call with a NULL argument.

- Set the implicitly allocated sub-device notifier NULL on async
  sub-device unregistration (used to be a dangling pointer).

- Clean up async sub-device unregistration.

- Fix v4l2_fwnode_endpoint_free() comment to match KernelDoc style, i.e.
  make the function visible in documentation.

- Don't add a random newline near the end of v4l2_async.h.

- Move patch "v4l: fwnode: Move KernelDoc documentation to the header"
  later in the set. The five first patches should now address bugs in the
  V4L2 async framework, causing an oops on complete callback failure.

since v13:

- Add patch "v4l: fwnode: Add a convenience function for registering sensors"
  and make the sensor driver changes a lot smaller.

- Fix v4l2_async_notifier_parse_fwnode_endpoints() error handling for
  omap3isp.

- Return -ENODEV in rcar-vin if no async sub-device is available. I.e. fix
  a bug in previous versions of "rcar-vin: Use generic parser for parsing
  fwnode endpoints".

- Rework notifier completion in patch "v4l: async: Allow binding notifiers to
  sub-devices". This fixes calling complete notifiers more than once; they
  are now all called once when all async sub-devices in all related
  notifiers have been bound.

- Split the same patch ("v4l: async: Allow binding notifiers to
  sub-devices") into two, first one that prepares for async sub-devices
  and another that implements the bulk of support for sub-device notifiers.

- Postpone sub-device bound callback until v4l2_device is available in all
  cases. This also applies to the media device. The notifier's bound
  callback was in some cases called before having v4l2_device in v13.

- Prevent registering fwnodes as async sub-devices more than once.

- Use list_move instead of list_del and list_add in
  v4l2_async_notifier_unbind_all_subdevs.

- Call v4l2_async_notifier_release v4l2_async_notifier_cleanup instead.
  It's a cleanup function and does not release the object passed to it.

- In v4l2_async_notifier_fwnode_parse_endpoint, set match_type field with
  the fwnode.fwnode field, not later.

- In debug and other messages, use port@number/endpoint@number format.

- Call fwnode_handle_put() to release references obtained using e.g.
  fwnode_graph_get_port_parent.

- Multiple KernelDoc documentation fixes.

since v12:

- Merge patches "v4l: fwnode: Support generic parsing of graph endpoints
  in a device" and "v4l: fwnode: Support generic parsing of graph
  endpoints, per port". Improve the commit and KernelDoc documentation as
  well.

- Reformat loop conditions in v4l2_async_notifier_try_complete() and
  v4l2_fwnode_reference_get_int_prop(). Improve comments in
  fwnode_property_get_reference_args() return value handling. Also check
  for -ENODATA in v4l2_fwnode_reference_parse_int_props().

- Add an ACPI example for v4l2_fwnode_reference_get_int_prop().

- Document index parameter, document nprops parameter better and fix
  -EINVAL error code documentation for
  v4l2_fwnode_reference_get_int_prop().

- Use WARN_ON_ONCE(true) instead of WARN_ON_ONCE(1) in
  v4l2_async_notifier_release().

since v11:

- Add patch "et8ek8: Add support for flash and lens devices".

- Add patch "v4l: fwnode: Support generic parsing of graph endpoints, per
  port". The use case for this is to parse only upstream ports in a device
  with sources and sinks. The downstream ports have already been parsed by
  other drivers.

- Rename v4l2_fwnode_reference_parse_sensor_common as
  v4l2_async_notifier_parse_fwnode_sensor_common. This is in line with
  other functions that parse information using fwnode API and set up async
  sub-devices in the notifier.

since v10:

- Rename v4l2_async_get_subdev_notifier as
  v4l2_async_find_subdev_notifier, as this is what it effectively does:
  finds a notifier for a sub-device. Same for v4l2_async_notifier_get_v4l2_dev
  / v4l2_async_notifier_get_v4l2_dev.

- Initialise lists before calling v4l2_async_notifier_call_complete() if
  there are no sub-devices in a notifier.

- Warn on missing sub-device or existing v4l2_device on sub-device
  notifier register, and conversely missing v4l2_device or existing
  sub-device for a master notifier.

- Set notifier's sd and v4l2_dev fields NULL when the sub-device is
  unregistered.

- Document the newly added helper functions for parsing external
  references in v4l2-fwnode.c better.

- Return -ENOENT in v4l2_fwnode_reference_parse if no entries are found,
  and other errors as they occur.

- Turn the loop in v4l2_fwnode_reference_get_int_prop a while loop (was
  for).

- Don't put fwnodes in v4l2_fwnode_reference_parse_int_props.

- Fix description of parent field in struct v4l2_async_notifier.

- In the documentation of v4l2_async_notifier_release, document that this
  function must be called also after
  v4l2_fwnode_reference_parse_sensor_common, not just
  v4l2_async_notifier_parse_fwnode_endpoints. The same goes for
  v4l2_async_notifier_parse_fwnode_endpoints as well as
  v4l2_fwnode_reference_parse_sensor_common.

since v9:

- Drop "as3645a: Switch to fwnode property API" and "ACPI: Document how to
  refer to LEDs from remote nodes" patches. They're better off separately
  from this set.

- Address property documentation redundancy in smiapp DT binding
  documentation.

- Add patches "ov5670: Add support for flash and lens devices" and
  "ov13858: Add support for flash and lens devices".

since v8:

- Improve terminology for notifiers. Instead of master / subdev, we
  have root, parent and subdev notifiers.

- Renamed "flash" property as "flash-leds". There are many, and currently
  we make assumptions in a lot of places (e.g. LED bindings) that these
  are LEDs. While we don't have any other types of flashes supported right
  now (e.g. Xenon), it's safer to assume we might have them in the future.

- Use ENOTCONN instead of EPERM to tell from driver's callback function
  that an endpoint is to be skipped but not handled as an error.

- Avoid accessing notifier's subdevs array as well as num_subdevs field
  from rcar-vin driver.

- Add a patch "v4l: async: Allow async notifier register call succeed with no
  subdevs", which allows, well, what the subject says.

- Move checks for subdev / v4l2_dev from __v4l2_async_notifier_register()
  to v4l2_async_notifier_register() and
  v4l2_async_subdev_notifier_register().

- Don't initialise notifier->list. There was no need to do so, as this is
  the entry added to the list and not used otherwise. I.e. regarding this,
  the state before this patchset is restored.

- Clean up error handling in v4l2_async_notifier_fwnode_parse_endpoint().

- WARN_ON() in v4l2_async_notifier_parse_fwnode_endpoints() if the
  asd_struct_size is smaller than size of struct v4l2_async_subdev.

- Make v4l2_fwnode_reference_parse() static as there should be no need to
  use it outside the V4L2 fwnode framework. Also, remove the callback
  function as well as other arguments that always have the same value in
  current usage. (This can be changed later on if needed without affecting
  drivers.)

- Add the patch "v4l: fwnode: Add a helper function to obtain device /
  interger references", which allows similar use than
  v4l2_fwnode_reference_parse() but is more useful on ACPI based systems
  --- on ACPI, you can only refer to device nodes (corresponding struct
  deice in Linux), not to data extension nodes under the devices.

- Improve v4l2_fwnode_reference_parse_sensor_common() to work on ACPI
  based systems.

- Add patch "ACPI: Document how to refer to LEDs from remote nodes" to
  document using and referring to LEDs on ACPI.

- Rebase the set on AS3645A fixes I just sent ("AS3645A fixes")

- In v4l2_fwnode_reference_parse_sensor_common(), tell if parsing a
  property failed.

- Improved documentation for v4l2_async_notifier_parse_fwnode_endpoints().

- Fix v4l2_async_notifier_try_all_subdevs(); it is allowed that the list
  entry being iterated over is deleted but no other changes to the list
  are allowed. This could be the case if a sub-device driver's notifier
  binds a sub-device. Restart the loop whenever a match is found.

- Add patch "as3645a: Switch to fwnode property API" which also adds ACPI
  support.

since v7:

- Added three more patches:

	v4l: async: Remove re-probing support
	v4l: async: Use more intuitive names for internal functions
	dt: bindings: smiapp: Document lens-focus and flash properties

  The last one was already sent previously after the rest of the patchset.

- Removed re-probing support. This is hard to support and only useful in
  special cases. It can be reintroduced later on if there's really a need
  --- note that in e.g. omap3isp this was always broken and no-one ever
  complained.

- Remove smiapp driver's async complete callback (and ops). It is
  redundant: the sub-device nodes are created through the master notifier.

- Improve flash property documentation in video-interfaces.txt.

- Introduce helper functions to call notifier operations, one for each
  operation.

- Rename v4l2_async_test_notify as v4l2_async_match_notify and
  v4l2_async_belongs to v4l2_async_find_match.

- v4l2_async_notifier_test_all_subdevs() renamed as
  v4l2_async_notifier_try_all_subdevs().

- Made notifier_v4l2_dev a function (it was a macro).

- Registering subdev notifiers from sub-device drivers that control
  sub-devices created through sub-notifiers is now supported. In other
  words, subdev notifiers may be registered through other subdev
  notifiers. This is the source of the bulk of the changes between v7 and
  v8.

- Add explanatory comments to helper functions used by V4L2 async
  framework. This should help understanding the internal workings of the
  framework.

- Removed the "notifiers" list in struct v4l2_async_notifier. The
  information can be found from existing data structures.

- Explicitly check that registering a non-subdev notifier has v4l2_dev and
  a subdev notifier has a sub-device pointer.

- Unified several code paths between subdev notifiers and non-subdev
  notifiers.

- Fixed v4l2_async_notifier_release() --- calling it on a notifier for
  which the driver had allocated the subdevs array would lead calling
  kvfree() on that array. Now notifier->max_subdevs is checked before
  proceeding.

- Fixed a use-after-free issue in
  v4l2_async_notifier_fwnode_parse_endpoints().

- Small fixes to KernelDoc documentation for
  v4l2_async_notifier_parse_fwnode_endpoints().

since v6:

- Drop the last patch that added variant for parsing endpoints given
  specific port and endpoints numbers.

- Separate driver changes from the fwnode endpoint parser patch into two
  patches. rcar-vin driver is now using the name function.

- Use -ENOTCONN to tell the parser that and endpoint (or a reference) is
  to be ignored.

- parse_endpoint and parse_single callback functions are now optional and
  documented as such.

- Added Laurent's patch adding notifier operations struct which I rebase
  on the fwnode parser patchset. I wrote another patch to call the
  notifier operations through macros.

- Add DT bindings for flash and lens devices.

- V4L2 fwnode parser for references (such as flash and lens).

- Added smiapp driver support for async sub-devices (lens and flash).

- Added a few fixes for omap3isp.

since v5:

- Use v4l2_async_ prefix for static functions as well (4th patch)

- Use memcpy() to copy array rather than a loop

- Document that the v4l2_async_subdev pointer in driver specific struct
  must be the first member

- Improve documentation of the added functions (4th and 5th
  patches)

	- Arguments

	- More thorough explation of the purpose, usage and object
	  lifetime

- Added acks

since v4:

- Prepend the set with three documentation fixes.

- The driver's async struct must begin with struct v4l2_async_subdev. Fix this
  for omap3isp and document it.

- Improve documentation for new functions.

- Don't use devm_ family of functions for allocating memory. Introduce
  v4l2_async_notifier_release() to release memory resources.

- Rework both v4l2_async_notifier_fwnode_parse_endpoints() and
  v4l2_async_notifier_fwnode_parse_endpoint() and the local functions they
  call. This should make the code cleaner. Despite the name, for linking
  and typical usage reasons the functions remain in v4l2-fwnode.c.

- Convert rcar-vin to use v4l2_async_notifier_fwnode_parse_endpoint().

- Use kvmalloc() for allocating the notifier's subdevs array.

- max_subdevs argument for notifier_realloc is now the total maximum
  number of subdevs, not the number of available subdevs.

- Use fwnode_device_is_available() to make sure the device actually
  exists.

- Move the note telling v4l2_async_notifier_fwnode_parse_endpoints()
  should not be used by new drivers to the last patch adding
  v4l2_async_notifier_fwnode_parse_endpoint().

since v3:

- Rebase on current mediatree master.

since v2:

- Rebase on CCP2 support patches.

- Prepend a patch cleaning up omap3isp driver a little.

since v1:

- The first patch has been merged (it was a bugfix).

- In anticipation that the parsing can take place over several iterations,
  take the existing number of async sub-devices into account when
  re-allocating an array of async sub-devices.

- Rework the first patch to better anticipate parsing single endpoint at a
  time by a driver.

- Add a second patch that adds a function for parsing endpoints one at a
  time based on port and endpoint numbers.

Laurent Pinchart (1):
  v4l: async: Move async subdev notifier operations to a separate
    structure

Niklas Söderlund (1):
  v4l: async: fix unbind error in v4l2_async_notifier_unregister()

Sakari Ailus (30):
  v4l: async: Remove re-probing support
  v4l: async: Don't set sd->dev NULL in v4l2_async_cleanup
  v4l: async: Fix notifier complete callback error handling
  v4l: async: Correctly serialise async sub-device unregistration
  v4l: async: Use more intuitive names for internal functions
  v4l: async: Add V4L2 async documentation to the documentation build
  v4l: fwnode: Support generic parsing of graph endpoints in a device
  omap3isp: Use generic parser for parsing fwnode endpoints
  rcar-vin: Use generic parser for parsing fwnode endpoints
  omap3isp: Fix check for our own sub-devices
  omap3isp: Print the name of the entity where no source pads could be
    found
  v4l: async: Introduce helpers for calling async ops callbacks
  v4l: async: Register sub-devices before calling bound callback
  v4l: async: Allow async notifier register call succeed with no subdevs
  v4l: async: Prepare for async sub-device notifiers
  v4l: async: Allow binding notifiers to sub-devices
  v4l: async: Ensure only unique fwnodes are registered to notifiers
  dt: bindings: Add a binding for flash LED devices associated to a
    sensor
  dt: bindings: Add lens-focus binding for image sensors
  v4l: fwnode: Move KernelDoc documentation to the header
  v4l: fwnode: Add a helper function for parsing generic references
  v4l: fwnode: Add a helper function to obtain device / integer
    references
  v4l: fwnode: Add convenience function for parsing common external refs
  v4l: fwnode: Add a convenience function for registering sensors
  dt: bindings: smiapp: Document lens-focus and flash-leds properties
  smiapp: Add support for flash and lens devices
  et8ek8: Add support for flash and lens devices
  ov5670: Add support for flash and lens devices
  ov13858: Add support for flash and lens devices
  arm: dts: omap3: N9/N950: Add flash references to the camera

 .../devicetree/bindings/media/i2c/nokia,smia.txt   |   2 +
 .../devicetree/bindings/media/video-interfaces.txt |  10 +
 Documentation/media/kapi/v4l2-async.rst            |   3 +
 Documentation/media/kapi/v4l2-core.rst             |   1 +
 arch/arm/boot/dts/omap3-n9.dts                     |   1 +
 arch/arm/boot/dts/omap3-n950-n9.dtsi               |   4 +-
 arch/arm/boot/dts/omap3-n950.dts                   |   1 +
 drivers/media/i2c/et8ek8/et8ek8_driver.c           |   2 +-
 drivers/media/i2c/ov13858.c                        |   2 +-
 drivers/media/i2c/ov5670.c                         |   2 +-
 drivers/media/i2c/smiapp/smiapp-core.c             |   2 +-
 drivers/media/platform/am437x/am437x-vpfe.c        |   8 +-
 drivers/media/platform/atmel/atmel-isc.c           |  10 +-
 drivers/media/platform/atmel/atmel-isi.c           |  10 +-
 drivers/media/platform/davinci/vpif_capture.c      |   8 +-
 drivers/media/platform/davinci/vpif_display.c      |   8 +-
 drivers/media/platform/exynos4-is/media-dev.c      |   8 +-
 drivers/media/platform/omap3isp/isp.c              | 133 ++--
 drivers/media/platform/omap3isp/isp.h              |   5 +-
 drivers/media/platform/pxa_camera.c                |   8 +-
 drivers/media/platform/qcom/camss-8x16/camss.c     |   8 +-
 drivers/media/platform/rcar-vin/rcar-core.c        | 117 ++--
 drivers/media/platform/rcar-vin/rcar-dma.c         |  10 +-
 drivers/media/platform/rcar-vin/rcar-v4l2.c        |  14 +-
 drivers/media/platform/rcar-vin/rcar-vin.h         |   4 +-
 drivers/media/platform/rcar_drif.c                 |  10 +-
 drivers/media/platform/soc_camera/soc_camera.c     |  14 +-
 drivers/media/platform/stm32/stm32-dcmi.c          |  10 +-
 drivers/media/platform/ti-vpe/cal.c                |   8 +-
 drivers/media/platform/xilinx/xilinx-vipp.c        |   8 +-
 drivers/media/v4l2-core/v4l2-async.c               | 517 +++++++++++----
 drivers/media/v4l2-core/v4l2-fwnode.c              | 703 ++++++++++++++++++---
 drivers/staging/media/imx/imx-media-dev.c          |   8 +-
 include/media/v4l2-async.h                         |  91 ++-
 include/media/v4l2-fwnode.h                        | 220 ++++++-
 include/media/v4l2-subdev.h                        |   3 +
 36 files changed, 1548 insertions(+), 425 deletions(-)
 create mode 100644 Documentation/media/kapi/v4l2-async.rst

-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* [PATCH v16 00/32] Unified fwnode endpoint parser, async sub-device notifier support, N9 flash DTS
@ 2017-10-26  7:53 ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Hi folks,

	I've dropped the full set from devicetree and linux-acpi lists;
	let me know if you want it back. The entire set is posted to
	linux-media list.

We have a large influx of new, unmerged, drivers that are now parsing
fwnode endpoints and each one of them is doing this a little bit
differently. The needs are still exactly the same for the graph data
structure is device independent. This is still a non-trivial task and the
majority of the driver implementations are buggy, just buggy in different
ways.

Facilitate parsing endpoints by adding a convenience function for parsing
the endpoints, and make the omap3isp and rcar-vin drivers use them as an
example.

To show where we're getting with this, I've added support for async
sub-device notifier support that is notifiers that can be registered by
sub-device drivers as well as V4L2 fwnode improvements to make use of them
and the DTS changes for the Nokia N9. Some of these patches I've posted
previously in this set here:

<URL:http://www.spinics.net/lists/linux-media/msg118764.html>

Since that, the complete callback of the master notifier registering the
V4L2 device is only called once all sub-notifiers have been completed as
well. This way the device node creation can be postponed until all devices
have been successfully initialised.

With this, the as3645a driver successfully registers a sub-device to the
media device created by the omap3isp driver. The kernel also has the
information it's related to the sensor driven by the smiapp driver but we
don't have a way to expose that information yet.

The patches have a dependency to the as3645a driver fixes:

<URL:https://git.kernel.org/pub/scm/linux/kernel/git/j.anaszewski/linux-leds.git/log/?h=fixes-4.14-rc3>

since v15:

- Remove complete callback support from sub-device notifiers. There's no
  need for these now and likely we wish to get rid of the complete
  callback in the long run.

- Document fwnode argument and add examples and improved description
  v4l2_fwnode_reference_get_int_prop.

- Fix over 80 characters per line issue for
  v4l2_fwnode_reference_parse_int_props, as well as constify string
  arrays.

- Fix vep argument documentation for v4l2_fwnode_endpoint_free.

since v14:

- Patch "v4l: fwnode: Support generic parsing of graph endpoints in a
  device" depends on another patch "device property: preserve usecount for
  node passed to of_fwnode_graph_get_port_parent()". Add Depends-on tag.

- Add patch "v4l: async: fix unbind error in
  v4l2_async_notifier_unregister()" by Niklas. Effectively the notifier's
  unbind callback is called before v4l2_async_cleanup(), not after it.

- Fix complete callback error handling (patch "v4l: async: Fix notifier
  complete callback error handling").

- Rework error handling in in v4l2_async_match_notify() and add comments.
  No functional changes there.

- Don't assign sd->dev to NULL in v4l2_async_cleanup() (patch "v4l: async:
  Don't set sd->dev NULL in v4l2_async_cleanup").

- Introduce a function to unbind sub-devices from a notifier. This is a
  common operation so a common implementation is beneficial.

- Assign notifier's v4l2_dev (or sd for sub-device notifiers) NULL on
  failure.

- Make v4l2_async_notifier_unregister() safe to call with a NULL argument.

- Set the implicitly allocated sub-device notifier NULL on async
  sub-device unregistration (used to be a dangling pointer).

- Clean up async sub-device unregistration.

- Fix v4l2_fwnode_endpoint_free() comment to match KernelDoc style, i.e.
  make the function visible in documentation.

- Don't add a random newline near the end of v4l2_async.h.

- Move patch "v4l: fwnode: Move KernelDoc documentation to the header"
  later in the set. The five first patches should now address bugs in the
  V4L2 async framework, causing an oops on complete callback failure.

since v13:

- Add patch "v4l: fwnode: Add a convenience function for registering sensors"
  and make the sensor driver changes a lot smaller.

- Fix v4l2_async_notifier_parse_fwnode_endpoints() error handling for
  omap3isp.

- Return -ENODEV in rcar-vin if no async sub-device is available. I.e. fix
  a bug in previous versions of "rcar-vin: Use generic parser for parsing
  fwnode endpoints".

- Rework notifier completion in patch "v4l: async: Allow binding notifiers to
  sub-devices". This fixes calling complete notifiers more than once; they
  are now all called once when all async sub-devices in all related
  notifiers have been bound.

- Split the same patch ("v4l: async: Allow binding notifiers to
  sub-devices") into two, first one that prepares for async sub-devices
  and another that implements the bulk of support for sub-device notifiers.

- Postpone sub-device bound callback until v4l2_device is available in all
  cases. This also applies to the media device. The notifier's bound
  callback was in some cases called before having v4l2_device in v13.

- Prevent registering fwnodes as async sub-devices more than once.

- Use list_move instead of list_del and list_add in
  v4l2_async_notifier_unbind_all_subdevs.

- Call v4l2_async_notifier_release v4l2_async_notifier_cleanup instead.
  It's a cleanup function and does not release the object passed to it.

- In v4l2_async_notifier_fwnode_parse_endpoint, set match_type field with
  the fwnode.fwnode field, not later.

- In debug and other messages, use port@number/endpoint@number format.

- Call fwnode_handle_put() to release references obtained using e.g.
  fwnode_graph_get_port_parent.

- Multiple KernelDoc documentation fixes.

since v12:

- Merge patches "v4l: fwnode: Support generic parsing of graph endpoints
  in a device" and "v4l: fwnode: Support generic parsing of graph
  endpoints, per port". Improve the commit and KernelDoc documentation as
  well.

- Reformat loop conditions in v4l2_async_notifier_try_complete() and
  v4l2_fwnode_reference_get_int_prop(). Improve comments in
  fwnode_property_get_reference_args() return value handling. Also check
  for -ENODATA in v4l2_fwnode_reference_parse_int_props().

- Add an ACPI example for v4l2_fwnode_reference_get_int_prop().

- Document index parameter, document nprops parameter better and fix
  -EINVAL error code documentation for
  v4l2_fwnode_reference_get_int_prop().

- Use WARN_ON_ONCE(true) instead of WARN_ON_ONCE(1) in
  v4l2_async_notifier_release().

since v11:

- Add patch "et8ek8: Add support for flash and lens devices".

- Add patch "v4l: fwnode: Support generic parsing of graph endpoints, per
  port". The use case for this is to parse only upstream ports in a device
  with sources and sinks. The downstream ports have already been parsed by
  other drivers.

- Rename v4l2_fwnode_reference_parse_sensor_common as
  v4l2_async_notifier_parse_fwnode_sensor_common. This is in line with
  other functions that parse information using fwnode API and set up async
  sub-devices in the notifier.

since v10:

- Rename v4l2_async_get_subdev_notifier as
  v4l2_async_find_subdev_notifier, as this is what it effectively does:
  finds a notifier for a sub-device. Same for v4l2_async_notifier_get_v4l2_dev
  / v4l2_async_notifier_get_v4l2_dev.

- Initialise lists before calling v4l2_async_notifier_call_complete() if
  there are no sub-devices in a notifier.

- Warn on missing sub-device or existing v4l2_device on sub-device
  notifier register, and conversely missing v4l2_device or existing
  sub-device for a master notifier.

- Set notifier's sd and v4l2_dev fields NULL when the sub-device is
  unregistered.

- Document the newly added helper functions for parsing external
  references in v4l2-fwnode.c better.

- Return -ENOENT in v4l2_fwnode_reference_parse if no entries are found,
  and other errors as they occur.

- Turn the loop in v4l2_fwnode_reference_get_int_prop a while loop (was
  for).

- Don't put fwnodes in v4l2_fwnode_reference_parse_int_props.

- Fix description of parent field in struct v4l2_async_notifier.

- In the documentation of v4l2_async_notifier_release, document that this
  function must be called also after
  v4l2_fwnode_reference_parse_sensor_common, not just
  v4l2_async_notifier_parse_fwnode_endpoints. The same goes for
  v4l2_async_notifier_parse_fwnode_endpoints as well as
  v4l2_fwnode_reference_parse_sensor_common.

since v9:

- Drop "as3645a: Switch to fwnode property API" and "ACPI: Document how to
  refer to LEDs from remote nodes" patches. They're better off separately
  from this set.

- Address property documentation redundancy in smiapp DT binding
  documentation.

- Add patches "ov5670: Add support for flash and lens devices" and
  "ov13858: Add support for flash and lens devices".

since v8:

- Improve terminology for notifiers. Instead of master / subdev, we
  have root, parent and subdev notifiers.

- Renamed "flash" property as "flash-leds". There are many, and currently
  we make assumptions in a lot of places (e.g. LED bindings) that these
  are LEDs. While we don't have any other types of flashes supported right
  now (e.g. Xenon), it's safer to assume we might have them in the future.

- Use ENOTCONN instead of EPERM to tell from driver's callback function
  that an endpoint is to be skipped but not handled as an error.

- Avoid accessing notifier's subdevs array as well as num_subdevs field
  from rcar-vin driver.

- Add a patch "v4l: async: Allow async notifier register call succeed with no
  subdevs", which allows, well, what the subject says.

- Move checks for subdev / v4l2_dev from __v4l2_async_notifier_register()
  to v4l2_async_notifier_register() and
  v4l2_async_subdev_notifier_register().

- Don't initialise notifier->list. There was no need to do so, as this is
  the entry added to the list and not used otherwise. I.e. regarding this,
  the state before this patchset is restored.

- Clean up error handling in v4l2_async_notifier_fwnode_parse_endpoint().

- WARN_ON() in v4l2_async_notifier_parse_fwnode_endpoints() if the
  asd_struct_size is smaller than size of struct v4l2_async_subdev.

- Make v4l2_fwnode_reference_parse() static as there should be no need to
  use it outside the V4L2 fwnode framework. Also, remove the callback
  function as well as other arguments that always have the same value in
  current usage. (This can be changed later on if needed without affecting
  drivers.)

- Add the patch "v4l: fwnode: Add a helper function to obtain device /
  interger references", which allows similar use than
  v4l2_fwnode_reference_parse() but is more useful on ACPI based systems
  --- on ACPI, you can only refer to device nodes (corresponding struct
  deice in Linux), not to data extension nodes under the devices.

- Improve v4l2_fwnode_reference_parse_sensor_common() to work on ACPI
  based systems.

- Add patch "ACPI: Document how to refer to LEDs from remote nodes" to
  document using and referring to LEDs on ACPI.

- Rebase the set on AS3645A fixes I just sent ("AS3645A fixes")

- In v4l2_fwnode_reference_parse_sensor_common(), tell if parsing a
  property failed.

- Improved documentation for v4l2_async_notifier_parse_fwnode_endpoints().

- Fix v4l2_async_notifier_try_all_subdevs(); it is allowed that the list
  entry being iterated over is deleted but no other changes to the list
  are allowed. This could be the case if a sub-device driver's notifier
  binds a sub-device. Restart the loop whenever a match is found.

- Add patch "as3645a: Switch to fwnode property API" which also adds ACPI
  support.

since v7:

- Added three more patches:

	v4l: async: Remove re-probing support
	v4l: async: Use more intuitive names for internal functions
	dt: bindings: smiapp: Document lens-focus and flash properties

  The last one was already sent previously after the rest of the patchset.

- Removed re-probing support. This is hard to support and only useful in
  special cases. It can be reintroduced later on if there's really a need
  --- note that in e.g. omap3isp this was always broken and no-one ever
  complained.

- Remove smiapp driver's async complete callback (and ops). It is
  redundant: the sub-device nodes are created through the master notifier.

- Improve flash property documentation in video-interfaces.txt.

- Introduce helper functions to call notifier operations, one for each
  operation.

- Rename v4l2_async_test_notify as v4l2_async_match_notify and
  v4l2_async_belongs to v4l2_async_find_match.

- v4l2_async_notifier_test_all_subdevs() renamed as
  v4l2_async_notifier_try_all_subdevs().

- Made notifier_v4l2_dev a function (it was a macro).

- Registering subdev notifiers from sub-device drivers that control
  sub-devices created through sub-notifiers is now supported. In other
  words, subdev notifiers may be registered through other subdev
  notifiers. This is the source of the bulk of the changes between v7 and
  v8.

- Add explanatory comments to helper functions used by V4L2 async
  framework. This should help understanding the internal workings of the
  framework.

- Removed the "notifiers" list in struct v4l2_async_notifier. The
  information can be found from existing data structures.

- Explicitly check that registering a non-subdev notifier has v4l2_dev and
  a subdev notifier has a sub-device pointer.

- Unified several code paths between subdev notifiers and non-subdev
  notifiers.

- Fixed v4l2_async_notifier_release() --- calling it on a notifier for
  which the driver had allocated the subdevs array would lead calling
  kvfree() on that array. Now notifier->max_subdevs is checked before
  proceeding.

- Fixed a use-after-free issue in
  v4l2_async_notifier_fwnode_parse_endpoints().

- Small fixes to KernelDoc documentation for
  v4l2_async_notifier_parse_fwnode_endpoints().

since v6:

- Drop the last patch that added variant for parsing endpoints given
  specific port and endpoints numbers.

- Separate driver changes from the fwnode endpoint parser patch into two
  patches. rcar-vin driver is now using the name function.

- Use -ENOTCONN to tell the parser that and endpoint (or a reference) is
  to be ignored.

- parse_endpoint and parse_single callback functions are now optional and
  documented as such.

- Added Laurent's patch adding notifier operations struct which I rebase
  on the fwnode parser patchset. I wrote another patch to call the
  notifier operations through macros.

- Add DT bindings for flash and lens devices.

- V4L2 fwnode parser for references (such as flash and lens).

- Added smiapp driver support for async sub-devices (lens and flash).

- Added a few fixes for omap3isp.

since v5:

- Use v4l2_async_ prefix for static functions as well (4th patch)

- Use memcpy() to copy array rather than a loop

- Document that the v4l2_async_subdev pointer in driver specific struct
  must be the first member

- Improve documentation of the added functions (4th and 5th
  patches)

	- Arguments

	- More thorough explation of the purpose, usage and object
	  lifetime

- Added acks

since v4:

- Prepend the set with three documentation fixes.

- The driver's async struct must begin with struct v4l2_async_subdev. Fix this
  for omap3isp and document it.

- Improve documentation for new functions.

- Don't use devm_ family of functions for allocating memory. Introduce
  v4l2_async_notifier_release() to release memory resources.

- Rework both v4l2_async_notifier_fwnode_parse_endpoints() and
  v4l2_async_notifier_fwnode_parse_endpoint() and the local functions they
  call. This should make the code cleaner. Despite the name, for linking
  and typical usage reasons the functions remain in v4l2-fwnode.c.

- Convert rcar-vin to use v4l2_async_notifier_fwnode_parse_endpoint().

- Use kvmalloc() for allocating the notifier's subdevs array.

- max_subdevs argument for notifier_realloc is now the total maximum
  number of subdevs, not the number of available subdevs.

- Use fwnode_device_is_available() to make sure the device actually
  exists.

- Move the note telling v4l2_async_notifier_fwnode_parse_endpoints()
  should not be used by new drivers to the last patch adding
  v4l2_async_notifier_fwnode_parse_endpoint().

since v3:

- Rebase on current mediatree master.

since v2:

- Rebase on CCP2 support patches.

- Prepend a patch cleaning up omap3isp driver a little.

since v1:

- The first patch has been merged (it was a bugfix).

- In anticipation that the parsing can take place over several iterations,
  take the existing number of async sub-devices into account when
  re-allocating an array of async sub-devices.

- Rework the first patch to better anticipate parsing single endpoint at a
  time by a driver.

- Add a second patch that adds a function for parsing endpoints one at a
  time based on port and endpoint numbers.

Laurent Pinchart (1):
  v4l: async: Move async subdev notifier operations to a separate
    structure

Niklas Söderlund (1):
  v4l: async: fix unbind error in v4l2_async_notifier_unregister()

Sakari Ailus (30):
  v4l: async: Remove re-probing support
  v4l: async: Don't set sd->dev NULL in v4l2_async_cleanup
  v4l: async: Fix notifier complete callback error handling
  v4l: async: Correctly serialise async sub-device unregistration
  v4l: async: Use more intuitive names for internal functions
  v4l: async: Add V4L2 async documentation to the documentation build
  v4l: fwnode: Support generic parsing of graph endpoints in a device
  omap3isp: Use generic parser for parsing fwnode endpoints
  rcar-vin: Use generic parser for parsing fwnode endpoints
  omap3isp: Fix check for our own sub-devices
  omap3isp: Print the name of the entity where no source pads could be
    found
  v4l: async: Introduce helpers for calling async ops callbacks
  v4l: async: Register sub-devices before calling bound callback
  v4l: async: Allow async notifier register call succeed with no subdevs
  v4l: async: Prepare for async sub-device notifiers
  v4l: async: Allow binding notifiers to sub-devices
  v4l: async: Ensure only unique fwnodes are registered to notifiers
  dt: bindings: Add a binding for flash LED devices associated to a
    sensor
  dt: bindings: Add lens-focus binding for image sensors
  v4l: fwnode: Move KernelDoc documentation to the header
  v4l: fwnode: Add a helper function for parsing generic references
  v4l: fwnode: Add a helper function to obtain device / integer
    references
  v4l: fwnode: Add convenience function for parsing common external refs
  v4l: fwnode: Add a convenience function for registering sensors
  dt: bindings: smiapp: Document lens-focus and flash-leds properties
  smiapp: Add support for flash and lens devices
  et8ek8: Add support for flash and lens devices
  ov5670: Add support for flash and lens devices
  ov13858: Add support for flash and lens devices
  arm: dts: omap3: N9/N950: Add flash references to the camera

 .../devicetree/bindings/media/i2c/nokia,smia.txt   |   2 +
 .../devicetree/bindings/media/video-interfaces.txt |  10 +
 Documentation/media/kapi/v4l2-async.rst            |   3 +
 Documentation/media/kapi/v4l2-core.rst             |   1 +
 arch/arm/boot/dts/omap3-n9.dts                     |   1 +
 arch/arm/boot/dts/omap3-n950-n9.dtsi               |   4 +-
 arch/arm/boot/dts/omap3-n950.dts                   |   1 +
 drivers/media/i2c/et8ek8/et8ek8_driver.c           |   2 +-
 drivers/media/i2c/ov13858.c                        |   2 +-
 drivers/media/i2c/ov5670.c                         |   2 +-
 drivers/media/i2c/smiapp/smiapp-core.c             |   2 +-
 drivers/media/platform/am437x/am437x-vpfe.c        |   8 +-
 drivers/media/platform/atmel/atmel-isc.c           |  10 +-
 drivers/media/platform/atmel/atmel-isi.c           |  10 +-
 drivers/media/platform/davinci/vpif_capture.c      |   8 +-
 drivers/media/platform/davinci/vpif_display.c      |   8 +-
 drivers/media/platform/exynos4-is/media-dev.c      |   8 +-
 drivers/media/platform/omap3isp/isp.c              | 133 ++--
 drivers/media/platform/omap3isp/isp.h              |   5 +-
 drivers/media/platform/pxa_camera.c                |   8 +-
 drivers/media/platform/qcom/camss-8x16/camss.c     |   8 +-
 drivers/media/platform/rcar-vin/rcar-core.c        | 117 ++--
 drivers/media/platform/rcar-vin/rcar-dma.c         |  10 +-
 drivers/media/platform/rcar-vin/rcar-v4l2.c        |  14 +-
 drivers/media/platform/rcar-vin/rcar-vin.h         |   4 +-
 drivers/media/platform/rcar_drif.c                 |  10 +-
 drivers/media/platform/soc_camera/soc_camera.c     |  14 +-
 drivers/media/platform/stm32/stm32-dcmi.c          |  10 +-
 drivers/media/platform/ti-vpe/cal.c                |   8 +-
 drivers/media/platform/xilinx/xilinx-vipp.c        |   8 +-
 drivers/media/v4l2-core/v4l2-async.c               | 517 +++++++++++----
 drivers/media/v4l2-core/v4l2-fwnode.c              | 703 ++++++++++++++++++---
 drivers/staging/media/imx/imx-media-dev.c          |   8 +-
 include/media/v4l2-async.h                         |  91 ++-
 include/media/v4l2-fwnode.h                        | 220 ++++++-
 include/media/v4l2-subdev.h                        |   3 +
 36 files changed, 1548 insertions(+), 425 deletions(-)
 create mode 100644 Documentation/media/kapi/v4l2-async.rst

-- 
2.11.0

^ permalink raw reply	[flat|nested] 107+ messages in thread

* [PATCH v16 01/32] v4l: async: Remove re-probing support
  2017-10-26  7:53 ` Sakari Ailus
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-26 15:20   ` Niklas Söderlund
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Remove V4L2 async re-probing support. The re-probing support has been
there to support cases where the sub-devices require resources provided by
the main driver's hardware to function, such as clocks.

Reprobing has allowed unbinding and again binding the main driver without
explicitly unbinding the sub-device drivers. This is certainly not a
common need, and the responsibility will be the user's going forward.

An alternative could have been to introduce notifier specific locks.
Considering the complexity of the re-probing and that it isn't really a
solution to a problem but a workaround, remove re-probing instead.

If there is a need to support the clock provider unregister/register cycle
while keeping the clock references in the consumers in the future, this
should be implemented in the clock framework instead, not in V4L2.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
---
 drivers/media/v4l2-core/v4l2-async.c | 54 +-----------------------------------
 1 file changed, 1 insertion(+), 53 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index d741a8e0fdac..60a1a50b9537 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -198,78 +198,26 @@ EXPORT_SYMBOL(v4l2_async_notifier_register);
 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_subdev *sd, *tmp;
-	unsigned int notif_n_subdev = notifier->num_subdevs;
-	unsigned int n_subdev = min(notif_n_subdev, V4L2_MAX_SUBDEVS);
-	struct device **dev;
-	int i = 0;
 
 	if (!notifier->v4l2_dev)
 		return;
 
-	dev = kvmalloc_array(n_subdev, sizeof(*dev), GFP_KERNEL);
-	if (!dev) {
-		dev_err(notifier->v4l2_dev->dev,
-			"Failed to allocate device cache!\n");
-	}
-
 	mutex_lock(&list_lock);
 
 	list_del(&notifier->list);
 
 	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
-		struct device *d;
-
-		d = get_device(sd->dev);
-
 		v4l2_async_cleanup(sd);
 
-		/* If we handled USB devices, we'd have to lock the parent too */
-		device_release_driver(d);
-
 		if (notifier->unbind)
 			notifier->unbind(notifier, sd, sd->asd);
 
-		/*
-		 * Store device at the device cache, in order to call
-		 * put_device() on the final step
-		 */
-		if (dev)
-			dev[i++] = d;
-		else
-			put_device(d);
+		list_move(&sd->async_list, &subdev_list);
 	}
 
 	mutex_unlock(&list_lock);
 
-	/*
-	 * Call device_attach() to reprobe devices
-	 *
-	 * NOTE: If dev allocation fails, i is 0, and the whole loop won't be
-	 * executed.
-	 */
-	while (i--) {
-		struct device *d = dev[i];
-
-		if (d && device_attach(d) < 0) {
-			const char *name = "(none)";
-			int lock = device_trylock(d);
-
-			if (lock && d->driver)
-				name = d->driver->name;
-			dev_err(d, "Failed to re-probe to %s\n", name);
-			if (lock)
-				device_unlock(d);
-		}
-		put_device(d);
-	}
-	kvfree(dev);
-
 	notifier->v4l2_dev = NULL;
-
-	/*
-	 * Don't care about the waiting list, it is initialised and populated
-	 * upon notifier registration.
-	 */
 }
 EXPORT_SYMBOL(v4l2_async_notifier_unregister);
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 02/32] v4l: async: Don't set sd->dev NULL in v4l2_async_cleanup
  2017-10-26  7:53 ` Sakari Ailus
  (?)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
       [not found]   ` <20171026075342.5760-3-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

v4l2_async_cleanup() is called when the async sub-device is unbound from
the media device. As the pointer is set by the driver registering the
async sub-device, leave the pointer as set by the driver.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 1 -
 1 file changed, 1 deletion(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 60a1a50b9537..21c748bf3a7b 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -134,7 +134,6 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 	/* Subdevice driver will reprobe and put the subdev back onto the list */
 	list_del_init(&sd->async_list);
 	sd->asd = NULL;
-	sd->dev = NULL;
 }
 
 int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 03/32] v4l: async: fix unbind error in v4l2_async_notifier_unregister()
  2017-10-26  7:53 ` Sakari Ailus
                   ` (2 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree, Niklas Söderlund

From: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

The call to v4l2_async_cleanup() will set sd->asd to NULL so passing it to
notifier->unbind() has no effect and leaves the notifier confused. Call
the unbind() callback prior to cleaning up the subdevice to avoid this.

Signed-off-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 21c748bf3a7b..ca281438a0ae 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -206,11 +206,11 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 	list_del(&notifier->list);
 
 	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
-		v4l2_async_cleanup(sd);
-
 		if (notifier->unbind)
 			notifier->unbind(notifier, sd, sd->asd);
 
+		v4l2_async_cleanup(sd);
+
 		list_move(&sd->async_list, &subdev_list);
 	}
 
@@ -268,11 +268,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 
 	list_add(&sd->asd->list, &notifier->waiting);
 
-	v4l2_async_cleanup(sd);
-
 	if (notifier->unbind)
 		notifier->unbind(notifier, sd, sd->asd);
 
+	v4l2_async_cleanup(sd);
+
 	mutex_unlock(&list_lock);
 }
 EXPORT_SYMBOL(v4l2_async_unregister_subdev);
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 04/32] v4l: async: Fix notifier complete callback error handling
  2017-10-26  7:53 ` Sakari Ailus
@ 2017-10-26  7:53     ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

The notifier complete callback may return an error. This error code was
simply returned to the caller but never handled properly.

Move calling the complete callback function to the caller from
v4l2_async_test_notify and undo the work that was done either in async
sub-device or async notifier registration.

Reported-by: Russell King <rmk+kernel-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org>
Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
---
 drivers/media/v4l2-core/v4l2-async.c | 78 +++++++++++++++++++++++++++---------
 1 file changed, 60 insertions(+), 18 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index ca281438a0ae..4924481451ca 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -122,9 +122,6 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
 	/* Move from the global subdevice list to notifier's done */
 	list_move(&sd->async_list, &notifier->done);
 
-	if (list_empty(&notifier->waiting) && notifier->complete)
-		return notifier->complete(notifier);
-
 	return 0;
 }
 
@@ -136,11 +133,27 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 	sd->asd = NULL;
 }
 
+static void v4l2_async_notifier_unbind_all_subdevs(
+	struct v4l2_async_notifier *notifier)
+{
+	struct v4l2_subdev *sd, *tmp;
+
+	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
+		if (notifier->unbind)
+			notifier->unbind(notifier, sd, sd->asd);
+
+		v4l2_async_cleanup(sd);
+
+		list_move(&sd->async_list, &subdev_list);
+	}
+}
+
 int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 				 struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_subdev *sd, *tmp;
 	struct v4l2_async_subdev *asd;
+	int ret;
 	int i;
 
 	if (!v4l2_dev || !notifier->num_subdevs ||
@@ -185,19 +198,30 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 		}
 	}
 
+	if (list_empty(&notifier->waiting) && notifier->complete) {
+		ret = notifier->complete(notifier);
+		if (ret)
+			goto err_complete;
+	}
+
 	/* Keep also completed notifiers on the list */
 	list_add(&notifier->list, &notifier_list);
 
 	mutex_unlock(&list_lock);
 
 	return 0;
+
+err_complete:
+	v4l2_async_notifier_unbind_all_subdevs(notifier);
+
+	mutex_unlock(&list_lock);
+
+	return ret;
 }
 EXPORT_SYMBOL(v4l2_async_notifier_register);
 
 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 {
-	struct v4l2_subdev *sd, *tmp;
-
 	if (!notifier->v4l2_dev)
 		return;
 
@@ -205,14 +229,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 
 	list_del(&notifier->list);
 
-	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
-		if (notifier->unbind)
-			notifier->unbind(notifier, sd, sd->asd);
-
-		v4l2_async_cleanup(sd);
-
-		list_move(&sd->async_list, &subdev_list);
-	}
+	v4l2_async_notifier_unbind_all_subdevs(notifier);
 
 	mutex_unlock(&list_lock);
 
@@ -223,6 +240,7 @@ EXPORT_SYMBOL(v4l2_async_notifier_unregister);
 int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 {
 	struct v4l2_async_notifier *notifier;
+	int ret;
 
 	/*
 	 * No reference taken. The reference is held by the device
@@ -238,19 +256,43 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 
 	list_for_each_entry(notifier, &notifier_list, list) {
 		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
-		if (asd) {
-			int ret = v4l2_async_test_notify(notifier, sd, asd);
-			mutex_unlock(&list_lock);
-			return ret;
-		}
+		int ret;
+
+		if (!asd)
+			continue;
+
+		ret = v4l2_async_test_notify(notifier, sd, asd);
+		if (ret)
+			goto err_unlock;
+
+		if (!list_empty(&notifier->waiting) || !notifier->complete)
+			goto out_unlock;
+
+		ret = notifier->complete(notifier);
+		if (ret)
+			goto err_cleanup;
+
+		goto out_unlock;
 	}
 
 	/* None matched, wait for hot-plugging */
 	list_add(&sd->async_list, &subdev_list);
 
+out_unlock:
 	mutex_unlock(&list_lock);
 
 	return 0;
+
+err_cleanup:
+	if (notifier->unbind)
+		notifier->unbind(notifier, sd, sd->asd);
+
+	v4l2_async_cleanup(sd);
+
+err_unlock:
+	mutex_unlock(&list_lock);
+
+	return ret;
 }
 EXPORT_SYMBOL(v4l2_async_register_subdev);
 
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 04/32] v4l: async: Fix notifier complete callback error handling
@ 2017-10-26  7:53     ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

The notifier complete callback may return an error. This error code was
simply returned to the caller but never handled properly.

Move calling the complete callback function to the caller from
v4l2_async_test_notify and undo the work that was done either in async
sub-device or async notifier registration.

Reported-by: Russell King <rmk+kernel@armlinux.org.uk>
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 78 +++++++++++++++++++++++++++---------
 1 file changed, 60 insertions(+), 18 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index ca281438a0ae..4924481451ca 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -122,9 +122,6 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
 	/* Move from the global subdevice list to notifier's done */
 	list_move(&sd->async_list, &notifier->done);
 
-	if (list_empty(&notifier->waiting) && notifier->complete)
-		return notifier->complete(notifier);
-
 	return 0;
 }
 
@@ -136,11 +133,27 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 	sd->asd = NULL;
 }
 
+static void v4l2_async_notifier_unbind_all_subdevs(
+	struct v4l2_async_notifier *notifier)
+{
+	struct v4l2_subdev *sd, *tmp;
+
+	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
+		if (notifier->unbind)
+			notifier->unbind(notifier, sd, sd->asd);
+
+		v4l2_async_cleanup(sd);
+
+		list_move(&sd->async_list, &subdev_list);
+	}
+}
+
 int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 				 struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_subdev *sd, *tmp;
 	struct v4l2_async_subdev *asd;
+	int ret;
 	int i;
 
 	if (!v4l2_dev || !notifier->num_subdevs ||
@@ -185,19 +198,30 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 		}
 	}
 
+	if (list_empty(&notifier->waiting) && notifier->complete) {
+		ret = notifier->complete(notifier);
+		if (ret)
+			goto err_complete;
+	}
+
 	/* Keep also completed notifiers on the list */
 	list_add(&notifier->list, &notifier_list);
 
 	mutex_unlock(&list_lock);
 
 	return 0;
+
+err_complete:
+	v4l2_async_notifier_unbind_all_subdevs(notifier);
+
+	mutex_unlock(&list_lock);
+
+	return ret;
 }
 EXPORT_SYMBOL(v4l2_async_notifier_register);
 
 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 {
-	struct v4l2_subdev *sd, *tmp;
-
 	if (!notifier->v4l2_dev)
 		return;
 
@@ -205,14 +229,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 
 	list_del(&notifier->list);
 
-	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
-		if (notifier->unbind)
-			notifier->unbind(notifier, sd, sd->asd);
-
-		v4l2_async_cleanup(sd);
-
-		list_move(&sd->async_list, &subdev_list);
-	}
+	v4l2_async_notifier_unbind_all_subdevs(notifier);
 
 	mutex_unlock(&list_lock);
 
@@ -223,6 +240,7 @@ EXPORT_SYMBOL(v4l2_async_notifier_unregister);
 int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 {
 	struct v4l2_async_notifier *notifier;
+	int ret;
 
 	/*
 	 * No reference taken. The reference is held by the device
@@ -238,19 +256,43 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 
 	list_for_each_entry(notifier, &notifier_list, list) {
 		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
-		if (asd) {
-			int ret = v4l2_async_test_notify(notifier, sd, asd);
-			mutex_unlock(&list_lock);
-			return ret;
-		}
+		int ret;
+
+		if (!asd)
+			continue;
+
+		ret = v4l2_async_test_notify(notifier, sd, asd);
+		if (ret)
+			goto err_unlock;
+
+		if (!list_empty(&notifier->waiting) || !notifier->complete)
+			goto out_unlock;
+
+		ret = notifier->complete(notifier);
+		if (ret)
+			goto err_cleanup;
+
+		goto out_unlock;
 	}
 
 	/* None matched, wait for hot-plugging */
 	list_add(&sd->async_list, &subdev_list);
 
+out_unlock:
 	mutex_unlock(&list_lock);
 
 	return 0;
+
+err_cleanup:
+	if (notifier->unbind)
+		notifier->unbind(notifier, sd, sd->asd);
+
+	v4l2_async_cleanup(sd);
+
+err_unlock:
+	mutex_unlock(&list_lock);
+
+	return ret;
 }
 EXPORT_SYMBOL(v4l2_async_register_subdev);
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 05/32] v4l: async: Correctly serialise async sub-device unregistration
  2017-10-26  7:53 ` Sakari Ailus
                   ` (3 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
       [not found]   ` <20171026075342.5760-6-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

The check whether an async sub-device is bound to a notifier was performed
without list_lock held, making it possible for another process to
unbind the async sub-device before the sub-device unregistration function
proceeds to take the lock.

Fix this by first acquiring the lock and then proceeding with the check.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 18 +++++++-----------
 1 file changed, 7 insertions(+), 11 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 4924481451ca..cde2cf2ab4b0 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -298,20 +298,16 @@ EXPORT_SYMBOL(v4l2_async_register_subdev);
 
 void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 {
-	struct v4l2_async_notifier *notifier = sd->notifier;
-
-	if (!sd->asd) {
-		if (!list_empty(&sd->async_list))
-			v4l2_async_cleanup(sd);
-		return;
-	}
-
 	mutex_lock(&list_lock);
 
-	list_add(&sd->asd->list, &notifier->waiting);
+	if (sd->asd) {
+		struct v4l2_async_notifier *notifier = sd->notifier;
 
-	if (notifier->unbind)
-		notifier->unbind(notifier, sd, sd->asd);
+		list_add(&sd->asd->list, &notifier->waiting);
+
+		if (notifier->unbind)
+			notifier->unbind(notifier, sd, sd->asd);
+	}
 
 	v4l2_async_cleanup(sd);
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 06/32] v4l: async: Use more intuitive names for internal functions
  2017-10-26  7:53 ` Sakari Ailus
@ 2017-10-26  7:53     ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Rename internal functions to make the names of the functions better
describe what they do.

	Old name			New name
	v4l2_async_test_notify	v4l2_async_match_notify
	v4l2_async_belongs	v4l2_async_find_match

Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
Reviewed-by: Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
---
 drivers/media/v4l2-core/v4l2-async.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index cde2cf2ab4b0..8b84fea50c2a 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -60,8 +60,8 @@ static LIST_HEAD(subdev_list);
 static LIST_HEAD(notifier_list);
 static DEFINE_MUTEX(list_lock);
 
-static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
-						    struct v4l2_subdev *sd)
+static struct v4l2_async_subdev *v4l2_async_find_match(
+	struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd)
 {
 	bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *);
 	struct v4l2_async_subdev *asd;
@@ -95,9 +95,9 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *
 	return NULL;
 }
 
-static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
-				  struct v4l2_subdev *sd,
-				  struct v4l2_async_subdev *asd)
+static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
+				   struct v4l2_subdev *sd,
+				   struct v4l2_async_subdev *asd)
 {
 	int ret;
 
@@ -187,11 +187,11 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
 		int ret;
 
-		asd = v4l2_async_belongs(notifier, sd);
+		asd = v4l2_async_find_match(notifier, sd);
 		if (!asd)
 			continue;
 
-		ret = v4l2_async_test_notify(notifier, sd, asd);
+		ret = v4l2_async_match_notify(notifier, sd, asd);
 		if (ret < 0) {
 			mutex_unlock(&list_lock);
 			return ret;
@@ -255,13 +255,14 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 	INIT_LIST_HEAD(&sd->async_list);
 
 	list_for_each_entry(notifier, &notifier_list, list) {
-		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
+		struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
+								      sd);
 		int ret;
 
 		if (!asd)
 			continue;
 
-		ret = v4l2_async_test_notify(notifier, sd, asd);
+		ret = v4l2_async_match_notify(notifier, sd, asd);
 		if (ret)
 			goto err_unlock;
 
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 06/32] v4l: async: Use more intuitive names for internal functions
@ 2017-10-26  7:53     ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Rename internal functions to make the names of the functions better
describe what they do.

	Old name			New name
	v4l2_async_test_notify	v4l2_async_match_notify
	v4l2_async_belongs	v4l2_async_find_match

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
---
 drivers/media/v4l2-core/v4l2-async.c | 19 ++++++++++---------
 1 file changed, 10 insertions(+), 9 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index cde2cf2ab4b0..8b84fea50c2a 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -60,8 +60,8 @@ static LIST_HEAD(subdev_list);
 static LIST_HEAD(notifier_list);
 static DEFINE_MUTEX(list_lock);
 
-static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
-						    struct v4l2_subdev *sd)
+static struct v4l2_async_subdev *v4l2_async_find_match(
+	struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd)
 {
 	bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *);
 	struct v4l2_async_subdev *asd;
@@ -95,9 +95,9 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *
 	return NULL;
 }
 
-static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
-				  struct v4l2_subdev *sd,
-				  struct v4l2_async_subdev *asd)
+static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
+				   struct v4l2_subdev *sd,
+				   struct v4l2_async_subdev *asd)
 {
 	int ret;
 
@@ -187,11 +187,11 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
 		int ret;
 
-		asd = v4l2_async_belongs(notifier, sd);
+		asd = v4l2_async_find_match(notifier, sd);
 		if (!asd)
 			continue;
 
-		ret = v4l2_async_test_notify(notifier, sd, asd);
+		ret = v4l2_async_match_notify(notifier, sd, asd);
 		if (ret < 0) {
 			mutex_unlock(&list_lock);
 			return ret;
@@ -255,13 +255,14 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 	INIT_LIST_HEAD(&sd->async_list);
 
 	list_for_each_entry(notifier, &notifier_list, list) {
-		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
+		struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
+								      sd);
 		int ret;
 
 		if (!asd)
 			continue;
 
-		ret = v4l2_async_test_notify(notifier, sd, asd);
+		ret = v4l2_async_match_notify(notifier, sd, asd);
 		if (ret)
 			goto err_unlock;
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 07/32] v4l: async: Add V4L2 async documentation to the documentation build
  2017-10-26  7:53 ` Sakari Ailus
                   ` (4 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

The V4L2 async wasn't part of the documentation build. Fix this.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
---
 Documentation/media/kapi/v4l2-async.rst | 3 +++
 Documentation/media/kapi/v4l2-core.rst  | 1 +
 2 files changed, 4 insertions(+)
 create mode 100644 Documentation/media/kapi/v4l2-async.rst

diff --git a/Documentation/media/kapi/v4l2-async.rst b/Documentation/media/kapi/v4l2-async.rst
new file mode 100644
index 000000000000..523ff9eb09a0
--- /dev/null
+++ b/Documentation/media/kapi/v4l2-async.rst
@@ -0,0 +1,3 @@
+V4L2 async kAPI
+^^^^^^^^^^^^^^^
+.. kernel-doc:: include/media/v4l2-async.h
diff --git a/Documentation/media/kapi/v4l2-core.rst b/Documentation/media/kapi/v4l2-core.rst
index c7434f38fd9c..5cf292037a48 100644
--- a/Documentation/media/kapi/v4l2-core.rst
+++ b/Documentation/media/kapi/v4l2-core.rst
@@ -19,6 +19,7 @@ Video4Linux devices
     v4l2-mc
     v4l2-mediabus
     v4l2-mem2mem
+    v4l2-async
     v4l2-fwnode
     v4l2-rect
     v4l2-tuner
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 08/32] v4l: fwnode: Support generic parsing of graph endpoints in a device
  2017-10-26  7:53 ` Sakari Ailus
                   ` (5 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-26 21:35   ` Niklas Söderlund
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Add two functions for parsing devices graph endpoints:
v4l2_async_notifier_parse_fwnode_endpoints and
v4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates
over all endpoints whereas the latter only iterates over the endpoints in
a given port.

The former is mostly useful for existing drivers that currently implement
the iteration over all the endpoints themselves whereas the latter is
especially intended for devices with both sinks and sources: async
sub-devices for external devices connected to the device's sources will
have already been set up, or the external sub-devices are part of the
master device.

Depends-on: ("device property: preserve usecount for node passed to of_fwnode_graph_get_port_parent()")
Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c  |  31 ++++++
 drivers/media/v4l2-core/v4l2-fwnode.c | 196 ++++++++++++++++++++++++++++++++++
 include/media/v4l2-async.h            |  24 ++++-
 include/media/v4l2-fwnode.h           | 118 ++++++++++++++++++++
 4 files changed, 367 insertions(+), 2 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 8b84fea50c2a..46aebfc75e43 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -22,6 +22,7 @@
 
 #include <media/v4l2-async.h>
 #include <media/v4l2-device.h>
+#include <media/v4l2-fwnode.h>
 #include <media/v4l2-subdev.h>
 
 static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
@@ -237,6 +238,36 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 }
 EXPORT_SYMBOL(v4l2_async_notifier_unregister);
 
+void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
+{
+	unsigned int i;
+
+	if (!notifier->max_subdevs)
+		return;
+
+	for (i = 0; i < notifier->num_subdevs; i++) {
+		struct v4l2_async_subdev *asd = notifier->subdevs[i];
+
+		switch (asd->match_type) {
+		case V4L2_ASYNC_MATCH_FWNODE:
+			fwnode_handle_put(asd->match.fwnode.fwnode);
+			break;
+		default:
+			WARN_ON_ONCE(true);
+			break;
+		}
+
+		kfree(asd);
+	}
+
+	notifier->max_subdevs = 0;
+	notifier->num_subdevs = 0;
+
+	kvfree(notifier->subdevs);
+	notifier->subdevs = NULL;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
+
 int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 {
 	struct v4l2_async_notifier *notifier;
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 40b2fbfe8865..df0695b7bbcc 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -19,6 +19,7 @@
  */
 #include <linux/acpi.h>
 #include <linux/kernel.h>
+#include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/of.h>
 #include <linux/property.h>
@@ -26,6 +27,7 @@
 #include <linux/string.h>
 #include <linux/types.h>
 
+#include <media/v4l2-async.h>
 #include <media/v4l2-fwnode.h>
 
 enum v4l2_fwnode_bus_type {
@@ -388,6 +390,200 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
 
+static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
+				       unsigned int max_subdevs)
+{
+	struct v4l2_async_subdev **subdevs;
+
+	if (max_subdevs <= notifier->max_subdevs)
+		return 0;
+
+	subdevs = kvmalloc_array(
+		max_subdevs, sizeof(*notifier->subdevs),
+		GFP_KERNEL | __GFP_ZERO);
+	if (!subdevs)
+		return -ENOMEM;
+
+	if (notifier->subdevs) {
+		memcpy(subdevs, notifier->subdevs,
+		       sizeof(*subdevs) * notifier->num_subdevs);
+
+		kvfree(notifier->subdevs);
+	}
+
+	notifier->subdevs = subdevs;
+	notifier->max_subdevs = max_subdevs;
+
+	return 0;
+}
+
+static int v4l2_async_notifier_fwnode_parse_endpoint(
+	struct device *dev, struct v4l2_async_notifier *notifier,
+	struct fwnode_handle *endpoint, unsigned int asd_struct_size,
+	int (*parse_endpoint)(struct device *dev,
+			    struct v4l2_fwnode_endpoint *vep,
+			    struct v4l2_async_subdev *asd))
+{
+	struct v4l2_async_subdev *asd;
+	struct v4l2_fwnode_endpoint *vep;
+	int ret = 0;
+
+	asd = kzalloc(asd_struct_size, GFP_KERNEL);
+	if (!asd)
+		return -ENOMEM;
+
+	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+	asd->match.fwnode.fwnode =
+		fwnode_graph_get_remote_port_parent(endpoint);
+	if (!asd->match.fwnode.fwnode) {
+		dev_warn(dev, "bad remote port parent\n");
+		ret = -EINVAL;
+		goto out_err;
+	}
+
+	vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
+	if (IS_ERR(vep)) {
+		ret = PTR_ERR(vep);
+		dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
+			 ret);
+		goto out_err;
+	}
+
+	ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
+	if (ret == -ENOTCONN)
+		dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep->base.port,
+			vep->base.id);
+	else if (ret < 0)
+		dev_warn(dev,
+			 "driver could not parse port@%u/endpoint@%u (%d)\n",
+			 vep->base.port, vep->base.id, ret);
+	v4l2_fwnode_endpoint_free(vep);
+	if (ret < 0)
+		goto out_err;
+
+	notifier->subdevs[notifier->num_subdevs] = asd;
+	notifier->num_subdevs++;
+
+	return 0;
+
+out_err:
+	fwnode_handle_put(asd->match.fwnode.fwnode);
+	kfree(asd);
+
+	return ret == -ENOTCONN ? 0 : ret;
+}
+
+static int __v4l2_async_notifier_parse_fwnode_endpoints(
+	struct device *dev, struct v4l2_async_notifier *notifier,
+	size_t asd_struct_size, unsigned int port, bool has_port,
+	int (*parse_endpoint)(struct device *dev,
+			    struct v4l2_fwnode_endpoint *vep,
+			    struct v4l2_async_subdev *asd))
+{
+	struct fwnode_handle *fwnode;
+	unsigned int max_subdevs = notifier->max_subdevs;
+	int ret;
+
+	if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
+		return -EINVAL;
+
+	for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
+				     dev_fwnode(dev), fwnode)); ) {
+		struct fwnode_handle *dev_fwnode;
+		bool is_available;
+
+		dev_fwnode = fwnode_graph_get_port_parent(fwnode);
+		is_available = fwnode_device_is_available(dev_fwnode);
+		fwnode_handle_put(dev_fwnode);
+		if (!is_available)
+			continue;
+
+		if (has_port) {
+			struct fwnode_endpoint ep;
+
+			ret = fwnode_graph_parse_endpoint(fwnode, &ep);
+			if (ret) {
+				fwnode_handle_put(fwnode);
+				return ret;
+			}
+
+			if (ep.port != port)
+				continue;
+		}
+		max_subdevs++;
+	}
+
+	/* No subdevs to add? Return here. */
+	if (max_subdevs == notifier->max_subdevs)
+		return 0;
+
+	ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
+	if (ret)
+		return ret;
+
+	for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
+				     dev_fwnode(dev), fwnode)); ) {
+		struct fwnode_handle *dev_fwnode;
+		bool is_available;
+
+		dev_fwnode = fwnode_graph_get_port_parent(fwnode);
+		is_available = fwnode_device_is_available(dev_fwnode);
+		fwnode_handle_put(dev_fwnode);
+
+		if (!fwnode_device_is_available(dev_fwnode))
+			continue;
+
+		if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
+			ret = -EINVAL;
+			break;
+		}
+
+		if (has_port) {
+			struct fwnode_endpoint ep;
+
+			ret = fwnode_graph_parse_endpoint(fwnode, &ep);
+			if (ret)
+				break;
+
+			if (ep.port != port)
+				continue;
+		}
+
+		ret = v4l2_async_notifier_fwnode_parse_endpoint(
+			dev, notifier, fwnode, asd_struct_size, parse_endpoint);
+		if (ret < 0)
+			break;
+	}
+
+	fwnode_handle_put(fwnode);
+
+	return ret;
+}
+
+int v4l2_async_notifier_parse_fwnode_endpoints(
+	struct device *dev, struct v4l2_async_notifier *notifier,
+	size_t asd_struct_size,
+	int (*parse_endpoint)(struct device *dev,
+			    struct v4l2_fwnode_endpoint *vep,
+			    struct v4l2_async_subdev *asd))
+{
+	return __v4l2_async_notifier_parse_fwnode_endpoints(
+		dev, notifier, asd_struct_size, 0, false, parse_endpoint);
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
+
+int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
+	struct device *dev, struct v4l2_async_notifier *notifier,
+	size_t asd_struct_size, unsigned int port,
+	int (*parse_endpoint)(struct device *dev,
+			    struct v4l2_fwnode_endpoint *vep,
+			    struct v4l2_async_subdev *asd))
+{
+	return __v4l2_async_notifier_parse_fwnode_endpoints(
+		dev, notifier, asd_struct_size, port, true, parse_endpoint);
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index c69d8c8a66d0..329aeebd1a80 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -18,7 +18,6 @@ struct device;
 struct device_node;
 struct v4l2_device;
 struct v4l2_subdev;
-struct v4l2_async_notifier;
 
 /* A random max subdevice number, used to allocate an array on stack */
 #define V4L2_MAX_SUBDEVS 128U
@@ -50,6 +49,10 @@ enum v4l2_async_match_type {
  * @match:	union of per-bus type matching data sets
  * @list:	used to link struct v4l2_async_subdev objects, waiting to be
  *		probed, to a notifier->waiting list
+ *
+ * When this struct is used as a member in a driver specific struct,
+ * the driver specific struct shall contain the &struct
+ * v4l2_async_subdev as its first member.
  */
 struct v4l2_async_subdev {
 	enum v4l2_async_match_type match_type;
@@ -78,7 +81,8 @@ struct v4l2_async_subdev {
 /**
  * struct v4l2_async_notifier - v4l2_device notifier data
  *
- * @num_subdevs: number of subdevices
+ * @num_subdevs: number of subdevices used in the subdevs array
+ * @max_subdevs: number of subdevices allocated in the subdevs array
  * @subdevs:	array of pointers to subdevice descriptors
  * @v4l2_dev:	pointer to struct v4l2_device
  * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
@@ -90,6 +94,7 @@ struct v4l2_async_subdev {
  */
 struct v4l2_async_notifier {
 	unsigned int num_subdevs;
+	unsigned int max_subdevs;
 	struct v4l2_async_subdev **subdevs;
 	struct v4l2_device *v4l2_dev;
 	struct list_head waiting;
@@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
 
 /**
+ * v4l2_async_notifier_cleanup - clean up notifier resources
+ * @notifier: the notifier the resources of which are to be cleaned up
+ *
+ * Release memory resources related to a notifier, including the async
+ * sub-devices allocated for the purposes of the notifier but not the notifier
+ * itself. The user is responsible for calling this function to clean up the
+ * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints.
+ *
+ * There is no harm from calling v4l2_async_notifier_cleanup in other
+ * cases as long as its memory has been zeroed after it has been
+ * allocated.
+ */
+void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier);
+
+/**
  * v4l2_async_register_subdev - registers a sub-device to the asynchronous
  * 	subdevice framework
  *
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 7adec9851d9e..ac605af9b877 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -25,6 +25,8 @@
 #include <media/v4l2-mediabus.h>
 
 struct fwnode_handle;
+struct v4l2_async_notifier;
+struct v4l2_async_subdev;
 
 #define V4L2_FWNODE_CSI2_MAX_DATA_LANES	4
 
@@ -122,4 +124,120 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
 			   struct v4l2_fwnode_link *link);
 void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
 
+/**
+ * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
+ *						device node
+ * @dev: the device the endpoints of which are to be parsed
+ * @notifier: notifier for @dev
+ * @asd_struct_size: size of the driver's async sub-device struct, including
+ *		     sizeof(struct v4l2_async_subdev). The &struct
+ *		     v4l2_async_subdev shall be the first member of
+ *		     the driver's async sub-device struct, i.e. both
+ *		     begin at the same memory address.
+ * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
+ *		    endpoint. Optional.
+ *		    Return: %0 on success
+ *			    %-ENOTCONN if the endpoint is to be skipped but this
+ *				       should not be considered as an error
+ *			    %-EINVAL if the endpoint configuration is invalid
+ *
+ * Parse the fwnode endpoints of the @dev device and populate the async sub-
+ * devices array of the notifier. The @parse_endpoint callback function is
+ * called for each endpoint with the corresponding async sub-device pointer to
+ * let the caller initialize the driver-specific part of the async sub-device
+ * structure.
+ *
+ * The notifier memory shall be zeroed before this function is called on the
+ * notifier.
+ *
+ * This function may not be called on a registered notifier and may be called on
+ * a notifier only once.
+ *
+ * Do not change the notifier's subdevs array, take references to the subdevs
+ * array itself or change the notifier's num_subdevs field. This is because this
+ * function allocates and reallocates the subdevs array based on parsing
+ * endpoints.
+ *
+ * The &struct v4l2_fwnode_endpoint passed to the callback function
+ * @parse_endpoint is released once the function is finished. If there is a need
+ * to retain that configuration, the user needs to allocate memory for it.
+ *
+ * Any notifier populated using this function must be released with a call to
+ * v4l2_async_notifier_cleanup() after it has been unregistered and the async
+ * sub-devices are no longer in use, even if the function returned an error.
+ *
+ * Return: %0 on success, including when no async sub-devices are found
+ *	   %-ENOMEM if memory allocation failed
+ *	   %-EINVAL if graph or endpoint parsing failed
+ *	   Other error codes as returned by @parse_endpoint
+ */
+int v4l2_async_notifier_parse_fwnode_endpoints(
+	struct device *dev, struct v4l2_async_notifier *notifier,
+	size_t asd_struct_size,
+	int (*parse_endpoint)(struct device *dev,
+			      struct v4l2_fwnode_endpoint *vep,
+			      struct v4l2_async_subdev *asd));
+
+/**
+ * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode
+ *							endpoints of a port in a
+ *							device node
+ * @dev: the device the endpoints of which are to be parsed
+ * @notifier: notifier for @dev
+ * @asd_struct_size: size of the driver's async sub-device struct, including
+ *		     sizeof(struct v4l2_async_subdev). The &struct
+ *		     v4l2_async_subdev shall be the first member of
+ *		     the driver's async sub-device struct, i.e. both
+ *		     begin at the same memory address.
+ * @port: port number where endpoints are to be parsed
+ * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
+ *		    endpoint. Optional.
+ *		    Return: %0 on success
+ *			    %-ENOTCONN if the endpoint is to be skipped but this
+ *				       should not be considered as an error
+ *			    %-EINVAL if the endpoint configuration is invalid
+ *
+ * This function is just like v4l2_async_notifier_parse_fwnode_endpoints() with
+ * the exception that it only parses endpoints in a given port. This is useful
+ * on devices that have both sinks and sources: the async sub-devices connected
+ * to sources have already been configured by another driver (on capture
+ * devices). In this case the driver must know which ports to parse.
+ *
+ * Parse the fwnode endpoints of the @dev device on a given @port and populate
+ * the async sub-devices array of the notifier. The @parse_endpoint callback
+ * function is called for each endpoint with the corresponding async sub-device
+ * pointer to let the caller initialize the driver-specific part of the async
+ * sub-device structure.
+ *
+ * The notifier memory shall be zeroed before this function is called on the
+ * notifier the first time.
+ *
+ * This function may not be called on a registered notifier and may be called on
+ * a notifier only once per port.
+ *
+ * Do not change the notifier's subdevs array, take references to the subdevs
+ * array itself or change the notifier's num_subdevs field. This is because this
+ * function allocates and reallocates the subdevs array based on parsing
+ * endpoints.
+ *
+ * The &struct v4l2_fwnode_endpoint passed to the callback function
+ * @parse_endpoint is released once the function is finished. If there is a need
+ * to retain that configuration, the user needs to allocate memory for it.
+ *
+ * Any notifier populated using this function must be released with a call to
+ * v4l2_async_notifier_cleanup() after it has been unregistered and the async
+ * sub-devices are no longer in use, even if the function returned an error.
+ *
+ * Return: %0 on success, including when no async sub-devices are found
+ *	   %-ENOMEM if memory allocation failed
+ *	   %-EINVAL if graph or endpoint parsing failed
+ *	   Other error codes as returned by @parse_endpoint
+ */
+int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
+	struct device *dev, struct v4l2_async_notifier *notifier,
+	size_t asd_struct_size, unsigned int port,
+	int (*parse_endpoint)(struct device *dev,
+			      struct v4l2_fwnode_endpoint *vep,
+			      struct v4l2_async_subdev *asd));
+
 #endif /* _V4L2_FWNODE_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 09/32] omap3isp: Use generic parser for parsing fwnode endpoints
  2017-10-26  7:53 ` Sakari Ailus
                   ` (6 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
       [not found]   ` <20171026075342.5760-10-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Instead of using a custom driver implementation, use
v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints
of the device.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
---
 drivers/media/platform/omap3isp/isp.c | 121 +++++++++++-----------------------
 drivers/media/platform/omap3isp/isp.h |   5 +-
 2 files changed, 40 insertions(+), 86 deletions(-)

diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 1a428fe9f070..97a5206b6ddc 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -2001,6 +2001,7 @@ static int isp_remove(struct platform_device *pdev)
 	__omap3isp_put(isp, false);
 
 	media_entity_enum_cleanup(&isp->crashed);
+	v4l2_async_notifier_cleanup(&isp->notifier);
 
 	return 0;
 }
@@ -2011,44 +2012,41 @@ enum isp_of_phy {
 	ISP_OF_PHY_CSIPHY2,
 };
 
-static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
-			    struct isp_async_subdev *isd)
+static int isp_fwnode_parse(struct device *dev,
+			    struct v4l2_fwnode_endpoint *vep,
+			    struct v4l2_async_subdev *asd)
 {
+	struct isp_async_subdev *isd =
+		container_of(asd, struct isp_async_subdev, asd);
 	struct isp_bus_cfg *buscfg = &isd->bus;
-	struct v4l2_fwnode_endpoint vep;
-	unsigned int i;
-	int ret;
 	bool csi1 = false;
-
-	ret = v4l2_fwnode_endpoint_parse(fwnode, &vep);
-	if (ret)
-		return ret;
+	unsigned int i;
 
 	dev_dbg(dev, "parsing endpoint %pOF, interface %u\n",
-		to_of_node(fwnode), vep.base.port);
+		to_of_node(vep->base.local_fwnode), vep->base.port);
 
-	switch (vep.base.port) {
+	switch (vep->base.port) {
 	case ISP_OF_PHY_PARALLEL:
 		buscfg->interface = ISP_INTERFACE_PARALLEL;
 		buscfg->bus.parallel.data_lane_shift =
-			vep.bus.parallel.data_shift;
+			vep->bus.parallel.data_shift;
 		buscfg->bus.parallel.clk_pol =
-			!!(vep.bus.parallel.flags
+			!!(vep->bus.parallel.flags
 			   & V4L2_MBUS_PCLK_SAMPLE_FALLING);
 		buscfg->bus.parallel.hs_pol =
-			!!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
+			!!(vep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
 		buscfg->bus.parallel.vs_pol =
-			!!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
+			!!(vep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
 		buscfg->bus.parallel.fld_pol =
-			!!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
+			!!(vep->bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
 		buscfg->bus.parallel.data_pol =
-			!!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
-		buscfg->bus.parallel.bt656 = vep.bus_type == V4L2_MBUS_BT656;
+			!!(vep->bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
+		buscfg->bus.parallel.bt656 = vep->bus_type == V4L2_MBUS_BT656;
 		break;
 
 	case ISP_OF_PHY_CSIPHY1:
 	case ISP_OF_PHY_CSIPHY2:
-		switch (vep.bus_type) {
+		switch (vep->bus_type) {
 		case V4L2_MBUS_CCP2:
 		case V4L2_MBUS_CSI1:
 			dev_dbg(dev, "CSI-1/CCP-2 configuration\n");
@@ -2060,11 +2058,11 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
 			break;
 		default:
 			dev_err(dev, "unsupported bus type %u\n",
-				vep.bus_type);
+				vep->bus_type);
 			return -EINVAL;
 		}
 
-		switch (vep.base.port) {
+		switch (vep->base.port) {
 		case ISP_OF_PHY_CSIPHY1:
 			if (csi1)
 				buscfg->interface = ISP_INTERFACE_CCP2B_PHY1;
@@ -2080,47 +2078,47 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
 		}
 		if (csi1) {
 			buscfg->bus.ccp2.lanecfg.clk.pos =
-				vep.bus.mipi_csi1.clock_lane;
+				vep->bus.mipi_csi1.clock_lane;
 			buscfg->bus.ccp2.lanecfg.clk.pol =
-				vep.bus.mipi_csi1.lane_polarity[0];
+				vep->bus.mipi_csi1.lane_polarity[0];
 			dev_dbg(dev, "clock lane polarity %u, pos %u\n",
 				buscfg->bus.ccp2.lanecfg.clk.pol,
 				buscfg->bus.ccp2.lanecfg.clk.pos);
 
 			buscfg->bus.ccp2.lanecfg.data[0].pos =
-				vep.bus.mipi_csi1.data_lane;
+				vep->bus.mipi_csi1.data_lane;
 			buscfg->bus.ccp2.lanecfg.data[0].pol =
-				vep.bus.mipi_csi1.lane_polarity[1];
+				vep->bus.mipi_csi1.lane_polarity[1];
 
 			dev_dbg(dev, "data lane polarity %u, pos %u\n",
 				buscfg->bus.ccp2.lanecfg.data[0].pol,
 				buscfg->bus.ccp2.lanecfg.data[0].pos);
 
 			buscfg->bus.ccp2.strobe_clk_pol =
-				vep.bus.mipi_csi1.clock_inv;
-			buscfg->bus.ccp2.phy_layer = vep.bus.mipi_csi1.strobe;
+				vep->bus.mipi_csi1.clock_inv;
+			buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe;
 			buscfg->bus.ccp2.ccp2_mode =
-				vep.bus_type == V4L2_MBUS_CCP2;
+				vep->bus_type == V4L2_MBUS_CCP2;
 			buscfg->bus.ccp2.vp_clk_pol = 1;
 
 			buscfg->bus.ccp2.crc = 1;
 		} else {
 			buscfg->bus.csi2.lanecfg.clk.pos =
-				vep.bus.mipi_csi2.clock_lane;
+				vep->bus.mipi_csi2.clock_lane;
 			buscfg->bus.csi2.lanecfg.clk.pol =
-				vep.bus.mipi_csi2.lane_polarities[0];
+				vep->bus.mipi_csi2.lane_polarities[0];
 			dev_dbg(dev, "clock lane polarity %u, pos %u\n",
 				buscfg->bus.csi2.lanecfg.clk.pol,
 				buscfg->bus.csi2.lanecfg.clk.pos);
 
 			buscfg->bus.csi2.num_data_lanes =
-				vep.bus.mipi_csi2.num_data_lanes;
+				vep->bus.mipi_csi2.num_data_lanes;
 
 			for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) {
 				buscfg->bus.csi2.lanecfg.data[i].pos =
-					vep.bus.mipi_csi2.data_lanes[i];
+					vep->bus.mipi_csi2.data_lanes[i];
 				buscfg->bus.csi2.lanecfg.data[i].pol =
-					vep.bus.mipi_csi2.lane_polarities[i + 1];
+					vep->bus.mipi_csi2.lane_polarities[i + 1];
 				dev_dbg(dev,
 					"data lane %u polarity %u, pos %u\n", i,
 					buscfg->bus.csi2.lanecfg.data[i].pol,
@@ -2137,57 +2135,13 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
 
 	default:
 		dev_warn(dev, "%pOF: invalid interface %u\n",
-			 to_of_node(fwnode), vep.base.port);
+			 to_of_node(vep->base.local_fwnode), vep->base.port);
 		return -EINVAL;
 	}
 
 	return 0;
 }
 
-static int isp_fwnodes_parse(struct device *dev,
-			     struct v4l2_async_notifier *notifier)
-{
-	struct fwnode_handle *fwnode = NULL;
-
-	notifier->subdevs = devm_kcalloc(
-		dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), GFP_KERNEL);
-	if (!notifier->subdevs)
-		return -ENOMEM;
-
-	while (notifier->num_subdevs < ISP_MAX_SUBDEVS &&
-	       (fwnode = fwnode_graph_get_next_endpoint(
-			of_fwnode_handle(dev->of_node), fwnode))) {
-		struct isp_async_subdev *isd;
-
-		isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL);
-		if (!isd)
-			goto error;
-
-		if (isp_fwnode_parse(dev, fwnode, isd)) {
-			devm_kfree(dev, isd);
-			continue;
-		}
-
-		notifier->subdevs[notifier->num_subdevs] = &isd->asd;
-
-		isd->asd.match.fwnode.fwnode =
-			fwnode_graph_get_remote_port_parent(fwnode);
-		if (!isd->asd.match.fwnode.fwnode) {
-			dev_warn(dev, "bad remote port parent\n");
-			goto error;
-		}
-
-		isd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
-		notifier->num_subdevs++;
-	}
-
-	return notifier->num_subdevs;
-
-error:
-	fwnode_handle_put(fwnode);
-	return -EINVAL;
-}
-
 static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
 {
 	struct isp_device *isp = container_of(async, struct isp_device,
@@ -2256,15 +2210,17 @@ static int isp_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
-	ret = isp_fwnodes_parse(&pdev->dev, &isp->notifier);
-	if (ret < 0)
-		return ret;
-
 	isp->autoidle = autoidle;
 
 	mutex_init(&isp->isp_mutex);
 	spin_lock_init(&isp->stat_lock);
 
+	ret = v4l2_async_notifier_parse_fwnode_endpoints(
+		&pdev->dev, &isp->notifier, sizeof(struct isp_async_subdev),
+		isp_fwnode_parse);
+	if (ret < 0)
+		goto error;
+
 	isp->dev = &pdev->dev;
 	isp->ref_count = 0;
 
@@ -2406,6 +2362,7 @@ static int isp_probe(struct platform_device *pdev)
 	isp_xclk_cleanup(isp);
 	__omap3isp_put(isp, false);
 error:
+	v4l2_async_notifier_cleanup(&isp->notifier);
 	mutex_destroy(&isp->isp_mutex);
 
 	return ret;
diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
index e528df6efc09..8b9043db94b3 100644
--- a/drivers/media/platform/omap3isp/isp.h
+++ b/drivers/media/platform/omap3isp/isp.h
@@ -220,14 +220,11 @@ struct isp_device {
 
 	unsigned int sbl_resources;
 	unsigned int subclk_resources;
-
-#define ISP_MAX_SUBDEVS		8
-	struct v4l2_subdev *subdevs[ISP_MAX_SUBDEVS];
 };
 
 struct isp_async_subdev {
-	struct isp_bus_cfg bus;
 	struct v4l2_async_subdev asd;
+	struct isp_bus_cfg bus;
 };
 
 #define v4l2_subdev_to_bus_cfg(sd) \
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 10/32] rcar-vin: Use generic parser for parsing fwnode endpoints
  2017-10-26  7:53 ` Sakari Ailus
                   ` (7 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Instead of using a custom driver implementation, use
v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints
of the device.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/platform/rcar-vin/rcar-core.c | 107 +++++++++-------------------
 drivers/media/platform/rcar-vin/rcar-dma.c  |  10 +--
 drivers/media/platform/rcar-vin/rcar-v4l2.c |  14 ++--
 drivers/media/platform/rcar-vin/rcar-vin.h  |   4 +-
 4 files changed, 46 insertions(+), 89 deletions(-)

diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 142de447aaaa..380288658601 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -21,6 +21,7 @@
 #include <linux/platform_device.h>
 #include <linux/pm_runtime.h>
 
+#include <media/v4l2-async.h>
 #include <media/v4l2-fwnode.h>
 
 #include "rcar-vin.h"
@@ -77,14 +78,14 @@ static int rvin_digital_notify_complete(struct v4l2_async_notifier *notifier)
 	int ret;
 
 	/* Verify subdevices mbus format */
-	if (!rvin_mbus_supported(&vin->digital)) {
+	if (!rvin_mbus_supported(vin->digital)) {
 		vin_err(vin, "Unsupported media bus format for %s\n",
-			vin->digital.subdev->name);
+			vin->digital->subdev->name);
 		return -EINVAL;
 	}
 
 	vin_dbg(vin, "Found media bus format for %s: %d\n",
-		vin->digital.subdev->name, vin->digital.code);
+		vin->digital->subdev->name, vin->digital->code);
 
 	ret = v4l2_device_register_subdev_nodes(&vin->v4l2_dev);
 	if (ret < 0) {
@@ -103,7 +104,7 @@ static void rvin_digital_notify_unbind(struct v4l2_async_notifier *notifier,
 
 	vin_dbg(vin, "unbind digital subdev %s\n", subdev->name);
 	rvin_v4l2_remove(vin);
-	vin->digital.subdev = NULL;
+	vin->digital->subdev = NULL;
 }
 
 static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
@@ -120,117 +121,71 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
 	ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SOURCE);
 	if (ret < 0)
 		return ret;
-	vin->digital.source_pad = ret;
+	vin->digital->source_pad = ret;
 
 	ret = rvin_find_pad(subdev, MEDIA_PAD_FL_SINK);
-	vin->digital.sink_pad = ret < 0 ? 0 : ret;
+	vin->digital->sink_pad = ret < 0 ? 0 : ret;
 
-	vin->digital.subdev = subdev;
+	vin->digital->subdev = subdev;
 
 	vin_dbg(vin, "bound subdev %s source pad: %u sink pad: %u\n",
-		subdev->name, vin->digital.source_pad,
-		vin->digital.sink_pad);
+		subdev->name, vin->digital->source_pad,
+		vin->digital->sink_pad);
 
 	return 0;
 }
 
-static int rvin_digitial_parse_v4l2(struct rvin_dev *vin,
-				    struct device_node *ep,
-				    struct v4l2_mbus_config *mbus_cfg)
+static int rvin_digital_parse_v4l2(struct device *dev,
+				   struct v4l2_fwnode_endpoint *vep,
+				   struct v4l2_async_subdev *asd)
 {
-	struct v4l2_fwnode_endpoint v4l2_ep;
-	int ret;
+	struct rvin_dev *vin = dev_get_drvdata(dev);
+	struct rvin_graph_entity *rvge =
+		container_of(asd, struct rvin_graph_entity, asd);
 
-	ret = v4l2_fwnode_endpoint_parse(of_fwnode_handle(ep), &v4l2_ep);
-	if (ret) {
-		vin_err(vin, "Could not parse v4l2 endpoint\n");
-		return -EINVAL;
-	}
+	if (vep->base.port || vep->base.id)
+		return -ENOTCONN;
 
-	mbus_cfg->type = v4l2_ep.bus_type;
+	rvge->mbus_cfg.type = vep->bus_type;
 
-	switch (mbus_cfg->type) {
+	switch (rvge->mbus_cfg.type) {
 	case V4L2_MBUS_PARALLEL:
 		vin_dbg(vin, "Found PARALLEL media bus\n");
-		mbus_cfg->flags = v4l2_ep.bus.parallel.flags;
+		rvge->mbus_cfg.flags = vep->bus.parallel.flags;
 		break;
 	case V4L2_MBUS_BT656:
 		vin_dbg(vin, "Found BT656 media bus\n");
-		mbus_cfg->flags = 0;
+		rvge->mbus_cfg.flags = 0;
 		break;
 	default:
 		vin_err(vin, "Unknown media bus type\n");
 		return -EINVAL;
 	}
 
-	return 0;
-}
-
-static int rvin_digital_graph_parse(struct rvin_dev *vin)
-{
-	struct device_node *ep, *np;
-	int ret;
-
-	vin->digital.asd.match.fwnode.fwnode = NULL;
-	vin->digital.subdev = NULL;
-
-	/*
-	 * Port 0 id 0 is local digital input, try to get it.
-	 * Not all instances can or will have this, that is OK
-	 */
-	ep = of_graph_get_endpoint_by_regs(vin->dev->of_node, 0, 0);
-	if (!ep)
-		return 0;
-
-	np = of_graph_get_remote_port_parent(ep);
-	if (!np) {
-		vin_err(vin, "No remote parent for digital input\n");
-		of_node_put(ep);
-		return -EINVAL;
-	}
-	of_node_put(np);
-
-	ret = rvin_digitial_parse_v4l2(vin, ep, &vin->digital.mbus_cfg);
-	of_node_put(ep);
-	if (ret)
-		return ret;
-
-	vin->digital.asd.match.fwnode.fwnode = of_fwnode_handle(np);
-	vin->digital.asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
+	vin->digital = rvge;
 
 	return 0;
 }
 
 static int rvin_digital_graph_init(struct rvin_dev *vin)
 {
-	struct v4l2_async_subdev **subdevs = NULL;
 	int ret;
 
-	ret = rvin_digital_graph_parse(vin);
+	ret = v4l2_async_notifier_parse_fwnode_endpoints(
+		vin->dev, &vin->notifier,
+		sizeof(struct rvin_graph_entity), rvin_digital_parse_v4l2);
 	if (ret)
 		return ret;
 
-	if (!vin->digital.asd.match.fwnode.fwnode) {
-		vin_dbg(vin, "No digital subdevice found\n");
+	if (!vin->digital)
 		return -ENODEV;
-	}
-
-	/* Register the subdevices notifier. */
-	subdevs = devm_kzalloc(vin->dev, sizeof(*subdevs), GFP_KERNEL);
-	if (subdevs == NULL)
-		return -ENOMEM;
-
-	subdevs[0] = &vin->digital.asd;
 
 	vin_dbg(vin, "Found digital subdevice %pOF\n",
-		to_of_node(subdevs[0]->match.fwnode.fwnode));
+		to_of_node(vin->digital->asd.match.fwnode.fwnode));
 
-	vin->notifier.num_subdevs = 1;
-	vin->notifier.subdevs = subdevs;
 	vin->notifier.bound = rvin_digital_notify_bound;
 	vin->notifier.unbind = rvin_digital_notify_unbind;
 	vin->notifier.complete = rvin_digital_notify_complete;
-
 	ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
 	if (ret < 0) {
 		vin_err(vin, "Notifier registration failed\n");
@@ -290,6 +245,8 @@ static int rcar_vin_probe(struct platform_device *pdev)
 	if (ret)
 		return ret;
 
+	platform_set_drvdata(pdev, vin);
+
 	ret = rvin_digital_graph_init(vin);
 	if (ret < 0)
 		goto error;
@@ -297,11 +254,10 @@ static int rcar_vin_probe(struct platform_device *pdev)
 	pm_suspend_ignore_children(&pdev->dev, true);
 	pm_runtime_enable(&pdev->dev);
 
-	platform_set_drvdata(pdev, vin);
-
 	return 0;
 error:
 	rvin_dma_remove(vin);
+	v4l2_async_notifier_cleanup(&vin->notifier);
 
 	return ret;
 }
@@ -313,6 +269,7 @@ static int rcar_vin_remove(struct platform_device *pdev)
 	pm_runtime_disable(&pdev->dev);
 
 	v4l2_async_notifier_unregister(&vin->notifier);
+	v4l2_async_notifier_cleanup(&vin->notifier);
 
 	rvin_dma_remove(vin);
 
diff --git a/drivers/media/platform/rcar-vin/rcar-dma.c b/drivers/media/platform/rcar-vin/rcar-dma.c
index b136844499f6..23fdff7a7370 100644
--- a/drivers/media/platform/rcar-vin/rcar-dma.c
+++ b/drivers/media/platform/rcar-vin/rcar-dma.c
@@ -183,7 +183,7 @@ static int rvin_setup(struct rvin_dev *vin)
 	/*
 	 * Input interface
 	 */
-	switch (vin->digital.code) {
+	switch (vin->digital->code) {
 	case MEDIA_BUS_FMT_YUYV8_1X16:
 		/* BT.601/BT.1358 16bit YCbCr422 */
 		vnmc |= VNMC_INF_YUV16;
@@ -191,7 +191,7 @@ static int rvin_setup(struct rvin_dev *vin)
 		break;
 	case MEDIA_BUS_FMT_UYVY8_2X8:
 		/* BT.656 8bit YCbCr422 or BT.601 8bit YCbCr422 */
-		vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
+		vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ?
 			VNMC_INF_YUV8_BT656 : VNMC_INF_YUV8_BT601;
 		input_is_yuv = true;
 		break;
@@ -200,7 +200,7 @@ static int rvin_setup(struct rvin_dev *vin)
 		break;
 	case MEDIA_BUS_FMT_UYVY10_2X10:
 		/* BT.656 10bit YCbCr422 or BT.601 10bit YCbCr422 */
-		vnmc |= vin->digital.mbus_cfg.type == V4L2_MBUS_BT656 ?
+		vnmc |= vin->digital->mbus_cfg.type == V4L2_MBUS_BT656 ?
 			VNMC_INF_YUV10_BT656 : VNMC_INF_YUV10_BT601;
 		input_is_yuv = true;
 		break;
@@ -212,11 +212,11 @@ static int rvin_setup(struct rvin_dev *vin)
 	dmr2 = VNDMR2_FTEV | VNDMR2_VLV(1);
 
 	/* Hsync Signal Polarity Select */
-	if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
+	if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW))
 		dmr2 |= VNDMR2_HPS;
 
 	/* Vsync Signal Polarity Select */
-	if (!(vin->digital.mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
+	if (!(vin->digital->mbus_cfg.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW))
 		dmr2 |= VNDMR2_VPS;
 
 	/*
diff --git a/drivers/media/platform/rcar-vin/rcar-v4l2.c b/drivers/media/platform/rcar-vin/rcar-v4l2.c
index dd37ea811680..b479b882da12 100644
--- a/drivers/media/platform/rcar-vin/rcar-v4l2.c
+++ b/drivers/media/platform/rcar-vin/rcar-v4l2.c
@@ -111,7 +111,7 @@ static int rvin_reset_format(struct rvin_dev *vin)
 	struct v4l2_mbus_framefmt *mf = &fmt.format;
 	int ret;
 
-	fmt.pad = vin->digital.source_pad;
+	fmt.pad = vin->digital->source_pad;
 
 	ret = v4l2_subdev_call(vin_to_source(vin), pad, get_fmt, NULL, &fmt);
 	if (ret)
@@ -172,13 +172,13 @@ static int __rvin_try_format_source(struct rvin_dev *vin,
 
 	sd = vin_to_source(vin);
 
-	v4l2_fill_mbus_format(&format.format, pix, vin->digital.code);
+	v4l2_fill_mbus_format(&format.format, pix, vin->digital->code);
 
 	pad_cfg = v4l2_subdev_alloc_pad_config(sd);
 	if (pad_cfg == NULL)
 		return -ENOMEM;
 
-	format.pad = vin->digital.source_pad;
+	format.pad = vin->digital->source_pad;
 
 	field = pix->field;
 
@@ -555,7 +555,7 @@ static int rvin_enum_dv_timings(struct file *file, void *priv_fh,
 	if (timings->pad)
 		return -EINVAL;
 
-	timings->pad = vin->digital.sink_pad;
+	timings->pad = vin->digital->sink_pad;
 
 	ret = v4l2_subdev_call(sd, pad, enum_dv_timings, timings);
 
@@ -607,7 +607,7 @@ static int rvin_dv_timings_cap(struct file *file, void *priv_fh,
 	if (cap->pad)
 		return -EINVAL;
 
-	cap->pad = vin->digital.sink_pad;
+	cap->pad = vin->digital->sink_pad;
 
 	ret = v4l2_subdev_call(sd, pad, dv_timings_cap, cap);
 
@@ -625,7 +625,7 @@ static int rvin_g_edid(struct file *file, void *fh, struct v4l2_edid *edid)
 	if (edid->pad)
 		return -EINVAL;
 
-	edid->pad = vin->digital.sink_pad;
+	edid->pad = vin->digital->sink_pad;
 
 	ret = v4l2_subdev_call(sd, pad, get_edid, edid);
 
@@ -643,7 +643,7 @@ static int rvin_s_edid(struct file *file, void *fh, struct v4l2_edid *edid)
 	if (edid->pad)
 		return -EINVAL;
 
-	edid->pad = vin->digital.sink_pad;
+	edid->pad = vin->digital->sink_pad;
 
 	ret = v4l2_subdev_call(sd, pad, set_edid, edid);
 
diff --git a/drivers/media/platform/rcar-vin/rcar-vin.h b/drivers/media/platform/rcar-vin/rcar-vin.h
index 9bfb5a7c4dc4..5382078143fb 100644
--- a/drivers/media/platform/rcar-vin/rcar-vin.h
+++ b/drivers/media/platform/rcar-vin/rcar-vin.h
@@ -126,7 +126,7 @@ struct rvin_dev {
 	struct v4l2_device v4l2_dev;
 	struct v4l2_ctrl_handler ctrl_handler;
 	struct v4l2_async_notifier notifier;
-	struct rvin_graph_entity digital;
+	struct rvin_graph_entity *digital;
 
 	struct mutex lock;
 	struct vb2_queue queue;
@@ -145,7 +145,7 @@ struct rvin_dev {
 	struct v4l2_rect compose;
 };
 
-#define vin_to_source(vin)		vin->digital.subdev
+#define vin_to_source(vin)		((vin)->digital->subdev)
 
 /* Debug */
 #define vin_dbg(d, fmt, arg...)		dev_dbg(d->dev, fmt, ##arg)
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 11/32] omap3isp: Fix check for our own sub-devices
  2017-10-26  7:53 ` Sakari Ailus
                   ` (8 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-27 14:47   ` Sebastian Reichel
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

We only want to link sub-devices that were bound to the async notifier the
isp driver registered but there may be other sub-devices in the
v4l2_device as well. Check for the correct async notifier.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 drivers/media/platform/omap3isp/isp.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 97a5206b6ddc..4afd7ba4fad6 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -2155,7 +2155,7 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
 		return ret;
 
 	list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
-		if (!sd->asd)
+		if (sd->notifier != &isp->notifier)
 			continue;
 
 		ret = isp_link_entity(isp, &sd->entity,
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 12/32] omap3isp: Print the name of the entity where no source pads could be found
  2017-10-26  7:53 ` Sakari Ailus
                   ` (9 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-27 14:47   ` Sebastian Reichel
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

If no source pads are found in an entity, print the name of the entity.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 drivers/media/platform/omap3isp/isp.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 4afd7ba4fad6..35687c9707e0 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -1669,8 +1669,8 @@ static int isp_link_entity(
 			break;
 	}
 	if (i == entity->num_pads) {
-		dev_err(isp->dev, "%s: no source pad in external entity\n",
-			__func__);
+		dev_err(isp->dev, "%s: no source pad in external entity %s\n",
+			__func__, entity->name);
 		return -EINVAL;
 	}
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 13/32] v4l: async: Move async subdev notifier operations to a separate structure
  2017-10-26  7:53 ` Sakari Ailus
                   ` (10 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-26 21:44   ` Niklas Söderlund
  2017-10-27 14:47   ` Sebastian Reichel
  -1 siblings, 2 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>

The async subdev notifier .bound(), .unbind() and .complete() operations
are function pointers stored directly in the v4l2_async_subdev
structure. As the structure isn't immutable, this creates a potential
security risk as the function pointers are mutable.

To fix this, move the function pointers to a new
v4l2_async_subdev_operations structure that can be made const in
drivers.

Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/platform/am437x/am437x-vpfe.c    |  8 +++++--
 drivers/media/platform/atmel/atmel-isc.c       | 10 ++++++---
 drivers/media/platform/atmel/atmel-isi.c       | 10 ++++++---
 drivers/media/platform/davinci/vpif_capture.c  |  8 +++++--
 drivers/media/platform/davinci/vpif_display.c  |  8 +++++--
 drivers/media/platform/exynos4-is/media-dev.c  |  8 +++++--
 drivers/media/platform/omap3isp/isp.c          |  6 +++++-
 drivers/media/platform/pxa_camera.c            |  8 +++++--
 drivers/media/platform/qcom/camss-8x16/camss.c |  8 +++++--
 drivers/media/platform/rcar-vin/rcar-core.c    | 10 ++++++---
 drivers/media/platform/rcar_drif.c             | 10 ++++++---
 drivers/media/platform/soc_camera/soc_camera.c | 14 ++++++------
 drivers/media/platform/stm32/stm32-dcmi.c      | 10 ++++++---
 drivers/media/platform/ti-vpe/cal.c            |  8 +++++--
 drivers/media/platform/xilinx/xilinx-vipp.c    |  8 +++++--
 drivers/media/v4l2-core/v4l2-async.c           | 30 ++++++++++++--------------
 drivers/staging/media/imx/imx-media-dev.c      |  8 +++++--
 include/media/v4l2-async.h                     | 29 ++++++++++++++++---------
 18 files changed, 135 insertions(+), 66 deletions(-)

diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
index dfcc484cab89..0997c640191d 100644
--- a/drivers/media/platform/am437x/am437x-vpfe.c
+++ b/drivers/media/platform/am437x/am437x-vpfe.c
@@ -2417,6 +2417,11 @@ static int vpfe_async_complete(struct v4l2_async_notifier *notifier)
 	return vpfe_probe_complete(vpfe);
 }
 
+static const struct v4l2_async_notifier_operations vpfe_async_ops = {
+	.bound = vpfe_async_bound,
+	.complete = vpfe_async_complete,
+};
+
 static struct vpfe_config *
 vpfe_get_pdata(struct platform_device *pdev)
 {
@@ -2590,8 +2595,7 @@ static int vpfe_probe(struct platform_device *pdev)
 
 	vpfe->notifier.subdevs = vpfe->cfg->asd;
 	vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd);
-	vpfe->notifier.bound = vpfe_async_bound;
-	vpfe->notifier.complete = vpfe_async_complete;
+	vpfe->notifier.ops = &vpfe_async_ops;
 	ret = v4l2_async_notifier_register(&vpfe->v4l2_dev,
 						&vpfe->notifier);
 	if (ret) {
diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c
index 2f8e345d297e..382fe355e616 100644
--- a/drivers/media/platform/atmel/atmel-isc.c
+++ b/drivers/media/platform/atmel/atmel-isc.c
@@ -1637,6 +1637,12 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
 	return 0;
 }
 
+static const struct v4l2_async_notifier_operations isc_async_ops = {
+	.bound = isc_async_bound,
+	.unbind = isc_async_unbind,
+	.complete = isc_async_complete,
+};
+
 static void isc_subdev_cleanup(struct isc_device *isc)
 {
 	struct isc_subdev_entity *subdev_entity;
@@ -1849,9 +1855,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
 	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
 		subdev_entity->notifier.subdevs = &subdev_entity->asd;
 		subdev_entity->notifier.num_subdevs = 1;
-		subdev_entity->notifier.bound = isc_async_bound;
-		subdev_entity->notifier.unbind = isc_async_unbind;
-		subdev_entity->notifier.complete = isc_async_complete;
+		subdev_entity->notifier.ops = &isc_async_ops;
 
 		ret = v4l2_async_notifier_register(&isc->v4l2_dev,
 						   &subdev_entity->notifier);
diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
index 463c0146915e..e900995143a3 100644
--- a/drivers/media/platform/atmel/atmel-isi.c
+++ b/drivers/media/platform/atmel/atmel-isi.c
@@ -1103,6 +1103,12 @@ static int isi_graph_notify_bound(struct v4l2_async_notifier *notifier,
 	return 0;
 }
 
+static const struct v4l2_async_notifier_operations isi_graph_notify_ops = {
+	.bound = isi_graph_notify_bound,
+	.unbind = isi_graph_notify_unbind,
+	.complete = isi_graph_notify_complete,
+};
+
 static int isi_graph_parse(struct atmel_isi *isi, struct device_node *node)
 {
 	struct device_node *ep = NULL;
@@ -1150,9 +1156,7 @@ static int isi_graph_init(struct atmel_isi *isi)
 
 	isi->notifier.subdevs = subdevs;
 	isi->notifier.num_subdevs = 1;
-	isi->notifier.bound = isi_graph_notify_bound;
-	isi->notifier.unbind = isi_graph_notify_unbind;
-	isi->notifier.complete = isi_graph_notify_complete;
+	isi->notifier.ops = &isi_graph_notify_ops;
 
 	ret = v4l2_async_notifier_register(&isi->v4l2_dev, &isi->notifier);
 	if (ret < 0) {
diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
index 0ef36cec21d1..a89367ab1e06 100644
--- a/drivers/media/platform/davinci/vpif_capture.c
+++ b/drivers/media/platform/davinci/vpif_capture.c
@@ -1500,6 +1500,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)
 	return vpif_probe_complete();
 }
 
+static const struct v4l2_async_notifier_operations vpif_async_ops = {
+	.bound = vpif_async_bound,
+	.complete = vpif_async_complete,
+};
+
 static struct vpif_capture_config *
 vpif_capture_get_pdata(struct platform_device *pdev)
 {
@@ -1691,8 +1696,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 	} else {
 		vpif_obj.notifier.subdevs = vpif_obj.config->asd;
 		vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
-		vpif_obj.notifier.bound = vpif_async_bound;
-		vpif_obj.notifier.complete = vpif_async_complete;
+		vpif_obj.notifier.ops = &vpif_async_ops;
 		err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
 						   &vpif_obj.notifier);
 		if (err) {
diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
index 56fe4e5b396e..ff2f75a328c9 100644
--- a/drivers/media/platform/davinci/vpif_display.c
+++ b/drivers/media/platform/davinci/vpif_display.c
@@ -1232,6 +1232,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)
 	return vpif_probe_complete();
 }
 
+static const struct v4l2_async_notifier_operations vpif_async_ops = {
+	.bound = vpif_async_bound,
+	.complete = vpif_async_complete,
+};
+
 /*
  * vpif_probe: This function creates device entries by register itself to the
  * V4L2 driver and initializes fields of each channel objects
@@ -1313,8 +1318,7 @@ static __init int vpif_probe(struct platform_device *pdev)
 	} else {
 		vpif_obj.notifier.subdevs = vpif_obj.config->asd;
 		vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
-		vpif_obj.notifier.bound = vpif_async_bound;
-		vpif_obj.notifier.complete = vpif_async_complete;
+		vpif_obj.notifier.ops = &vpif_async_ops;
 		err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
 						   &vpif_obj.notifier);
 		if (err) {
diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
index d4656d5175d7..c15596b56dc9 100644
--- a/drivers/media/platform/exynos4-is/media-dev.c
+++ b/drivers/media/platform/exynos4-is/media-dev.c
@@ -1405,6 +1405,11 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
 	return media_device_register(&fmd->media_dev);
 }
 
+static const struct v4l2_async_notifier_operations subdev_notifier_ops = {
+	.bound = subdev_notifier_bound,
+	.complete = subdev_notifier_complete,
+};
+
 static int fimc_md_probe(struct platform_device *pdev)
 {
 	struct device *dev = &pdev->dev;
@@ -1479,8 +1484,7 @@ static int fimc_md_probe(struct platform_device *pdev)
 	if (fmd->num_sensors > 0) {
 		fmd->subdev_notifier.subdevs = fmd->async_subdevs;
 		fmd->subdev_notifier.num_subdevs = fmd->num_sensors;
-		fmd->subdev_notifier.bound = subdev_notifier_bound;
-		fmd->subdev_notifier.complete = subdev_notifier_complete;
+		fmd->subdev_notifier.ops = &subdev_notifier_ops;
 		fmd->num_sensors = 0;
 
 		ret = v4l2_async_notifier_register(&fmd->v4l2_dev,
diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
index 35687c9707e0..b7ff3842afc0 100644
--- a/drivers/media/platform/omap3isp/isp.c
+++ b/drivers/media/platform/omap3isp/isp.c
@@ -2171,6 +2171,10 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
 	return media_device_register(&isp->media_dev);
 }
 
+static const struct v4l2_async_notifier_operations isp_subdev_notifier_ops = {
+	.complete = isp_subdev_notifier_complete,
+};
+
 /*
  * isp_probe - Probe ISP platform device
  * @pdev: Pointer to ISP platform device
@@ -2341,7 +2345,7 @@ static int isp_probe(struct platform_device *pdev)
 	if (ret < 0)
 		goto error_register_entities;
 
-	isp->notifier.complete = isp_subdev_notifier_complete;
+	isp->notifier.ops = &isp_subdev_notifier_ops;
 
 	ret = v4l2_async_notifier_register(&isp->v4l2_dev, &isp->notifier);
 	if (ret)
diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
index edca993c2b1f..9d3f0cb1d95a 100644
--- a/drivers/media/platform/pxa_camera.c
+++ b/drivers/media/platform/pxa_camera.c
@@ -2221,6 +2221,11 @@ static void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier,
 	mutex_unlock(&pcdev->mlock);
 }
 
+static const struct v4l2_async_notifier_operations pxa_camera_sensor_ops = {
+	.bound = pxa_camera_sensor_bound,
+	.unbind = pxa_camera_sensor_unbind,
+};
+
 /*
  * Driver probe, remove, suspend and resume operations
  */
@@ -2489,8 +2494,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
 	pcdev->asds[0] = &pcdev->asd;
 	pcdev->notifier.subdevs = pcdev->asds;
 	pcdev->notifier.num_subdevs = 1;
-	pcdev->notifier.bound = pxa_camera_sensor_bound;
-	pcdev->notifier.unbind = pxa_camera_sensor_unbind;
+	pcdev->notifier.ops = &pxa_camera_sensor_ops;
 
 	if (!of_have_populated_dt())
 		pcdev->asd.match_type = V4L2_ASYNC_MATCH_I2C;
diff --git a/drivers/media/platform/qcom/camss-8x16/camss.c b/drivers/media/platform/qcom/camss-8x16/camss.c
index a3760b5dd1d1..390a42c17b66 100644
--- a/drivers/media/platform/qcom/camss-8x16/camss.c
+++ b/drivers/media/platform/qcom/camss-8x16/camss.c
@@ -601,6 +601,11 @@ static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async)
 	return media_device_register(&camss->media_dev);
 }
 
+static const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = {
+	.bound = camss_subdev_notifier_bound,
+	.complete = camss_subdev_notifier_complete,
+};
+
 static const struct media_device_ops camss_media_ops = {
 	.link_notify = v4l2_pipeline_link_notify,
 };
@@ -655,8 +660,7 @@ static int camss_probe(struct platform_device *pdev)
 		goto err_register_entities;
 
 	if (camss->notifier.num_subdevs) {
-		camss->notifier.bound = camss_subdev_notifier_bound;
-		camss->notifier.complete = camss_subdev_notifier_complete;
+		camss->notifier.ops = &camss_subdev_notifier_ops;
 
 		ret = v4l2_async_notifier_register(&camss->v4l2_dev,
 						   &camss->notifier);
diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
index 380288658601..108d776f3265 100644
--- a/drivers/media/platform/rcar-vin/rcar-core.c
+++ b/drivers/media/platform/rcar-vin/rcar-core.c
@@ -134,6 +134,12 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
 
 	return 0;
 }
+static const struct v4l2_async_notifier_operations rvin_digital_notify_ops = {
+	.bound = rvin_digital_notify_bound,
+	.unbind = rvin_digital_notify_unbind,
+	.complete = rvin_digital_notify_complete,
+};
+
 
 static int rvin_digital_parse_v4l2(struct device *dev,
 				   struct v4l2_fwnode_endpoint *vep,
@@ -183,9 +189,7 @@ static int rvin_digital_graph_init(struct rvin_dev *vin)
 	vin_dbg(vin, "Found digital subdevice %pOF\n",
 		to_of_node(vin->digital->asd.match.fwnode.fwnode));
 
-	vin->notifier.bound = rvin_digital_notify_bound;
-	vin->notifier.unbind = rvin_digital_notify_unbind;
-	vin->notifier.complete = rvin_digital_notify_complete;
+	vin->notifier.ops = &rvin_digital_notify_ops;
 	ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
 	if (ret < 0) {
 		vin_err(vin, "Notifier registration failed\n");
diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
index 2c6afd38b78a..63c94f4028a7 100644
--- a/drivers/media/platform/rcar_drif.c
+++ b/drivers/media/platform/rcar_drif.c
@@ -1185,6 +1185,12 @@ static int rcar_drif_notify_complete(struct v4l2_async_notifier *notifier)
 	return ret;
 }
 
+static const struct v4l2_async_notifier_operations rcar_drif_notify_ops = {
+	.bound = rcar_drif_notify_bound,
+	.unbind = rcar_drif_notify_unbind,
+	.complete = rcar_drif_notify_complete,
+};
+
 /* Read endpoint properties */
 static void rcar_drif_get_ep_properties(struct rcar_drif_sdr *sdr,
 					struct fwnode_handle *fwnode)
@@ -1347,9 +1353,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr)
 	if (ret)
 		goto error;
 
-	sdr->notifier.bound = rcar_drif_notify_bound;
-	sdr->notifier.unbind = rcar_drif_notify_unbind;
-	sdr->notifier.complete = rcar_drif_notify_complete;
+	sdr->notifier.ops = &rcar_drif_notify_ops;
 
 	/* Register notifier */
 	ret = v4l2_async_notifier_register(&sdr->v4l2_dev, &sdr->notifier);
diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
index 1f3c450c7a69..916ff68b73d4 100644
--- a/drivers/media/platform/soc_camera/soc_camera.c
+++ b/drivers/media/platform/soc_camera/soc_camera.c
@@ -1391,6 +1391,12 @@ static int soc_camera_async_complete(struct v4l2_async_notifier *notifier)
 	return 0;
 }
 
+static const struct v4l2_async_notifier_operations soc_camera_async_ops = {
+	.bound = soc_camera_async_bound,
+	.unbind = soc_camera_async_unbind,
+	.complete = soc_camera_async_complete,
+};
+
 static int scan_async_group(struct soc_camera_host *ici,
 			    struct v4l2_async_subdev **asd, unsigned int size)
 {
@@ -1437,9 +1443,7 @@ static int scan_async_group(struct soc_camera_host *ici,
 
 	sasc->notifier.subdevs = asd;
 	sasc->notifier.num_subdevs = size;
-	sasc->notifier.bound = soc_camera_async_bound;
-	sasc->notifier.unbind = soc_camera_async_unbind;
-	sasc->notifier.complete = soc_camera_async_complete;
+	sasc->notifier.ops = &soc_camera_async_ops;
 
 	icd->sasc = sasc;
 	icd->parent = ici->v4l2_dev.dev;
@@ -1537,9 +1541,7 @@ static int soc_of_bind(struct soc_camera_host *ici,
 
 	sasc->notifier.subdevs = &info->subdev;
 	sasc->notifier.num_subdevs = 1;
-	sasc->notifier.bound = soc_camera_async_bound;
-	sasc->notifier.unbind = soc_camera_async_unbind;
-	sasc->notifier.complete = soc_camera_async_complete;
+	sasc->notifier.ops = &soc_camera_async_ops;
 
 	icd->sasc = sasc;
 	icd->parent = ici->v4l2_dev.dev;
diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
index 35ba6f211b79..ac4c450a6c7d 100644
--- a/drivers/media/platform/stm32/stm32-dcmi.c
+++ b/drivers/media/platform/stm32/stm32-dcmi.c
@@ -1495,6 +1495,12 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier,
 	return 0;
 }
 
+static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = {
+	.bound = dcmi_graph_notify_bound,
+	.unbind = dcmi_graph_notify_unbind,
+	.complete = dcmi_graph_notify_complete,
+};
+
 static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node)
 {
 	struct device_node *ep = NULL;
@@ -1542,9 +1548,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
 
 	dcmi->notifier.subdevs = subdevs;
 	dcmi->notifier.num_subdevs = 1;
-	dcmi->notifier.bound = dcmi_graph_notify_bound;
-	dcmi->notifier.unbind = dcmi_graph_notify_unbind;
-	dcmi->notifier.complete = dcmi_graph_notify_complete;
+	dcmi->notifier.ops = &dcmi_graph_notify_ops;
 
 	ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier);
 	if (ret < 0) {
diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c
index 42e383a48ffe..8b586c864524 100644
--- a/drivers/media/platform/ti-vpe/cal.c
+++ b/drivers/media/platform/ti-vpe/cal.c
@@ -1522,6 +1522,11 @@ static int cal_async_complete(struct v4l2_async_notifier *notifier)
 	return 0;
 }
 
+static const struct v4l2_async_notifier_operations cal_async_ops = {
+	.bound = cal_async_bound,
+	.complete = cal_async_complete,
+};
+
 static int cal_complete_ctx(struct cal_ctx *ctx)
 {
 	struct video_device *vfd;
@@ -1736,8 +1741,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
 	ctx->asd_list[0] = asd;
 	ctx->notifier.subdevs = ctx->asd_list;
 	ctx->notifier.num_subdevs = 1;
-	ctx->notifier.bound = cal_async_bound;
-	ctx->notifier.complete = cal_async_complete;
+	ctx->notifier.ops = &cal_async_ops;
 	ret = v4l2_async_notifier_register(&ctx->v4l2_dev,
 					   &ctx->notifier);
 	if (ret) {
diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
index ebfdf334d99c..d881cf09876d 100644
--- a/drivers/media/platform/xilinx/xilinx-vipp.c
+++ b/drivers/media/platform/xilinx/xilinx-vipp.c
@@ -351,6 +351,11 @@ static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
 	return -EINVAL;
 }
 
+static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = {
+	.bound = xvip_graph_notify_bound,
+	.complete = xvip_graph_notify_complete,
+};
+
 static int xvip_graph_parse_one(struct xvip_composite_device *xdev,
 				struct device_node *node)
 {
@@ -548,8 +553,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
 
 	xdev->notifier.subdevs = subdevs;
 	xdev->notifier.num_subdevs = num_subdevs;
-	xdev->notifier.bound = xvip_graph_notify_bound;
-	xdev->notifier.complete = xvip_graph_notify_complete;
+	xdev->notifier.ops = &xvip_graph_notify_ops;
 
 	ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier);
 	if (ret < 0) {
diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 46aebfc75e43..9d6fc5f25619 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -102,16 +102,16 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 {
 	int ret;
 
-	if (notifier->bound) {
-		ret = notifier->bound(notifier, sd, asd);
+	if (notifier->ops->bound) {
+		ret = notifier->ops->bound(notifier, sd, asd);
 		if (ret < 0)
 			return ret;
 	}
 
 	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
 	if (ret < 0) {
-		if (notifier->unbind)
-			notifier->unbind(notifier, sd, asd);
+		if (notifier->ops->unbind)
+			notifier->ops->unbind(notifier, sd, asd);
 		return ret;
 	}
 
@@ -140,9 +140,8 @@ static void v4l2_async_notifier_unbind_all_subdevs(
 	struct v4l2_subdev *sd, *tmp;
 
 	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
-		if (notifier->unbind)
-			notifier->unbind(notifier, sd, sd->asd);
-
+		if (notifier->ops->unbind)
+			notifier->ops->unbind(notifier, sd, sd->asd);
 		v4l2_async_cleanup(sd);
 
 		list_move(&sd->async_list, &subdev_list);
@@ -199,8 +198,8 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 		}
 	}
 
-	if (list_empty(&notifier->waiting) && notifier->complete) {
-		ret = notifier->complete(notifier);
+	if (list_empty(&notifier->waiting) && notifier->ops->complete) {
+		ret = notifier->ops->complete(notifier);
 		if (ret)
 			goto err_complete;
 	}
@@ -297,10 +296,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 		if (ret)
 			goto err_unlock;
 
-		if (!list_empty(&notifier->waiting) || !notifier->complete)
+		if (!list_empty(&notifier->waiting) || !notifier->ops->complete)
 			goto out_unlock;
 
-		ret = notifier->complete(notifier);
+		ret = notifier->ops->complete(notifier);
 		if (ret)
 			goto err_cleanup;
 
@@ -316,9 +315,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 	return 0;
 
 err_cleanup:
-	if (notifier->unbind)
-		notifier->unbind(notifier, sd, sd->asd);
-
+	if (notifier->ops->unbind)
+		notifier->ops->unbind(notifier, sd, sd->asd);
 	v4l2_async_cleanup(sd);
 
 err_unlock:
@@ -337,8 +335,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 
 		list_add(&sd->asd->list, &notifier->waiting);
 
-		if (notifier->unbind)
-			notifier->unbind(notifier, sd, sd->asd);
+		if (notifier->ops->unbind)
+			notifier->ops->unbind(notifier, sd, sd->asd);
 	}
 
 	v4l2_async_cleanup(sd);
diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
index b55e5ebba8b4..47c4c954fed5 100644
--- a/drivers/staging/media/imx/imx-media-dev.c
+++ b/drivers/staging/media/imx/imx-media-dev.c
@@ -440,6 +440,11 @@ static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
 	return media_device_register(&imxmd->md);
 }
 
+static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
+	.bound = imx_media_subdev_bound,
+	.complete = imx_media_probe_complete,
+};
+
 /*
  * adds controls to a video device from an entity subdevice.
  * Continues upstream from the entity's sink pads.
@@ -608,8 +613,7 @@ static int imx_media_probe(struct platform_device *pdev)
 
 	/* prepare the async subdev notifier and register it */
 	imxmd->subdev_notifier.subdevs = imxmd->async_ptrs;
-	imxmd->subdev_notifier.bound = imx_media_subdev_bound;
-	imxmd->subdev_notifier.complete = imx_media_probe_complete;
+	imxmd->subdev_notifier.ops = &imx_media_subdev_ops;
 	ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
 					   &imxmd->subdev_notifier);
 	if (ret) {
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 329aeebd1a80..68606afb5ef9 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -18,6 +18,7 @@ struct device;
 struct device_node;
 struct v4l2_device;
 struct v4l2_subdev;
+struct v4l2_async_notifier;
 
 /* A random max subdevice number, used to allocate an array on stack */
 #define V4L2_MAX_SUBDEVS 128U
@@ -79,8 +80,25 @@ struct v4l2_async_subdev {
 };
 
 /**
+ * struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations
+ * @bound:	a subdevice driver has successfully probed one of the subdevices
+ * @complete:	all subdevices have been probed successfully
+ * @unbind:	a subdevice is leaving
+ */
+struct v4l2_async_notifier_operations {
+	int (*bound)(struct v4l2_async_notifier *notifier,
+		     struct v4l2_subdev *subdev,
+		     struct v4l2_async_subdev *asd);
+	int (*complete)(struct v4l2_async_notifier *notifier);
+	void (*unbind)(struct v4l2_async_notifier *notifier,
+		       struct v4l2_subdev *subdev,
+		       struct v4l2_async_subdev *asd);
+};
+
+/**
  * struct v4l2_async_notifier - v4l2_device notifier data
  *
+ * @ops:	notifier operations
  * @num_subdevs: number of subdevices used in the subdevs array
  * @max_subdevs: number of subdevices allocated in the subdevs array
  * @subdevs:	array of pointers to subdevice descriptors
@@ -88,11 +106,9 @@ struct v4l2_async_subdev {
  * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
  * @done:	list of struct v4l2_subdev, already probed
  * @list:	member in a global list of notifiers
- * @bound:	a subdevice driver has successfully probed one of subdevices
- * @complete:	all subdevices have been probed successfully
- * @unbind:	a subdevice is leaving
  */
 struct v4l2_async_notifier {
+	const struct v4l2_async_notifier_operations *ops;
 	unsigned int num_subdevs;
 	unsigned int max_subdevs;
 	struct v4l2_async_subdev **subdevs;
@@ -100,13 +116,6 @@ struct v4l2_async_notifier {
 	struct list_head waiting;
 	struct list_head done;
 	struct list_head list;
-	int (*bound)(struct v4l2_async_notifier *notifier,
-		     struct v4l2_subdev *subdev,
-		     struct v4l2_async_subdev *asd);
-	int (*complete)(struct v4l2_async_notifier *notifier);
-	void (*unbind)(struct v4l2_async_notifier *notifier,
-		       struct v4l2_subdev *subdev,
-		       struct v4l2_async_subdev *asd);
 };
 
 /**
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 14/32] v4l: async: Introduce helpers for calling async ops callbacks
  2017-10-26  7:53 ` Sakari Ailus
                   ` (11 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-26 21:46   ` Niklas Söderlund
  2017-10-27 14:48   ` Sebastian Reichel
  -1 siblings, 2 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Add three helper functions to call async operations callbacks. Besides
simplifying callbacks, this allows async notifiers to have no ops set,
i.e. it can be left NULL.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 drivers/media/v4l2-core/v4l2-async.c | 56 +++++++++++++++++++++++++-----------
 1 file changed, 39 insertions(+), 17 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 9d6fc5f25619..e170682dae78 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -25,6 +25,34 @@
 #include <media/v4l2-fwnode.h>
 #include <media/v4l2-subdev.h>
 
+static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
+					  struct v4l2_subdev *subdev,
+					  struct v4l2_async_subdev *asd)
+{
+	if (!n->ops || !n->ops->bound)
+		return 0;
+
+	return n->ops->bound(n, subdev, asd);
+}
+
+static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
+					    struct v4l2_subdev *subdev,
+					    struct v4l2_async_subdev *asd)
+{
+	if (!n->ops || !n->ops->unbind)
+		return;
+
+	n->ops->unbind(n, subdev, asd);
+}
+
+static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
+{
+	if (!n->ops || !n->ops->complete)
+		return 0;
+
+	return n->ops->complete(n);
+}
+
 static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
 {
 #if IS_ENABLED(CONFIG_I2C)
@@ -102,16 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 {
 	int ret;
 
-	if (notifier->ops->bound) {
-		ret = notifier->ops->bound(notifier, sd, asd);
-		if (ret < 0)
-			return ret;
-	}
+	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
+	if (ret < 0)
+		return ret;
 
 	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
 	if (ret < 0) {
-		if (notifier->ops->unbind)
-			notifier->ops->unbind(notifier, sd, asd);
+		v4l2_async_notifier_call_unbind(notifier, sd, asd);
 		return ret;
 	}
 
@@ -140,8 +165,7 @@ static void v4l2_async_notifier_unbind_all_subdevs(
 	struct v4l2_subdev *sd, *tmp;
 
 	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
-		if (notifier->ops->unbind)
-			notifier->ops->unbind(notifier, sd, sd->asd);
+		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
 		v4l2_async_cleanup(sd);
 
 		list_move(&sd->async_list, &subdev_list);
@@ -198,8 +222,8 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 		}
 	}
 
-	if (list_empty(&notifier->waiting) && notifier->ops->complete) {
-		ret = notifier->ops->complete(notifier);
+	if (list_empty(&notifier->waiting)) {
+		ret = v4l2_async_notifier_call_complete(notifier);
 		if (ret)
 			goto err_complete;
 	}
@@ -296,10 +320,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 		if (ret)
 			goto err_unlock;
 
-		if (!list_empty(&notifier->waiting) || !notifier->ops->complete)
+		if (!list_empty(&notifier->waiting))
 			goto out_unlock;
 
-		ret = notifier->ops->complete(notifier);
+		ret = v4l2_async_notifier_call_complete(notifier);
 		if (ret)
 			goto err_cleanup;
 
@@ -315,8 +339,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 	return 0;
 
 err_cleanup:
-	if (notifier->ops->unbind)
-		notifier->ops->unbind(notifier, sd, sd->asd);
+	v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
 	v4l2_async_cleanup(sd);
 
 err_unlock:
@@ -335,8 +358,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 
 		list_add(&sd->asd->list, &notifier->waiting);
 
-		if (notifier->ops->unbind)
-			notifier->ops->unbind(notifier, sd, sd->asd);
+		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
 	}
 
 	v4l2_async_cleanup(sd);
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 15/32] v4l: async: Register sub-devices before calling bound callback
  2017-10-26  7:53 ` Sakari Ailus
                   ` (12 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
       [not found]   ` <20171026075342.5760-16-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
  2017-10-27 14:49   ` Sebastian Reichel
  -1 siblings, 2 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Register the sub-device before calling the notifier's bound callback.
Doing this the other way around is problematic as the struct v4l2_device
has not assigned for the sub-device yet and may be required by the bound
callback.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 drivers/media/v4l2-core/v4l2-async.c | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index e170682dae78..46db85685894 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -130,13 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 {
 	int ret;
 
-	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
+	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
 	if (ret < 0)
 		return ret;
 
-	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
+	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
 	if (ret < 0) {
-		v4l2_async_notifier_call_unbind(notifier, sd, asd);
+		v4l2_device_unregister_subdev(sd);
 		return ret;
 	}
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 16/32] v4l: async: Allow async notifier register call succeed with no subdevs
  2017-10-26  7:53 ` Sakari Ailus
                   ` (13 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
       [not found]   ` <20171026075342.5760-17-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

The information on how many async sub-devices would be bindable to a
notifier is typically dependent on information from platform firmware and
it's not driver's business to be aware of that.

Many V4L2 main drivers are perfectly usable (and useful) without async
sub-devices and so if there aren't any around, just proceed call the
notifier's complete callback immediately without registering the notifier
itself.

If a driver needs to check whether there are async sub-devices available,
it can be done by inspecting the notifier's num_subdevs field which tells
the number of async sub-devices.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 46db85685894..1b536d68cedf 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -180,14 +180,22 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 	int ret;
 	int i;
 
-	if (!v4l2_dev || !notifier->num_subdevs ||
-	    notifier->num_subdevs > V4L2_MAX_SUBDEVS)
+	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
 		return -EINVAL;
 
 	notifier->v4l2_dev = v4l2_dev;
 	INIT_LIST_HEAD(&notifier->waiting);
 	INIT_LIST_HEAD(&notifier->done);
 
+	if (!notifier->num_subdevs) {
+		int ret;
+
+		ret = v4l2_async_notifier_call_complete(notifier);
+		notifier->v4l2_dev = NULL;
+
+		return ret;
+	}
+
 	for (i = 0; i < notifier->num_subdevs; i++) {
 		asd = notifier->subdevs[i];
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 17/32] v4l: async: Prepare for async sub-device notifiers
  2017-10-26  7:53 ` Sakari Ailus
                   ` (14 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-26 22:10   ` Niklas Söderlund
  2017-10-27  8:26   ` [PATCH v16.1 " Sakari Ailus
  -1 siblings, 2 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Refactor the V4L2 async framework a little in preparation for async
sub-device notifiers. This avoids making some structural changes in the
patch actually implementing sub-device notifiers, making that patch easier
to review.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 71 ++++++++++++++++++++++++++----------
 1 file changed, 52 insertions(+), 19 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 1b536d68cedf..eb31d96254d1 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
 }
 
 static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
+				   struct v4l2_device *v4l2_dev,
 				   struct v4l2_subdev *sd,
 				   struct v4l2_async_subdev *asd)
 {
 	int ret;
 
-	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
+	ret = v4l2_device_register_subdev(v4l2_dev, sd);
 	if (ret < 0)
 		return ret;
 
@@ -151,6 +152,31 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 	return 0;
 }
 
+/* Test all async sub-devices in a notifier for a match. */
+static int v4l2_async_notifier_try_all_subdevs(
+	struct v4l2_async_notifier *notifier)
+{
+	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
+	struct v4l2_subdev *sd, *tmp;
+
+	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
+		struct v4l2_async_subdev *asd;
+		int ret;
+
+		asd = v4l2_async_find_match(notifier, sd);
+		if (!asd)
+			continue;
+
+		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
+		if (ret < 0) {
+			mutex_unlock(&list_lock);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+
 static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 {
 	v4l2_device_unregister_subdev(sd);
@@ -172,18 +198,15 @@ static void v4l2_async_notifier_unbind_all_subdevs(
 	}
 }
 
-int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
-				 struct v4l2_async_notifier *notifier)
+static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 {
-	struct v4l2_subdev *sd, *tmp;
 	struct v4l2_async_subdev *asd;
 	int ret;
 	int i;
 
-	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
+	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
 		return -EINVAL;
 
-	notifier->v4l2_dev = v4l2_dev;
 	INIT_LIST_HEAD(&notifier->waiting);
 	INIT_LIST_HEAD(&notifier->done);
 
@@ -216,18 +239,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 
 	mutex_lock(&list_lock);
 
-	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
-		int ret;
-
-		asd = v4l2_async_find_match(notifier, sd);
-		if (!asd)
-			continue;
-
-		ret = v4l2_async_match_notify(notifier, sd, asd);
-		if (ret < 0) {
-			mutex_unlock(&list_lock);
-			return ret;
-		}
+	ret = v4l2_async_notifier_try_all_subdevs(notifier);
+	if (ret) {
+		mutex_unlock(&list_lock);
+		return ret;
 	}
 
 	if (list_empty(&notifier->waiting)) {
@@ -250,6 +265,23 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 
 	return ret;
 }
+
+int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
+				 struct v4l2_async_notifier *notifier)
+{
+	int ret;
+
+	if (WARN_ON(!v4l2_dev))
+		return -EINVAL;
+
+	notifier->v4l2_dev = v4l2_dev;
+
+	ret = __v4l2_async_notifier_register(notifier);
+	if (ret)
+		notifier->v4l2_dev = NULL;
+
+	return ret;
+}
 EXPORT_SYMBOL(v4l2_async_notifier_register);
 
 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
@@ -324,7 +356,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 		if (!asd)
 			continue;
 
-		ret = v4l2_async_match_notify(notifier, sd, asd);
+		ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd,
+					      asd);
 		if (ret)
 			goto err_unlock;
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 18/32] v4l: async: Allow binding notifiers to sub-devices
  2017-10-26  7:53 ` Sakari Ailus
                   ` (15 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-27  8:27   ` [PATCH v16.1 " Sakari Ailus
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Registering a notifier has required the knowledge of struct v4l2_device
for the reason that sub-devices generally are registered to the
v4l2_device (as well as the media device, also available through
v4l2_device).

This information is not available for sub-device drivers at probe time.

What this patch does is that it allows registering notifiers without
having v4l2_device around. Instead the sub-device pointer is stored in the
notifier. Once the sub-device of the driver that registered the notifier
is registered, the notifier will gain the knowledge of the v4l2_device,
and the binding of async sub-devices from the sub-device driver's notifier
may proceed.

The complete callback of the root notifier will be called only when the
v4l2_device is available and no notifier has pending sub-devices to bind.
No complete callbacks are supported for sub-device notifiers.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 216 ++++++++++++++++++++++++++++-------
 include/media/v4l2-async.h           |  19 ++-
 2 files changed, 190 insertions(+), 45 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index eb31d96254d1..ed539c4fd5dc 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -124,11 +124,87 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
 	return NULL;
 }
 
+/* Find the sub-device notifier registered by a sub-device driver. */
+static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier(
+	struct v4l2_subdev *sd)
+{
+	struct v4l2_async_notifier *n;
+
+	list_for_each_entry(n, &notifier_list, list)
+		if (n->sd == sd)
+			return n;
+
+	return NULL;
+}
+
+/* Get v4l2_device related to the notifier if one can be found. */
+static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev(
+	struct v4l2_async_notifier *notifier)
+{
+	while (notifier->parent)
+		notifier = notifier->parent;
+
+	return notifier->v4l2_dev;
+}
+
+/*
+ * Return true if all child sub-device notifiers are complete, false otherwise.
+ */
+static bool v4l2_async_notifier_can_complete(
+	struct v4l2_async_notifier *notifier)
+{
+	struct v4l2_subdev *sd;
+
+	if (!list_empty(&notifier->waiting))
+		return false;
+
+	list_for_each_entry(sd, &notifier->done, async_list) {
+		struct v4l2_async_notifier *subdev_notifier =
+			v4l2_async_find_subdev_notifier(sd);
+
+		if (subdev_notifier &&
+		    !v4l2_async_notifier_can_complete(subdev_notifier))
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * Complete the master notifier if possible. This is done when all async
+ * sub-devices have been bound; v4l2_device is also available then.
+ */
+static int v4l2_async_notifier_try_complete(
+	struct v4l2_async_notifier *notifier)
+{
+	/* Quick check whether there are still more sub-devices here. */
+	if (!list_empty(&notifier->waiting))
+		return 0;
+
+	/* Check the entire notifier tree; find the root notifier first. */
+	while (notifier->parent)
+		notifier = notifier->parent;
+
+	/* This is root if it has v4l2_dev. */
+	if (!notifier->v4l2_dev)
+		return 0;
+
+	/* Is everything ready? */
+	if (!v4l2_async_notifier_can_complete(notifier))
+		return 0;
+
+	return v4l2_async_notifier_call_complete(notifier);
+}
+
+static int v4l2_async_notifier_try_all_subdevs(
+	struct v4l2_async_notifier *notifier);
+
 static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 				   struct v4l2_device *v4l2_dev,
 				   struct v4l2_subdev *sd,
 				   struct v4l2_async_subdev *asd)
 {
+	struct v4l2_async_notifier *subdev_notifier;
 	int ret;
 
 	ret = v4l2_device_register_subdev(v4l2_dev, sd);
@@ -149,17 +225,36 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 	/* Move from the global subdevice list to notifier's done */
 	list_move(&sd->async_list, &notifier->done);
 
-	return 0;
+	/*
+	 * See if the sub-device has a notifier. If not, return here.
+	 */
+	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
+	if (!subdev_notifier || subdev_notifier->parent)
+		return 0;
+
+	/*
+	 * Proceed with checking for the sub-device notifier's async
+	 * sub-devices, and return the result. The error will be handled by the
+	 * caller.
+	 */
+	subdev_notifier->parent = notifier;
+
+	return v4l2_async_notifier_try_all_subdevs(subdev_notifier);
 }
 
 /* Test all async sub-devices in a notifier for a match. */
 static int v4l2_async_notifier_try_all_subdevs(
 	struct v4l2_async_notifier *notifier)
 {
-	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
-	struct v4l2_subdev *sd, *tmp;
+	struct v4l2_device *v4l2_dev =
+		v4l2_async_notifier_find_v4l2_dev(notifier);
+	struct v4l2_subdev *sd;
 
-	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
+	if (!v4l2_dev)
+		return 0;
+
+again:
+	list_for_each_entry(sd, &subdev_list, async_list) {
 		struct v4l2_async_subdev *asd;
 		int ret;
 
@@ -168,10 +263,16 @@ static int v4l2_async_notifier_try_all_subdevs(
 			continue;
 
 		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
-		if (ret < 0) {
-			mutex_unlock(&list_lock);
+		if (ret < 0)
 			return ret;
-		}
+
+		/*
+		 * v4l2_async_match_notify() may lead to registering a
+		 * new notifier and thus changing the async subdevs
+		 * list. In order to proceed safely from here, restart
+		 * parsing the list from the beginning.
+		 */
+		goto again;
 	}
 
 	return 0;
@@ -185,17 +286,26 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 	sd->asd = NULL;
 }
 
+/* Unbind all sub-devices in the notifier tree. */
 static void v4l2_async_notifier_unbind_all_subdevs(
 	struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_subdev *sd, *tmp;
 
 	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
+		struct v4l2_async_notifier *subdev_notifier =
+			v4l2_async_find_subdev_notifier(sd);
+
+		if (subdev_notifier)
+			v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
+
 		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
 		v4l2_async_cleanup(sd);
 
 		list_move(&sd->async_list, &subdev_list);
 	}
+
+	notifier->parent = NULL;
 }
 
 static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
@@ -210,15 +320,6 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	INIT_LIST_HEAD(&notifier->waiting);
 	INIT_LIST_HEAD(&notifier->done);
 
-	if (!notifier->num_subdevs) {
-		int ret;
-
-		ret = v4l2_async_notifier_call_complete(notifier);
-		notifier->v4l2_dev = NULL;
-
-		return ret;
-	}
-
 	for (i = 0; i < notifier->num_subdevs; i++) {
 		asd = notifier->subdevs[i];
 
@@ -240,16 +341,12 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	mutex_lock(&list_lock);
 
 	ret = v4l2_async_notifier_try_all_subdevs(notifier);
-	if (ret) {
-		mutex_unlock(&list_lock);
-		return ret;
-	}
+	if (ret)
+		goto err_unbind;
 
-	if (list_empty(&notifier->waiting)) {
-		ret = v4l2_async_notifier_call_complete(notifier);
-		if (ret)
-			goto err_complete;
-	}
+	ret = v4l2_async_notifier_try_complete(notifier);
+	if (ret)
+		goto err_unbind;
 
 	/* Keep also completed notifiers on the list */
 	list_add(&notifier->list, &notifier_list);
@@ -258,7 +355,10 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 
 	return 0;
 
-err_complete:
+err_unbind:
+	/*
+	 * On failure, unbind all sub-devices registered through this notifier.
+	 */
 	v4l2_async_notifier_unbind_all_subdevs(notifier);
 
 	mutex_unlock(&list_lock);
@@ -271,7 +371,7 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 {
 	int ret;
 
-	if (WARN_ON(!v4l2_dev))
+	if (WARN_ON(!v4l2_dev || notifier->sd))
 		return -EINVAL;
 
 	notifier->v4l2_dev = v4l2_dev;
@@ -284,20 +384,39 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 }
 EXPORT_SYMBOL(v4l2_async_notifier_register);
 
+int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
+					struct v4l2_async_notifier *notifier)
+{
+	int ret;
+
+	if (WARN_ON(!sd || notifier->v4l2_dev))
+		return -EINVAL;
+
+	notifier->sd = sd;
+
+	ret = __v4l2_async_notifier_register(notifier);
+	if (ret)
+		notifier->sd = NULL;
+
+	return ret;
+}
+EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
+
 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 {
-	if (!notifier->v4l2_dev)
+	if (!notifier->v4l2_dev && !notifier->sd)
 		return;
 
 	mutex_lock(&list_lock);
 
-	list_del(&notifier->list);
-
 	v4l2_async_notifier_unbind_all_subdevs(notifier);
 
-	mutex_unlock(&list_lock);
-
+	notifier->sd = NULL;
 	notifier->v4l2_dev = NULL;
+
+	list_del(&notifier->list);
+
+	mutex_unlock(&list_lock);
 }
 EXPORT_SYMBOL(v4l2_async_notifier_unregister);
 
@@ -333,6 +452,7 @@ EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
 
 int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 {
+	struct v4l2_async_notifier *subdev_notifier;
 	struct v4l2_async_notifier *notifier;
 	int ret;
 
@@ -349,24 +469,26 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 	INIT_LIST_HEAD(&sd->async_list);
 
 	list_for_each_entry(notifier, &notifier_list, list) {
-		struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
-								      sd);
+		struct v4l2_device *v4l2_dev =
+			v4l2_async_notifier_find_v4l2_dev(notifier);
+		struct v4l2_async_subdev *asd;
 		int ret;
 
+		if (!v4l2_dev)
+			continue;
+
+		asd = v4l2_async_find_match(notifier, sd);
 		if (!asd)
 			continue;
 
 		ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd,
 					      asd);
 		if (ret)
-			goto err_unlock;
-
-		if (!list_empty(&notifier->waiting))
-			goto out_unlock;
+			goto err_unbind;
 
-		ret = v4l2_async_notifier_call_complete(notifier);
+		ret = v4l2_async_notifier_try_complete(notifier);
 		if (ret)
-			goto err_cleanup;
+			goto err_unbind;
 
 		goto out_unlock;
 	}
@@ -379,11 +501,19 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 
 	return 0;
 
-err_cleanup:
-	v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
+err_unbind:
+	/*
+	 * Complete failed. Unbind the sub-devices bound through registering
+	 * this async sub-device.
+	 */
+	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
+	if (subdev_notifier)
+		v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
+
+	if (sd->asd)
+		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
 	v4l2_async_cleanup(sd);
 
-err_unlock:
 	mutex_unlock(&list_lock);
 
 	return ret;
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 68606afb5ef9..17c4ac7c73e8 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -82,7 +82,8 @@ struct v4l2_async_subdev {
 /**
  * struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations
  * @bound:	a subdevice driver has successfully probed one of the subdevices
- * @complete:	all subdevices have been probed successfully
+ * @complete:	All subdevices have been probed successfully. The complete
+ *		callback is only executed for the root notifier.
  * @unbind:	a subdevice is leaving
  */
 struct v4l2_async_notifier_operations {
@@ -102,7 +103,9 @@ struct v4l2_async_notifier_operations {
  * @num_subdevs: number of subdevices used in the subdevs array
  * @max_subdevs: number of subdevices allocated in the subdevs array
  * @subdevs:	array of pointers to subdevice descriptors
- * @v4l2_dev:	pointer to struct v4l2_device
+ * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
+ * @sd:		sub-device that registered the notifier, NULL otherwise
+ * @parent:	parent notifier
  * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
  * @done:	list of struct v4l2_subdev, already probed
  * @list:	member in a global list of notifiers
@@ -113,6 +116,8 @@ struct v4l2_async_notifier {
 	unsigned int max_subdevs;
 	struct v4l2_async_subdev **subdevs;
 	struct v4l2_device *v4l2_dev;
+	struct v4l2_subdev *sd;
+	struct v4l2_async_notifier *parent;
 	struct list_head waiting;
 	struct list_head done;
 	struct list_head list;
@@ -128,6 +133,16 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 				 struct v4l2_async_notifier *notifier);
 
 /**
+ * v4l2_async_subdev_notifier_register - registers a subdevice asynchronous
+ *					 notifier for a sub-device
+ *
+ * @sd: pointer to &struct v4l2_subdev
+ * @notifier: pointer to &struct v4l2_async_notifier
+ */
+int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
+					struct v4l2_async_notifier *notifier);
+
+/**
  * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier
  *
  * @notifier: pointer to &struct v4l2_async_notifier
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers
  2017-10-26  7:53 ` Sakari Ailus
                   ` (16 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-27  9:52   ` Niklas Söderlund
  2017-10-27 10:53   ` [PATCH v16.1 " Sakari Ailus
  -1 siblings, 2 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

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>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 82 +++++++++++++++++++++++++++++++++---
 1 file changed, 77 insertions(+), 5 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index ed539c4fd5dc..b4e88eef195f 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -308,8 +308,71 @@ static void v4l2_async_notifier_unbind_all_subdevs(
 	notifier->parent = NULL;
 }
 
+/* See if an fwnode can be found in a notifier's lists. */
+static bool __v4l2_async_notifier_fwnode_has_async_subdev(
+	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
+{
+	struct v4l2_async_subdev *asd;
+	struct v4l2_subdev *sd;
+
+	list_for_each_entry(asd, &notifier->waiting, list) {
+		if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
+			continue;
+
+		if (asd->match.fwnode.fwnode == fwnode)
+			return true;
+	}
+
+	list_for_each_entry(sd, &notifier->done, async_list) {
+		if (WARN_ON(!sd->asd))
+			continue;
+
+		if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
+			continue;
+
+		if (sd->asd->match.fwnode.fwnode == fwnode)
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * Find out whether an async sub-device was set up for an fwnode already or
+ * whether it exists in a given notifier before @this_index.
+ */
+static bool v4l2_async_notifier_fwnode_has_async_subdev(
+	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
+	unsigned int this_index)
+{
+	unsigned int j;
+
+	lockdep_assert_held(&list_lock);
+
+	/* Check that an fwnode is not being added more than once. */
+	for (j = 0; j < this_index; j++) {
+		struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
+		struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
+
+		if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
+		    asd->match.fwnode.fwnode ==
+		    other_asd->match.fwnode.fwnode)
+			return true;
+	}
+
+	/* Check than an fwnode did not exist in other notifiers. */
+	list_for_each_entry(notifier, &notifier_list, list)
+		if (__v4l2_async_notifier_fwnode_has_async_subdev(
+			    notifier, fwnode))
+			return true;
+
+	return false;
+}
+
 static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 {
+	struct device *dev =
+		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
 	struct v4l2_async_subdev *asd;
 	int ret;
 	int i;
@@ -320,6 +383,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	INIT_LIST_HEAD(&notifier->waiting);
 	INIT_LIST_HEAD(&notifier->done);
 
+	mutex_lock(&list_lock);
+
 	for (i = 0; i < notifier->num_subdevs; i++) {
 		asd = notifier->subdevs[i];
 
@@ -327,19 +392,25 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 		case V4L2_ASYNC_MATCH_CUSTOM:
 		case V4L2_ASYNC_MATCH_DEVNAME:
 		case V4L2_ASYNC_MATCH_I2C:
+			break;
 		case V4L2_ASYNC_MATCH_FWNODE:
+			if (v4l2_async_notifier_fwnode_has_async_subdev(
+				    notifier, asd->match.fwnode.fwnode, i)) {
+				dev_err(dev,
+					"fwnode has already been registered or in notifier's subdev list\n");
+				ret = -EEXIST;
+				goto out_unlock;
+			}
 			break;
 		default:
-			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
-				"Invalid match type %u on %p\n",
+			dev_err(dev, "Invalid match type %u on %p\n",
 				asd->match_type, asd);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out_unlock;
 		}
 		list_add_tail(&asd->list, &notifier->waiting);
 	}
 
-	mutex_lock(&list_lock);
-
 	ret = v4l2_async_notifier_try_all_subdevs(notifier);
 	if (ret)
 		goto err_unbind;
@@ -351,6 +422,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	/* Keep also completed notifiers on the list */
 	list_add(&notifier->list, &notifier_list);
 
+out_unlock:
 	mutex_unlock(&list_lock);
 
 	return 0;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 20/32] dt: bindings: Add a binding for flash LED devices associated to a sensor
  2017-10-26  7:53 ` Sakari Ailus
                   ` (17 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
       [not found]   ` <20171026075342.5760-21-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree, Rob Herring

Camera flash drivers (and LEDs) are separate from the sensor devices in
DT. In order to make an association between the two, provide the
association information to the software.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Cc: Rob Herring <robh@kernel.org>
Cc: devicetree@vger.kernel.org
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
Acked-by: Rob Herring <robh@kernel.org>
---
 Documentation/devicetree/bindings/media/video-interfaces.txt | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt
index bd6474920510..dc66e3224692 100644
--- a/Documentation/devicetree/bindings/media/video-interfaces.txt
+++ b/Documentation/devicetree/bindings/media/video-interfaces.txt
@@ -76,6 +76,14 @@ are required in a relevant parent node:
 		    identifier, should be 1.
  - #size-cells    : should be zero.
 
+
+Optional properties
+-------------------
+
+- flash-leds: An array of phandles, each referring to a flash LED, a sub-node
+  of the LED driver device node.
+
+
 Optional endpoint properties
 ----------------------------
 
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 21/32] dt: bindings: Add lens-focus binding for image sensors
  2017-10-26  7:53 ` Sakari Ailus
                   ` (18 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree, Rob Herring

The lens-focus property contains a phandle to the lens voice coil driver
that is associated to the sensor; typically both are contained in the same
camera module.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Cc: Rob Herring <robh@kernel.org>
Cc: devicetree@vger.kernel.org
Acked-by: Pavel Machek <pavel@ucw.cz>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
Acked-by: Rob Herring <robh@kernel.org>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 Documentation/devicetree/bindings/media/video-interfaces.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt
index dc66e3224692..3994b0143dd1 100644
--- a/Documentation/devicetree/bindings/media/video-interfaces.txt
+++ b/Documentation/devicetree/bindings/media/video-interfaces.txt
@@ -83,6 +83,8 @@ Optional properties
 - flash-leds: An array of phandles, each referring to a flash LED, a sub-node
   of the LED driver device node.
 
+- lens-focus: A phandle to the node of the focus lens controller.
+
 
 Optional endpoint properties
 ----------------------------
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 22/32] v4l: fwnode: Move KernelDoc documentation to the header
  2017-10-26  7:53 ` Sakari Ailus
                   ` (19 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-29 22:28   ` Sebastian Reichel
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

In V4L2 the practice is to have the KernelDoc documentation in the header
and not in .c source code files. This consequently makes the V4L2 fwnode
function documentation part of the Media documentation build.

Also correct the link related function and argument naming in
documentation and add an asterisk to v4l2_fwnode_endpoint_free()
documentation to make it proper KernelDoc documentation.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 drivers/media/v4l2-core/v4l2-fwnode.c | 75 --------------------------------
 include/media/v4l2-fwnode.h           | 81 ++++++++++++++++++++++++++++++++++-
 2 files changed, 80 insertions(+), 76 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index df0695b7bbcc..65bdcd59744a 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -183,25 +183,6 @@ v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
 		vep->bus_type = V4L2_MBUS_CSI1;
 }
 
-/**
- * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
- * @fwnode: pointer to the endpoint's fwnode handle
- * @vep: pointer to the V4L2 fwnode data structure
- *
- * All properties are optional. If none are found, we don't set any flags. This
- * means the port has a static configuration and no properties have to be
- * specified explicitly. If any properties that identify the bus as parallel
- * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
- * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
- * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
- * reference to @fwnode.
- *
- * NOTE: This function does not parse properties the size of which is variable
- * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in
- * new drivers instead.
- *
- * Return: 0 on success or a negative error code on failure.
- */
 int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
 			       struct v4l2_fwnode_endpoint *vep)
 {
@@ -241,14 +222,6 @@ int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
 
-/*
- * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by
- * v4l2_fwnode_endpoint_alloc_parse()
- * @vep - the V4L2 fwnode the resources of which are to be released
- *
- * It is safe to call this function with NULL argument or on a V4L2 fwnode the
- * parsing of which failed.
- */
 void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
 {
 	if (IS_ERR_OR_NULL(vep))
@@ -259,29 +232,6 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
 
-/**
- * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
- * @fwnode: pointer to the endpoint's fwnode handle
- *
- * All properties are optional. If none are found, we don't set any flags. This
- * means the port has a static configuration and no properties have to be
- * specified explicitly. If any properties that identify the bus as parallel
- * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
- * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
- * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
- * reference to @fwnode.
- *
- * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
- * v4l2_fwnode_endpoint_parse():
- *
- * 1. It also parses variable size data.
- *
- * 2. The memory it has allocated to store the variable size data must be freed
- *    using v4l2_fwnode_endpoint_free() when no longer needed.
- *
- * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer
- * on error.
- */
 struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
 	struct fwnode_handle *fwnode)
 {
@@ -324,24 +274,6 @@ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
 
-/**
- * v4l2_fwnode_endpoint_parse_link() - parse a link between two endpoints
- * @__fwnode: pointer to the endpoint's fwnode at the local end of the link
- * @link: pointer to the V4L2 fwnode link data structure
- *
- * Fill the link structure with the local and remote nodes and port numbers.
- * The local_node and remote_node fields are set to point to the local and
- * remote port's parent nodes respectively (the port parent node being the
- * parent node of the port node if that node isn't a 'ports' node, or the
- * grand-parent node of the port node otherwise).
- *
- * A reference is taken to both the local and remote nodes, the caller must use
- * v4l2_fwnode_endpoint_put_link() to drop the references when done with the
- * link.
- *
- * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be
- * found.
- */
 int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
 			   struct v4l2_fwnode_link *link)
 {
@@ -376,13 +308,6 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
 }
 EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
 
-/**
- * v4l2_fwnode_put_link() - drop references to nodes in a link
- * @link: pointer to the V4L2 fwnode link data structure
- *
- * Drop references to the local and remote nodes in the link. This function
- * must be called on every link parsed with v4l2_fwnode_parse_link().
- */
 void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
 {
 	fwnode_handle_put(link->local_node);
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index ac605af9b877..105cfeee44ef 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -115,13 +115,92 @@ struct v4l2_fwnode_link {
 	unsigned int remote_port;
 };
 
+/**
+ * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
+ * @fwnode: pointer to the endpoint's fwnode handle
+ * @vep: pointer to the V4L2 fwnode data structure
+ *
+ * All properties are optional. If none are found, we don't set any flags. This
+ * means the port has a static configuration and no properties have to be
+ * specified explicitly. If any properties that identify the bus as parallel
+ * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
+ * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
+ * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
+ * reference to @fwnode.
+ *
+ * NOTE: This function does not parse properties the size of which is variable
+ * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in
+ * new drivers instead.
+ *
+ * Return: 0 on success or a negative error code on failure.
+ */
 int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
 			       struct v4l2_fwnode_endpoint *vep);
+
+/**
+ * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by
+ * v4l2_fwnode_endpoint_alloc_parse()
+ * @vep: the V4L2 fwnode the resources of which are to be released
+ *
+ * It is safe to call this function with NULL argument or on a V4L2 fwnode the
+ * parsing of which failed.
+ */
+void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
+
+/**
+ * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
+ * @fwnode: pointer to the endpoint's fwnode handle
+ *
+ * All properties are optional. If none are found, we don't set any flags. This
+ * means the port has a static configuration and no properties have to be
+ * specified explicitly. If any properties that identify the bus as parallel
+ * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
+ * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
+ * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
+ * reference to @fwnode.
+ *
+ * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
+ * v4l2_fwnode_endpoint_parse():
+ *
+ * 1. It also parses variable size data.
+ *
+ * 2. The memory it has allocated to store the variable size data must be freed
+ *    using v4l2_fwnode_endpoint_free() when no longer needed.
+ *
+ * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer
+ * on error.
+ */
 struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
 	struct fwnode_handle *fwnode);
-void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
+
+/**
+ * v4l2_fwnode_parse_link() - parse a link between two endpoints
+ * @fwnode: pointer to the endpoint's fwnode at the local end of the link
+ * @link: pointer to the V4L2 fwnode link data structure
+ *
+ * Fill the link structure with the local and remote nodes and port numbers.
+ * The local_node and remote_node fields are set to point to the local and
+ * remote port's parent nodes respectively (the port parent node being the
+ * parent node of the port node if that node isn't a 'ports' node, or the
+ * grand-parent node of the port node otherwise).
+ *
+ * A reference is taken to both the local and remote nodes, the caller must use
+ * v4l2_fwnode_put_link() to drop the references when done with the
+ * link.
+ *
+ * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be
+ * found.
+ */
 int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
 			   struct v4l2_fwnode_link *link);
+
+/**
+ * v4l2_fwnode_put_link() - drop references to nodes in a link
+ * @link: pointer to the V4L2 fwnode link data structure
+ *
+ * Drop references to the local and remote nodes in the link. This function
+ * must be called on every link parsed with v4l2_fwnode_parse_link().
+ */
 void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
 
 /**
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 23/32] v4l: fwnode: Add a helper function for parsing generic references
  2017-10-26  7:53 ` Sakari Ailus
                   ` (20 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-27 10:30   ` Niklas Söderlund
  2017-10-29 22:53   ` Sebastian Reichel
  -1 siblings, 2 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Add function v4l2_fwnode_reference_parse() for parsing them as async
sub-devices. This can be done on e.g. flash or lens async sub-devices that
are not part of but are associated with a sensor.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-fwnode.c | 69 +++++++++++++++++++++++++++++++++++
 1 file changed, 69 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 65bdcd59744a..edd2e8d983a1 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -509,6 +509,75 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
 }
 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
 
+/*
+ * v4l2_fwnode_reference_parse - parse references for async sub-devices
+ * @dev: the device node the properties of which are parsed for references
+ * @notifier: the async notifier where the async subdevs will be added
+ * @prop: the name of the property
+ *
+ * Return: 0 on success
+ *	   -ENOENT if no entries were found
+ *	   -ENOMEM if memory allocation failed
+ *	   -EINVAL if property parsing failed
+ */
+static int v4l2_fwnode_reference_parse(
+	struct device *dev, struct v4l2_async_notifier *notifier,
+	const char *prop)
+{
+	struct fwnode_reference_args args;
+	unsigned int index;
+	int ret;
+
+	for (index = 0;
+	     !(ret = fwnode_property_get_reference_args(
+		       dev_fwnode(dev), prop, NULL, 0, index, &args));
+	     index++)
+		fwnode_handle_put(args.fwnode);
+
+	if (!index)
+		return -ENOENT;
+
+	/*
+	 * Note that right now both -ENODATA and -ENOENT may signal
+	 * out-of-bounds access. Return the error in cases other than that.
+	 */
+	if (ret != -ENOENT && ret != -ENODATA)
+		return ret;
+
+	ret = v4l2_async_notifier_realloc(notifier,
+					  notifier->num_subdevs + index);
+	if (ret)
+		return ret;
+
+	for (index = 0; !fwnode_property_get_reference_args(
+		     dev_fwnode(dev), prop, NULL, 0, index, &args);
+	     index++) {
+		struct v4l2_async_subdev *asd;
+
+		if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
+			ret = -EINVAL;
+			goto error;
+		}
+
+		asd = kzalloc(sizeof(*asd), GFP_KERNEL);
+		if (!asd) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		notifier->subdevs[notifier->num_subdevs] = asd;
+		asd->match.fwnode.fwnode = args.fwnode;
+		asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+		notifier->num_subdevs++;
+	}
+
+	return 0;
+
+error:
+	fwnode_handle_put(args.fwnode);
+	return ret;
+}
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 24/32] v4l: fwnode: Add a helper function to obtain device / integer references
  2017-10-26  7:53 ` Sakari Ailus
                   ` (21 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-26 15:01   ` [PATCH v16.1 " Sakari Ailus
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

v4l2_fwnode_reference_parse_int_prop() will find an fwnode such that under
the device's own fwnode, it will follow child fwnodes with the given
property-value pair and return the resulting fwnode.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-fwnode.c | 287 ++++++++++++++++++++++++++++++++++
 1 file changed, 287 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index edd2e8d983a1..845ef8da9002 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -578,6 +578,293 @@ static int v4l2_fwnode_reference_parse(
 	return ret;
 }
 
+/*
+ * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
+ *					arguments
+ * @fwnode: fwnode to read @prop from
+ * @notifier: notifier for @dev
+ * @prop: the name of the property
+ * @index: the index of the reference to get
+ * @props: the array of integer property names
+ * @nprops: the number of integer property names in @nprops
+ *
+ * First find an fwnode referred to by the reference at @index in @prop.
+ *
+ * Then under that fwnode, @nprops times, for each property in @props,
+ * iteratively follow child nodes starting from fwnode such that they have the
+ * property in @props array at the index of the child node distance from the
+ * root node and the value of that property matching with the integer argument
+ * of the reference, at the same index.
+ *
+ * The child fwnode reched at the end of the iteration is then returned to the
+ * caller.
+ *
+ * The core reason for this is that you cannot refer to just any node in ACPI.
+ * So to refer to an endpoint (easy in DT) you need to refer to a device, then
+ * provide a list of (property name, property value) tuples where each tuple
+ * uniquely identifies a child node. The first tuple identifies a child directly
+ * underneath the device fwnode, the next tuple identifies a child node
+ * underneath the fwnode identified by the previous tuple, etc. until you
+ * reached the fwnode you need.
+ *
+ * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
+ *
+ *	Scope (\_SB.PCI0.I2C2)
+ *	{
+ *		Device (CAM0)
+ *		{
+ *			Name (_DSD, Package () {
+ *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ *				Package () {
+ *					Package () {
+ *						"compatible",
+ *						Package () { "nokia,smia" }
+ *					},
+ *				},
+ *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+ *				Package () {
+ *					Package () { "port0", "PRT0" },
+ *				}
+ *			})
+ *			Name (PRT0, Package() {
+ *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ *				Package () {
+ *					Package () { "port", 0 },
+ *				},
+ *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+ *				Package () {
+ *					Package () { "endpoint0", "EP00" },
+ *				}
+ *			})
+ *			Name (EP00, Package() {
+ *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ *				Package () {
+ *					Package () { "endpoint", 0 },
+ *					Package () {
+ *						"remote-endpoint",
+ *						Package() {
+ *							\_SB.PCI0.ISP, 4, 0
+ *						}
+ *					},
+ *				}
+ *			})
+ *		}
+ *	}
+ *
+ *	Scope (\_SB.PCI0)
+ *	{
+ *		Device (ISP)
+ *		{
+ *			Name (_DSD, Package () {
+ *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+ *				Package () {
+ *					Package () { "port4", "PRT4" },
+ *				}
+ *			})
+ *
+ *			Name (PRT4, Package() {
+ *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ *				Package () {
+ *					Package () { "port", 4 },
+ *				},
+ *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+ *				Package () {
+ *					Package () { "endpoint0", "EP40" },
+ *				}
+ *			})
+ *
+ *			Name (EP40, Package() {
+ *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ *				Package () {
+ *					Package () { "endpoint", 0 },
+ *					Package () {
+ *						"remote-endpoint",
+ *						Package () {
+ *							\_SB.PCI0.I2C2.CAM0,
+ *							0, 0
+ *						}
+ *					},
+ *				}
+ *			})
+ *		}
+ *	}
+ *
+ * From the EP40 node under ISP device, you could parse the graph remote
+ * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
+ *
+ *  @fwnode: fwnode referring to EP40 under ISP.
+ *  @prop: "remote-endpoint"
+ *  @index: 0
+ *  @props: "port", "endpoint"
+ *  @nprops: 2
+ *
+ * And you'd get back fwnode referring to EP00 under CAM0.
+ *
+ * The same works the other way around: if you use EP00 under CAM0 as the
+ * fwnode, you'll get fwnode referring to EP40 under ISP.
+ *
+ * The same example in DT syntax would look like this:
+ *
+ * cam: cam0 {
+ *	compatible = "nokia,smia";
+ *
+ *	port {
+ *		port = <0>;
+ *		endpoint {
+ *			endpoint = <0>;
+ *			remote-endpoint = <&isp 4 0>;
+ *		};
+ *	};
+ * };
+ *
+ * isp: isp {
+ *	ports {
+ *		port@4 {
+ *			port = <4>;
+ *			endpoint {
+ *				endpoint = <0>;
+ *				remote-endpoint = <&cam 0 0>;
+ *			};
+ *		};
+ *	};
+ * };
+ *
+ * Return: 0 on success
+ *	   -ENOENT if no entries (or the property itself) were found
+ *	   -EINVAL if property parsing otherwise failed
+ *	   -ENOMEM if memory allocation failed
+ */
+static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
+	struct fwnode_handle *fwnode, const char *prop, unsigned int index,
+	const char **props, unsigned int nprops)
+{
+	struct fwnode_reference_args fwnode_args;
+	unsigned int *args = fwnode_args.args;
+	struct fwnode_handle *child;
+	int ret;
+
+	/*
+	 * Obtain remote fwnode as well as the integer arguments.
+	 *
+	 * Note that right now both -ENODATA and -ENOENT may signal
+	 * out-of-bounds access. Return -ENOENT in that case.
+	 */
+	ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
+						 index, &fwnode_args);
+	if (ret)
+		return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
+
+	/*
+	 * Find a node in the tree under the referred fwnode corresponding to
+	 * the integer arguments.
+	 */
+	fwnode = fwnode_args.fwnode;
+	while (nprops--) {
+		u32 val;
+
+		/* Loop over all child nodes under fwnode. */
+		fwnode_for_each_child_node(fwnode, child) {
+			if (fwnode_property_read_u32(child, *props, &val))
+				continue;
+
+			/* Found property, see if its value matches. */
+			if (val == *args)
+				break;
+		}
+
+		fwnode_handle_put(fwnode);
+
+		/* No property found; return an error here. */
+		if (!child) {
+			fwnode = ERR_PTR(-ENOENT);
+			break;
+		}
+
+		props++;
+		args++;
+		fwnode = child;
+	}
+
+	return fwnode;
+}
+
+/*
+ * v4l2_fwnode_reference_parse_int_props - parse references for async
+ *					   sub-devices
+ * @dev: struct device pointer
+ * @notifier: notifier for @dev
+ * @prop: the name of the property
+ * @props: the array of integer property names
+ * @nprops: the number of integer properties
+ *
+ * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
+ * property @prop with integer arguments with child nodes matching in properties
+ * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
+ * accordingly.
+ *
+ * While it is technically possible to use this function on DT, it is only
+ * meaningful on ACPI. On Device tree you can refer to any node in the tree but
+ * on ACPI the references are limited to devices.
+ *
+ * Return: 0 on success
+ *	   -ENOENT if no entries (or the property itself) were found
+ *	   -EINVAL if property parsing otherwisefailed
+ *	   -ENOMEM if memory allocation failed
+ */
+static int v4l2_fwnode_reference_parse_int_props(
+	struct device *dev, struct v4l2_async_notifier *notifier,
+	const char *prop, const char **props, unsigned int nprops)
+{
+	struct fwnode_handle *fwnode;
+	unsigned int index;
+	int ret;
+
+	for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
+					 dev_fwnode(dev), prop, index, props,
+					 nprops))); index++)
+		fwnode_handle_put(fwnode);
+
+	/*
+	 * Note that right now both -ENODATA and -ENOENT may signal
+	 * out-of-bounds access. Return the error in cases other than that.
+	 */
+	if (PTR_ERR(fwnode) != -ENOENT && PTR_ERR(fwnode) != -ENODATA)
+		return PTR_ERR(fwnode);
+
+	ret = v4l2_async_notifier_realloc(notifier,
+					  notifier->num_subdevs + index);
+	if (ret)
+		return -ENOMEM;
+
+	for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
+					 dev_fwnode(dev), prop, index, props,
+					 nprops))); index++) {
+		struct v4l2_async_subdev *asd;
+
+		if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
+			ret = -EINVAL;
+			goto error;
+		}
+
+		asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL);
+		if (!asd) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		notifier->subdevs[notifier->num_subdevs] = asd;
+		asd->match.fwnode.fwnode = fwnode;
+		asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+		notifier->num_subdevs++;
+	}
+
+	return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
+
+error:
+	fwnode_handle_put(fwnode);
+	return ret;
+}
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 25/32] v4l: fwnode: Add convenience function for parsing common external refs
  2017-10-26  7:53 ` Sakari Ailus
                   ` (22 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-26 15:03   ` [PATCH v16.1 " Sakari Ailus
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Add v4l2_fwnode_parse_reference_sensor_common for parsing common
sensor properties that refer to adjacent devices such as flash or lens
driver chips.

As this is an association only, there's little a regular driver needs to
know about these devices as such.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 drivers/media/v4l2-core/v4l2-fwnode.c | 35 +++++++++++++++++++++++++++++++++++
 include/media/v4l2-async.h            |  3 ++-
 include/media/v4l2-fwnode.h           | 21 +++++++++++++++++++++
 3 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 845ef8da9002..1234bd1a2f49 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -865,6 +865,41 @@ static int v4l2_fwnode_reference_parse_int_props(
 	return ret;
 }
 
+int v4l2_async_notifier_parse_fwnode_sensor_common(
+	struct device *dev, struct v4l2_async_notifier *notifier)
+{
+	static const char * const led_props[] = { "led" };
+	static const struct {
+		const char * const name;
+		const char **props;
+		unsigned int nprops;
+	} props[] = {
+		{ "flash-leds", led_props, ARRAY_SIZE(led_props) },
+		{ "lens-focus", NULL, 0 },
+	};
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(props); i++) {
+		int ret;
+
+		if (props[i].props && is_acpi_node(dev_fwnode(dev)))
+			ret = v4l2_fwnode_reference_parse_int_props(
+				dev, notifier, props[i].name,
+				props[i].props, props[i].nprops);
+		else
+			ret = v4l2_fwnode_reference_parse(
+				dev, notifier, props[i].name);
+		if (ret && ret != -ENOENT) {
+			dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
+				 props[i].name, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 17c4ac7c73e8..8d8cfc3f3100 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -156,7 +156,8 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
  * Release memory resources related to a notifier, including the async
  * sub-devices allocated for the purposes of the notifier but not the notifier
  * itself. The user is responsible for calling this function to clean up the
- * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints.
+ * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints or
+ * @v4l2_fwnode_reference_parse_sensor_common.
  *
  * There is no harm from calling v4l2_async_notifier_cleanup in other
  * cases as long as its memory has been zeroed after it has been
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 105cfeee44ef..ca50108dfd8f 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -319,4 +319,25 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
 			      struct v4l2_fwnode_endpoint *vep,
 			      struct v4l2_async_subdev *asd));
 
+/**
+ * v4l2_fwnode_reference_parse_sensor_common - parse common references on
+ *					       sensors for async sub-devices
+ * @dev: the device node the properties of which are parsed for references
+ * @notifier: the async notifier where the async subdevs will be added
+ *
+ * Parse common sensor properties for remote devices related to the
+ * sensor and set up async sub-devices for them.
+ *
+ * Any notifier populated using this function must be released with a call to
+ * v4l2_async_notifier_release() after it has been unregistered and the async
+ * sub-devices are no longer in use, even in the case the function returned an
+ * error.
+ *
+ * Return: 0 on success
+ *	   -ENOMEM if memory allocation failed
+ *	   -EINVAL if property parsing failed
+ */
+int v4l2_async_notifier_parse_fwnode_sensor_common(
+	struct device *dev, struct v4l2_async_notifier *notifier);
+
 #endif /* _V4L2_FWNODE_H */
-- 
2.11.0


^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 26/32] v4l: fwnode: Add a convenience function for registering sensors
  2017-10-26  7:53 ` Sakari Ailus
@ 2017-10-26  7:53     ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Add a convenience function for parsing firmware for information on related
devices using v4l2_async_notifier_parse_fwnode_sensor_common() registering
the notifier and finally the async sub-device itself.

This should be useful for sensor drivers that do not have device specific
requirements related to firmware information parsing or the async
framework.

Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
---
 drivers/media/v4l2-core/v4l2-async.c  | 19 ++++++++++++----
 drivers/media/v4l2-core/v4l2-fwnode.c | 41 +++++++++++++++++++++++++++++++++++
 include/media/v4l2-async.h            | 22 +++++++++++++++++++
 include/media/v4l2-subdev.h           |  3 +++
 4 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index b4e88eef195f..e81a72b8d46e 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -474,19 +474,25 @@ int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
 }
 EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
 
-void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
+static void __v4l2_async_notifier_unregister(
+	struct v4l2_async_notifier *notifier)
 {
-	if (!notifier->v4l2_dev && !notifier->sd)
+	if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
 		return;
 
-	mutex_lock(&list_lock);
-
 	v4l2_async_notifier_unbind_all_subdevs(notifier);
 
 	notifier->sd = NULL;
 	notifier->v4l2_dev = NULL;
 
 	list_del(&notifier->list);
+}
+
+void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
+{
+	mutex_lock(&list_lock);
+
+	__v4l2_async_notifier_unregister(notifier);
 
 	mutex_unlock(&list_lock);
 }
@@ -596,6 +602,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 {
 	mutex_lock(&list_lock);
 
+	__v4l2_async_notifier_unregister(sd->subdev_notifier);
+	v4l2_async_notifier_cleanup(sd->subdev_notifier);
+	kfree(sd->subdev_notifier);
+	sd->subdev_notifier = NULL;
+
 	if (sd->asd) {
 		struct v4l2_async_notifier *notifier = sd->notifier;
 
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 1234bd1a2f49..82af608fd626 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -29,6 +29,7 @@
 
 #include <media/v4l2-async.h>
 #include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
 
 enum v4l2_fwnode_bus_type {
 	V4L2_FWNODE_BUS_TYPE_GUESS = 0,
@@ -900,6 +901,46 @@ int v4l2_async_notifier_parse_fwnode_sensor_common(
 }
 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
 
+int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
+{
+	struct v4l2_async_notifier *notifier;
+	int ret;
+
+	if (WARN_ON(!sd->dev))
+		return -ENODEV;
+
+	notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
+	if (!notifier)
+		return -ENOMEM;
+
+	ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
+							     notifier);
+	if (ret < 0)
+		goto out_cleanup;
+
+	ret = v4l2_async_subdev_notifier_register(sd, notifier);
+	if (ret < 0)
+		goto out_cleanup;
+
+	ret = v4l2_async_register_subdev(sd);
+	if (ret < 0)
+		goto out_unregister;
+
+	sd->subdev_notifier = notifier;
+
+	return 0;
+
+out_unregister:
+	v4l2_async_notifier_unregister(notifier);
+
+out_cleanup:
+	v4l2_async_notifier_cleanup(notifier);
+	kfree(notifier);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki-Sze3O3UU22JBDgjK7y7TUQ@public.gmane.org>");
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 8d8cfc3f3100..6152434cbe82 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -174,6 +174,28 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier);
 int v4l2_async_register_subdev(struct v4l2_subdev *sd);
 
 /**
+ * v4l2_async_register_subdev_sensor_common - registers a sensor sub-device to
+ *					      the asynchronous sub-device
+ *					      framework and parse set up common
+ *					      sensor related devices
+ *
+ * @sd: pointer to struct &v4l2_subdev
+ *
+ * This function is just like v4l2_async_register_subdev() with the exception
+ * that calling it will also parse firmware interfaces for remote references
+ * using v4l2_async_notifier_parse_fwnode_sensor_common() and registers the
+ * async sub-devices. The sub-device is similarly unregistered by calling
+ * v4l2_async_unregister_subdev().
+ *
+ * While registered, the subdev module is marked as in-use.
+ *
+ * An error is returned if the module is no longer loaded on any attempts
+ * to register it.
+ */
+int __must_check v4l2_async_register_subdev_sensor_common(
+	struct v4l2_subdev *sd);
+
+/**
  * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous
  * 	subdevice framework
  *
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index e83872078376..ec399c770301 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -793,6 +793,8 @@ struct v4l2_subdev_platform_data {
  *	list.
  * @asd: Pointer to respective &struct v4l2_async_subdev.
  * @notifier: Pointer to the managing notifier.
+ * @subdev_notifier: A sub-device notifier implicitly registered for the sub-
+ *		     device using v4l2_device_register_sensor_subdev().
  * @pdata: common part of subdevice platform data
  *
  * Each instance of a subdev driver should create this struct, either
@@ -823,6 +825,7 @@ struct v4l2_subdev {
 	struct list_head async_list;
 	struct v4l2_async_subdev *asd;
 	struct v4l2_async_notifier *notifier;
+	struct v4l2_async_notifier *subdev_notifier;
 	struct v4l2_subdev_platform_data *pdata;
 };
 
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 26/32] v4l: fwnode: Add a convenience function for registering sensors
@ 2017-10-26  7:53     ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Add a convenience function for parsing firmware for information on related
devices using v4l2_async_notifier_parse_fwnode_sensor_common() registering
the notifier and finally the async sub-device itself.

This should be useful for sensor drivers that do not have device specific
requirements related to firmware information parsing or the async
framework.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c  | 19 ++++++++++++----
 drivers/media/v4l2-core/v4l2-fwnode.c | 41 +++++++++++++++++++++++++++++++++++
 include/media/v4l2-async.h            | 22 +++++++++++++++++++
 include/media/v4l2-subdev.h           |  3 +++
 4 files changed, 81 insertions(+), 4 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index b4e88eef195f..e81a72b8d46e 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -474,19 +474,25 @@ int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
 }
 EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
 
-void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
+static void __v4l2_async_notifier_unregister(
+	struct v4l2_async_notifier *notifier)
 {
-	if (!notifier->v4l2_dev && !notifier->sd)
+	if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
 		return;
 
-	mutex_lock(&list_lock);
-
 	v4l2_async_notifier_unbind_all_subdevs(notifier);
 
 	notifier->sd = NULL;
 	notifier->v4l2_dev = NULL;
 
 	list_del(&notifier->list);
+}
+
+void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
+{
+	mutex_lock(&list_lock);
+
+	__v4l2_async_notifier_unregister(notifier);
 
 	mutex_unlock(&list_lock);
 }
@@ -596,6 +602,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
 {
 	mutex_lock(&list_lock);
 
+	__v4l2_async_notifier_unregister(sd->subdev_notifier);
+	v4l2_async_notifier_cleanup(sd->subdev_notifier);
+	kfree(sd->subdev_notifier);
+	sd->subdev_notifier = NULL;
+
 	if (sd->asd) {
 		struct v4l2_async_notifier *notifier = sd->notifier;
 
diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index 1234bd1a2f49..82af608fd626 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -29,6 +29,7 @@
 
 #include <media/v4l2-async.h>
 #include <media/v4l2-fwnode.h>
+#include <media/v4l2-subdev.h>
 
 enum v4l2_fwnode_bus_type {
 	V4L2_FWNODE_BUS_TYPE_GUESS = 0,
@@ -900,6 +901,46 @@ int v4l2_async_notifier_parse_fwnode_sensor_common(
 }
 EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
 
+int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
+{
+	struct v4l2_async_notifier *notifier;
+	int ret;
+
+	if (WARN_ON(!sd->dev))
+		return -ENODEV;
+
+	notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
+	if (!notifier)
+		return -ENOMEM;
+
+	ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
+							     notifier);
+	if (ret < 0)
+		goto out_cleanup;
+
+	ret = v4l2_async_subdev_notifier_register(sd, notifier);
+	if (ret < 0)
+		goto out_cleanup;
+
+	ret = v4l2_async_register_subdev(sd);
+	if (ret < 0)
+		goto out_unregister;
+
+	sd->subdev_notifier = notifier;
+
+	return 0;
+
+out_unregister:
+	v4l2_async_notifier_unregister(notifier);
+
+out_cleanup:
+	v4l2_async_notifier_cleanup(notifier);
+	kfree(notifier);
+
+	return ret;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 8d8cfc3f3100..6152434cbe82 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -174,6 +174,28 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier);
 int v4l2_async_register_subdev(struct v4l2_subdev *sd);
 
 /**
+ * v4l2_async_register_subdev_sensor_common - registers a sensor sub-device to
+ *					      the asynchronous sub-device
+ *					      framework and parse set up common
+ *					      sensor related devices
+ *
+ * @sd: pointer to struct &v4l2_subdev
+ *
+ * This function is just like v4l2_async_register_subdev() with the exception
+ * that calling it will also parse firmware interfaces for remote references
+ * using v4l2_async_notifier_parse_fwnode_sensor_common() and registers the
+ * async sub-devices. The sub-device is similarly unregistered by calling
+ * v4l2_async_unregister_subdev().
+ *
+ * While registered, the subdev module is marked as in-use.
+ *
+ * An error is returned if the module is no longer loaded on any attempts
+ * to register it.
+ */
+int __must_check v4l2_async_register_subdev_sensor_common(
+	struct v4l2_subdev *sd);
+
+/**
  * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous
  * 	subdevice framework
  *
diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
index e83872078376..ec399c770301 100644
--- a/include/media/v4l2-subdev.h
+++ b/include/media/v4l2-subdev.h
@@ -793,6 +793,8 @@ struct v4l2_subdev_platform_data {
  *	list.
  * @asd: Pointer to respective &struct v4l2_async_subdev.
  * @notifier: Pointer to the managing notifier.
+ * @subdev_notifier: A sub-device notifier implicitly registered for the sub-
+ *		     device using v4l2_device_register_sensor_subdev().
  * @pdata: common part of subdevice platform data
  *
  * Each instance of a subdev driver should create this struct, either
@@ -823,6 +825,7 @@ struct v4l2_subdev {
 	struct list_head async_list;
 	struct v4l2_async_subdev *asd;
 	struct v4l2_async_notifier *notifier;
+	struct v4l2_async_notifier *subdev_notifier;
 	struct v4l2_subdev_platform_data *pdata;
 };
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 27/32] dt: bindings: smiapp: Document lens-focus and flash-leds properties
  2017-10-26  7:53 ` Sakari Ailus
@ 2017-10-26  7:53     ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Document optional lens-focus and flash-leds properties for the smiapp
driver.

Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
---
 Documentation/devicetree/bindings/media/i2c/nokia,smia.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
index 855e1faf73e2..33f10a94c381 100644
--- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
+++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
@@ -27,6 +27,8 @@ Optional properties
 - nokia,nvm-size: The size of the NVM, in bytes. If the size is not given,
   the NVM contents will not be read.
 - reset-gpios: XSHUTDOWN GPIO
+- flash-leds: See ../video-interfaces.txt
+- lens-focus: See ../video-interfaces.txt
 
 
 Endpoint node mandatory properties
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 27/32] dt: bindings: smiapp: Document lens-focus and flash-leds properties
@ 2017-10-26  7:53     ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Document optional lens-focus and flash-leds properties for the smiapp
driver.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 Documentation/devicetree/bindings/media/i2c/nokia,smia.txt | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
index 855e1faf73e2..33f10a94c381 100644
--- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
+++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
@@ -27,6 +27,8 @@ Optional properties
 - nokia,nvm-size: The size of the NVM, in bytes. If the size is not given,
   the NVM contents will not be read.
 - reset-gpios: XSHUTDOWN GPIO
+- flash-leds: See ../video-interfaces.txt
+- lens-focus: See ../video-interfaces.txt
 
 
 Endpoint node mandatory properties
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 28/32] smiapp: Add support for flash and lens devices
  2017-10-26  7:53 ` Sakari Ailus
@ 2017-10-26  7:53     ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Parse async sub-devices related to the sensor by switching the async
sub-device registration function.

These types devices aren't directly related to the sensor, but are
nevertheless handled by the smiapp driver due to the relationship of these
component to the main part of the camera module --- the sensor.

This does not yet address providing the user space with information on how
to associate the sensor or lens devices but the kernel now has the
necessary information to do that.

Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
---
 drivers/media/i2c/smiapp/smiapp-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index fbd851be51d2..a87c50373813 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -3118,7 +3118,7 @@ static int smiapp_probe(struct i2c_client *client,
 	if (rval < 0)
 		goto out_media_entity_cleanup;
 
-	rval = v4l2_async_register_subdev(&sensor->src->sd);
+	rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd);
 	if (rval < 0)
 		goto out_media_entity_cleanup;
 
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 28/32] smiapp: Add support for flash and lens devices
@ 2017-10-26  7:53     ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Parse async sub-devices related to the sensor by switching the async
sub-device registration function.

These types devices aren't directly related to the sensor, but are
nevertheless handled by the smiapp driver due to the relationship of these
component to the main part of the camera module --- the sensor.

This does not yet address providing the user space with information on how
to associate the sensor or lens devices but the kernel now has the
necessary information to do that.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 drivers/media/i2c/smiapp/smiapp-core.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
index fbd851be51d2..a87c50373813 100644
--- a/drivers/media/i2c/smiapp/smiapp-core.c
+++ b/drivers/media/i2c/smiapp/smiapp-core.c
@@ -3118,7 +3118,7 @@ static int smiapp_probe(struct i2c_client *client,
 	if (rval < 0)
 		goto out_media_entity_cleanup;
 
-	rval = v4l2_async_register_subdev(&sensor->src->sd);
+	rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd);
 	if (rval < 0)
 		goto out_media_entity_cleanup;
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 29/32] et8ek8: Add support for flash and lens devices
  2017-10-26  7:53 ` Sakari Ailus
                   ` (24 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-29 23:05   ` Sebastian Reichel
  2017-11-12 11:27   ` et8ek8: Document " Pavel Machek
  -1 siblings, 2 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Parse async sub-devices related to the sensor by switching the async
sub-device registration function.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 drivers/media/i2c/et8ek8/et8ek8_driver.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c
index c14f0fd6ded3..e9eff9039ef5 100644
--- a/drivers/media/i2c/et8ek8/et8ek8_driver.c
+++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c
@@ -1453,7 +1453,7 @@ static int et8ek8_probe(struct i2c_client *client,
 		goto err_mutex;
 	}
 
-	ret = v4l2_async_register_subdev(&sensor->subdev);
+	ret = v4l2_async_register_subdev_sensor_common(&sensor->subdev);
 	if (ret < 0)
 		goto err_entity;
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 30/32] ov5670: Add support for flash and lens devices
  2017-10-26  7:53 ` Sakari Ailus
@ 2017-10-26  7:53     ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media-u79uwXL29TY76Z2rM5mHXA
  Cc: niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Parse async sub-devices related to the sensor by switching the async
sub-device registration function.

Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
---
 drivers/media/i2c/ov5670.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index a65469f88e36..9f9196568eb8 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -2529,7 +2529,7 @@ static int ov5670_probe(struct i2c_client *client)
 	}
 
 	/* Async register for subdev */
-	ret = v4l2_async_register_subdev(&ov5670->sd);
+	ret = v4l2_async_register_subdev_sensor_common(&ov5670->sd);
 	if (ret < 0) {
 		err_msg = "v4l2_async_register_subdev() error";
 		goto error_entity_cleanup;
-- 
2.11.0

--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 30/32] ov5670: Add support for flash and lens devices
@ 2017-10-26  7:53     ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Parse async sub-devices related to the sensor by switching the async
sub-device registration function.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/i2c/ov5670.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
index a65469f88e36..9f9196568eb8 100644
--- a/drivers/media/i2c/ov5670.c
+++ b/drivers/media/i2c/ov5670.c
@@ -2529,7 +2529,7 @@ static int ov5670_probe(struct i2c_client *client)
 	}
 
 	/* Async register for subdev */
-	ret = v4l2_async_register_subdev(&ov5670->sd);
+	ret = v4l2_async_register_subdev_sensor_common(&ov5670->sd);
 	if (ret < 0) {
 		err_msg = "v4l2_async_register_subdev() error";
 		goto error_entity_cleanup;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 31/32] ov13858: Add support for flash and lens devices
  2017-10-26  7:53 ` Sakari Ailus
                   ` (25 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
       [not found]   ` <20171026075342.5760-32-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Parse async sub-devices related to the sensor by switching the async
sub-device registration function.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/i2c/ov13858.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
index fdce2befed02..bf7d06f3f21a 100644
--- a/drivers/media/i2c/ov13858.c
+++ b/drivers/media/i2c/ov13858.c
@@ -1761,7 +1761,7 @@ static int ov13858_probe(struct i2c_client *client,
 		goto error_handler_free;
 	}
 
-	ret = v4l2_async_register_subdev(&ov13858->sd);
+	ret = v4l2_async_register_subdev_sensor_common(&ov13858->sd);
 	if (ret < 0)
 		goto error_media_entity;
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16 32/32] arm: dts: omap3: N9/N950: Add flash references to the camera
  2017-10-26  7:53 ` Sakari Ailus
                   ` (26 preceding siblings ...)
  (?)
@ 2017-10-26  7:53 ` Sakari Ailus
  2017-10-29 23:08   ` Sebastian Reichel
  -1 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26  7:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart,
	pavel, sre, linux-acpi, devicetree

Add flash and indicator LED phandles to the sensor node.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
 arch/arm/boot/dts/omap3-n9.dts       | 1 +
 arch/arm/boot/dts/omap3-n950-n9.dtsi | 4 ++--
 arch/arm/boot/dts/omap3-n950.dts     | 1 +
 3 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/arch/arm/boot/dts/omap3-n9.dts b/arch/arm/boot/dts/omap3-n9.dts
index b9e58c536afd..39e35f8b8206 100644
--- a/arch/arm/boot/dts/omap3-n9.dts
+++ b/arch/arm/boot/dts/omap3-n9.dts
@@ -26,6 +26,7 @@
 		clocks = <&isp 0>;
 		clock-frequency = <9600000>;
 		nokia,nvm-size = <(16 * 64)>;
+		flash-leds = <&as3645a_flash &as3645a_indicator>;
 		port {
 			smia_1_1: endpoint {
 				link-frequencies = /bits/ 64 <199200000 210000000 499200000>;
diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi
index 1b0bd72945f2..12fbb3da5fce 100644
--- a/arch/arm/boot/dts/omap3-n950-n9.dtsi
+++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi
@@ -271,14 +271,14 @@
 		#size-cells = <0>;
 		reg = <0x30>;
 		compatible = "ams,as3645a";
-		flash@0 {
+		as3645a_flash: flash@0 {
 			reg = <0x0>;
 			flash-timeout-us = <150000>;
 			flash-max-microamp = <320000>;
 			led-max-microamp = <60000>;
 			ams,input-max-microamp = <1750000>;
 		};
-		indicator@1 {
+		as3645a_indicator: indicator@1 {
 			reg = <0x1>;
 			led-max-microamp = <10000>;
 		};
diff --git a/arch/arm/boot/dts/omap3-n950.dts b/arch/arm/boot/dts/omap3-n950.dts
index 646601a3ebd8..c354a1ed1e70 100644
--- a/arch/arm/boot/dts/omap3-n950.dts
+++ b/arch/arm/boot/dts/omap3-n950.dts
@@ -60,6 +60,7 @@
 		clocks = <&isp 0>;
 		clock-frequency = <9600000>;
 		nokia,nvm-size = <(16 * 64)>;
+		flash-leds = <&as3645a_flash &as3645a_indicator>;
 		port {
 			smia_1_1: endpoint {
 				link-frequencies = /bits/ 64 <210000000 333600000 398400000>;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16.1 24/32] v4l: fwnode: Add a helper function to obtain device / integer references
  2017-10-26  7:53 ` [PATCH v16 24/32] v4l: fwnode: Add a helper function to obtain device / integer references Sakari Ailus
@ 2017-10-26 15:01   ` Sakari Ailus
  2017-10-29 22:58     ` Sebastian Reichel
  0 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26 15:01 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart, pavel, sre

v4l2_fwnode_reference_parse_int_prop() will find an fwnode such that under
the device's own fwnode, it will follow child fwnodes with the given
property-value pair and return the resulting fwnode.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
since v16:

- use const char * const *props for string arrays with property names.

 drivers/media/v4l2-core/v4l2-fwnode.c | 287 ++++++++++++++++++++++++++++++++++
 1 file changed, 287 insertions(+)

diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index edd2e8d983a1..f8cd88f791c4 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -578,6 +578,293 @@ static int v4l2_fwnode_reference_parse(
 	return ret;
 }
 
+/*
+ * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
+ *					arguments
+ * @fwnode: fwnode to read @prop from
+ * @notifier: notifier for @dev
+ * @prop: the name of the property
+ * @index: the index of the reference to get
+ * @props: the array of integer property names
+ * @nprops: the number of integer property names in @nprops
+ *
+ * First find an fwnode referred to by the reference at @index in @prop.
+ *
+ * Then under that fwnode, @nprops times, for each property in @props,
+ * iteratively follow child nodes starting from fwnode such that they have the
+ * property in @props array at the index of the child node distance from the
+ * root node and the value of that property matching with the integer argument
+ * of the reference, at the same index.
+ *
+ * The child fwnode reched at the end of the iteration is then returned to the
+ * caller.
+ *
+ * The core reason for this is that you cannot refer to just any node in ACPI.
+ * So to refer to an endpoint (easy in DT) you need to refer to a device, then
+ * provide a list of (property name, property value) tuples where each tuple
+ * uniquely identifies a child node. The first tuple identifies a child directly
+ * underneath the device fwnode, the next tuple identifies a child node
+ * underneath the fwnode identified by the previous tuple, etc. until you
+ * reached the fwnode you need.
+ *
+ * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
+ *
+ *	Scope (\_SB.PCI0.I2C2)
+ *	{
+ *		Device (CAM0)
+ *		{
+ *			Name (_DSD, Package () {
+ *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ *				Package () {
+ *					Package () {
+ *						"compatible",
+ *						Package () { "nokia,smia" }
+ *					},
+ *				},
+ *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+ *				Package () {
+ *					Package () { "port0", "PRT0" },
+ *				}
+ *			})
+ *			Name (PRT0, Package() {
+ *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ *				Package () {
+ *					Package () { "port", 0 },
+ *				},
+ *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+ *				Package () {
+ *					Package () { "endpoint0", "EP00" },
+ *				}
+ *			})
+ *			Name (EP00, Package() {
+ *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ *				Package () {
+ *					Package () { "endpoint", 0 },
+ *					Package () {
+ *						"remote-endpoint",
+ *						Package() {
+ *							\_SB.PCI0.ISP, 4, 0
+ *						}
+ *					},
+ *				}
+ *			})
+ *		}
+ *	}
+ *
+ *	Scope (\_SB.PCI0)
+ *	{
+ *		Device (ISP)
+ *		{
+ *			Name (_DSD, Package () {
+ *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+ *				Package () {
+ *					Package () { "port4", "PRT4" },
+ *				}
+ *			})
+ *
+ *			Name (PRT4, Package() {
+ *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ *				Package () {
+ *					Package () { "port", 4 },
+ *				},
+ *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
+ *				Package () {
+ *					Package () { "endpoint0", "EP40" },
+ *				}
+ *			})
+ *
+ *			Name (EP40, Package() {
+ *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
+ *				Package () {
+ *					Package () { "endpoint", 0 },
+ *					Package () {
+ *						"remote-endpoint",
+ *						Package () {
+ *							\_SB.PCI0.I2C2.CAM0,
+ *							0, 0
+ *						}
+ *					},
+ *				}
+ *			})
+ *		}
+ *	}
+ *
+ * From the EP40 node under ISP device, you could parse the graph remote
+ * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
+ *
+ *  @fwnode: fwnode referring to EP40 under ISP.
+ *  @prop: "remote-endpoint"
+ *  @index: 0
+ *  @props: "port", "endpoint"
+ *  @nprops: 2
+ *
+ * And you'd get back fwnode referring to EP00 under CAM0.
+ *
+ * The same works the other way around: if you use EP00 under CAM0 as the
+ * fwnode, you'll get fwnode referring to EP40 under ISP.
+ *
+ * The same example in DT syntax would look like this:
+ *
+ * cam: cam0 {
+ *	compatible = "nokia,smia";
+ *
+ *	port {
+ *		port = <0>;
+ *		endpoint {
+ *			endpoint = <0>;
+ *			remote-endpoint = <&isp 4 0>;
+ *		};
+ *	};
+ * };
+ *
+ * isp: isp {
+ *	ports {
+ *		port@4 {
+ *			port = <4>;
+ *			endpoint {
+ *				endpoint = <0>;
+ *				remote-endpoint = <&cam 0 0>;
+ *			};
+ *		};
+ *	};
+ * };
+ *
+ * Return: 0 on success
+ *	   -ENOENT if no entries (or the property itself) were found
+ *	   -EINVAL if property parsing otherwise failed
+ *	   -ENOMEM if memory allocation failed
+ */
+static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
+	struct fwnode_handle *fwnode, const char *prop, unsigned int index,
+	const char * const *props, unsigned int nprops)
+{
+	struct fwnode_reference_args fwnode_args;
+	unsigned int *args = fwnode_args.args;
+	struct fwnode_handle *child;
+	int ret;
+
+	/*
+	 * Obtain remote fwnode as well as the integer arguments.
+	 *
+	 * Note that right now both -ENODATA and -ENOENT may signal
+	 * out-of-bounds access. Return -ENOENT in that case.
+	 */
+	ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
+						 index, &fwnode_args);
+	if (ret)
+		return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
+
+	/*
+	 * Find a node in the tree under the referred fwnode corresponding to
+	 * the integer arguments.
+	 */
+	fwnode = fwnode_args.fwnode;
+	while (nprops--) {
+		u32 val;
+
+		/* Loop over all child nodes under fwnode. */
+		fwnode_for_each_child_node(fwnode, child) {
+			if (fwnode_property_read_u32(child, *props, &val))
+				continue;
+
+			/* Found property, see if its value matches. */
+			if (val == *args)
+				break;
+		}
+
+		fwnode_handle_put(fwnode);
+
+		/* No property found; return an error here. */
+		if (!child) {
+			fwnode = ERR_PTR(-ENOENT);
+			break;
+		}
+
+		props++;
+		args++;
+		fwnode = child;
+	}
+
+	return fwnode;
+}
+
+/*
+ * v4l2_fwnode_reference_parse_int_props - parse references for async
+ *					   sub-devices
+ * @dev: struct device pointer
+ * @notifier: notifier for @dev
+ * @prop: the name of the property
+ * @props: the array of integer property names
+ * @nprops: the number of integer properties
+ *
+ * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
+ * property @prop with integer arguments with child nodes matching in properties
+ * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
+ * accordingly.
+ *
+ * While it is technically possible to use this function on DT, it is only
+ * meaningful on ACPI. On Device tree you can refer to any node in the tree but
+ * on ACPI the references are limited to devices.
+ *
+ * Return: 0 on success
+ *	   -ENOENT if no entries (or the property itself) were found
+ *	   -EINVAL if property parsing otherwisefailed
+ *	   -ENOMEM if memory allocation failed
+ */
+static int v4l2_fwnode_reference_parse_int_props(
+	struct device *dev, struct v4l2_async_notifier *notifier,
+	const char *prop, const char * const *props, unsigned int nprops)
+{
+	struct fwnode_handle *fwnode;
+	unsigned int index;
+	int ret;
+
+	for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
+					 dev_fwnode(dev), prop, index, props,
+					 nprops))); index++)
+		fwnode_handle_put(fwnode);
+
+	/*
+	 * Note that right now both -ENODATA and -ENOENT may signal
+	 * out-of-bounds access. Return the error in cases other than that.
+	 */
+	if (PTR_ERR(fwnode) != -ENOENT && PTR_ERR(fwnode) != -ENODATA)
+		return PTR_ERR(fwnode);
+
+	ret = v4l2_async_notifier_realloc(notifier,
+					  notifier->num_subdevs + index);
+	if (ret)
+		return -ENOMEM;
+
+	for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
+					 dev_fwnode(dev), prop, index, props,
+					 nprops))); index++) {
+		struct v4l2_async_subdev *asd;
+
+		if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
+			ret = -EINVAL;
+			goto error;
+		}
+
+		asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL);
+		if (!asd) {
+			ret = -ENOMEM;
+			goto error;
+		}
+
+		notifier->subdevs[notifier->num_subdevs] = asd;
+		asd->match.fwnode.fwnode = fwnode;
+		asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
+		notifier->num_subdevs++;
+	}
+
+	return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
+
+error:
+	fwnode_handle_put(fwnode);
+	return ret;
+}
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16.1 25/32] v4l: fwnode: Add convenience function for parsing common external refs
  2017-10-26  7:53 ` [PATCH v16 25/32] v4l: fwnode: Add convenience function for parsing common external refs Sakari Ailus
@ 2017-10-26 15:03   ` Sakari Ailus
  2017-10-29 23:00     ` Sebastian Reichel
  0 siblings, 1 reply; 107+ messages in thread
From: Sakari Ailus @ 2017-10-26 15:03 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart, pavel, sre

Add v4l2_fwnode_parse_reference_sensor_common for parsing common
sensor properties that refer to adjacent devices such as flash or lens
driver chips.

As this is an association only, there's little a regular driver needs to
know about these devices as such.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Pavel Machek <pavel@ucw.cz>
---
since v16:

- use const char * const *props for string arrays with property names.

 drivers/media/v4l2-core/v4l2-fwnode.c | 35 +++++++++++++++++++++++++++++++++++
 include/media/v4l2-async.h            |  3 ++-
 include/media/v4l2-fwnode.h           | 21 +++++++++++++++++++++
 3 files changed, 58 insertions(+), 1 deletion(-)

diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
index f8cd88f791c4..39387dc6cadd 100644
--- a/drivers/media/v4l2-core/v4l2-fwnode.c
+++ b/drivers/media/v4l2-core/v4l2-fwnode.c
@@ -865,6 +865,41 @@ static int v4l2_fwnode_reference_parse_int_props(
 	return ret;
 }
 
+int v4l2_async_notifier_parse_fwnode_sensor_common(
+	struct device *dev, struct v4l2_async_notifier *notifier)
+{
+	static const char * const led_props[] = { "led" };
+	static const struct {
+		const char *name;
+		const char * const *props;
+		unsigned int nprops;
+	} props[] = {
+		{ "flash-leds", led_props, ARRAY_SIZE(led_props) },
+		{ "lens-focus", NULL, 0 },
+	};
+	unsigned int i;
+
+	for (i = 0; i < ARRAY_SIZE(props); i++) {
+		int ret;
+
+		if (props[i].props && is_acpi_node(dev_fwnode(dev)))
+			ret = v4l2_fwnode_reference_parse_int_props(
+				dev, notifier, props[i].name,
+				props[i].props, props[i].nprops);
+		else
+			ret = v4l2_fwnode_reference_parse(
+				dev, notifier, props[i].name);
+		if (ret && ret != -ENOENT) {
+			dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
+				 props[i].name, ret);
+			return ret;
+		}
+	}
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
+
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
 MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 17c4ac7c73e8..8d8cfc3f3100 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -156,7 +156,8 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
  * Release memory resources related to a notifier, including the async
  * sub-devices allocated for the purposes of the notifier but not the notifier
  * itself. The user is responsible for calling this function to clean up the
- * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints.
+ * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints or
+ * @v4l2_fwnode_reference_parse_sensor_common.
  *
  * There is no harm from calling v4l2_async_notifier_cleanup in other
  * cases as long as its memory has been zeroed after it has been
diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
index 105cfeee44ef..ca50108dfd8f 100644
--- a/include/media/v4l2-fwnode.h
+++ b/include/media/v4l2-fwnode.h
@@ -319,4 +319,25 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
 			      struct v4l2_fwnode_endpoint *vep,
 			      struct v4l2_async_subdev *asd));
 
+/**
+ * v4l2_fwnode_reference_parse_sensor_common - parse common references on
+ *					       sensors for async sub-devices
+ * @dev: the device node the properties of which are parsed for references
+ * @notifier: the async notifier where the async subdevs will be added
+ *
+ * Parse common sensor properties for remote devices related to the
+ * sensor and set up async sub-devices for them.
+ *
+ * Any notifier populated using this function must be released with a call to
+ * v4l2_async_notifier_release() after it has been unregistered and the async
+ * sub-devices are no longer in use, even in the case the function returned an
+ * error.
+ *
+ * Return: 0 on success
+ *	   -ENOMEM if memory allocation failed
+ *	   -EINVAL if property parsing failed
+ */
+int v4l2_async_notifier_parse_fwnode_sensor_common(
+	struct device *dev, struct v4l2_async_notifier *notifier);
+
 #endif /* _V4L2_FWNODE_H */
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 01/32] v4l: async: Remove re-probing support
  2017-10-26  7:53 ` [PATCH v16 01/32] v4l: async: Remove re-probing support Sakari Ailus
@ 2017-10-26 15:20   ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 15:20 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:11 +0300, Sakari Ailus wrote:
> Remove V4L2 async re-probing support. The re-probing support has been
> there to support cases where the sub-devices require resources provided by
> the main driver's hardware to function, such as clocks.
> 
> Reprobing has allowed unbinding and again binding the main driver without
> explicitly unbinding the sub-device drivers. This is certainly not a
> common need, and the responsibility will be the user's going forward.
> 
> An alternative could have been to introduce notifier specific locks.
> Considering the complexity of the re-probing and that it isn't really a
> solution to a problem but a workaround, remove re-probing instead.
> 
> If there is a need to support the clock provider unregister/register cycle
> while keeping the clock references in the consumers in the future, this
> should be implemented in the clock framework instead, not in V4L2.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 54 +-----------------------------------
>  1 file changed, 1 insertion(+), 53 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index d741a8e0fdac..60a1a50b9537 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -198,78 +198,26 @@ EXPORT_SYMBOL(v4l2_async_notifier_register);
>  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_subdev *sd, *tmp;
> -	unsigned int notif_n_subdev = notifier->num_subdevs;
> -	unsigned int n_subdev = min(notif_n_subdev, V4L2_MAX_SUBDEVS);
> -	struct device **dev;
> -	int i = 0;
>  
>  	if (!notifier->v4l2_dev)
>  		return;
>  
> -	dev = kvmalloc_array(n_subdev, sizeof(*dev), GFP_KERNEL);
> -	if (!dev) {
> -		dev_err(notifier->v4l2_dev->dev,
> -			"Failed to allocate device cache!\n");
> -	}
> -
>  	mutex_lock(&list_lock);
>  
>  	list_del(&notifier->list);
>  
>  	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> -		struct device *d;
> -
> -		d = get_device(sd->dev);
> -
>  		v4l2_async_cleanup(sd);
>  
> -		/* If we handled USB devices, we'd have to lock the parent too */
> -		device_release_driver(d);
> -
>  		if (notifier->unbind)
>  			notifier->unbind(notifier, sd, sd->asd);
>  
> -		/*
> -		 * Store device at the device cache, in order to call
> -		 * put_device() on the final step
> -		 */
> -		if (dev)
> -			dev[i++] = d;
> -		else
> -			put_device(d);
> +		list_move(&sd->async_list, &subdev_list);
>  	}
>  
>  	mutex_unlock(&list_lock);
>  
> -	/*
> -	 * Call device_attach() to reprobe devices
> -	 *
> -	 * NOTE: If dev allocation fails, i is 0, and the whole loop won't be
> -	 * executed.
> -	 */
> -	while (i--) {
> -		struct device *d = dev[i];
> -
> -		if (d && device_attach(d) < 0) {
> -			const char *name = "(none)";
> -			int lock = device_trylock(d);
> -
> -			if (lock && d->driver)
> -				name = d->driver->name;
> -			dev_err(d, "Failed to re-probe to %s\n", name);
> -			if (lock)
> -				device_unlock(d);
> -		}
> -		put_device(d);
> -	}
> -	kvfree(dev);
> -
>  	notifier->v4l2_dev = NULL;
> -
> -	/*
> -	 * Don't care about the waiting list, it is initialised and populated
> -	 * upon notifier registration.
> -	 */
>  }
>  EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 02/32] v4l: async: Don't set sd->dev NULL in v4l2_async_cleanup
  2017-10-26  7:53 ` [PATCH v16 02/32] v4l: async: Don't set sd->dev NULL in v4l2_async_cleanup Sakari Ailus
@ 2017-10-26 15:23       ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 15:23 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 2017-10-26 10:53:12 +0300, Sakari Ailus wrote:
> v4l2_async_cleanup() is called when the async sub-device is unbound from
> the media device. As the pointer is set by the driver registering the
> async sub-device, leave the pointer as set by the driver.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 60a1a50b9537..21c748bf3a7b 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -134,7 +134,6 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  	/* Subdevice driver will reprobe and put the subdev back onto the list */
>  	list_del_init(&sd->async_list);
>  	sd->asd = NULL;
> -	sd->dev = NULL;
>  }
>  
>  int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 02/32] v4l: async: Don't set sd->dev NULL in v4l2_async_cleanup
@ 2017-10-26 15:23       ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 15:23 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:12 +0300, Sakari Ailus wrote:
> v4l2_async_cleanup() is called when the async sub-device is unbound from
> the media device. As the pointer is set by the driver registering the
> async sub-device, leave the pointer as set by the driver.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 1 -
>  1 file changed, 1 deletion(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 60a1a50b9537..21c748bf3a7b 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -134,7 +134,6 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  	/* Subdevice driver will reprobe and put the subdev back onto the list */
>  	list_del_init(&sd->async_list);
>  	sd->asd = NULL;
> -	sd->dev = NULL;
>  }
>  
>  int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 04/32] v4l: async: Fix notifier complete callback error handling
  2017-10-26  7:53     ` Sakari Ailus
@ 2017-10-26 15:34         ` Niklas Söderlund
  -1 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 15:34 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Sakari,

On 2017-10-26 10:53:14 +0300, Sakari Ailus wrote:
> The notifier complete callback may return an error. This error code was
> simply returned to the caller but never handled properly.
> 
> Move calling the complete callback function to the caller from
> v4l2_async_test_notify and undo the work that was done either in async
> sub-device or async notifier registration.
> 
> Reported-by: Russell King <rmk+kernel-I+IVW8TIWO2tmTQ+vhA3Yw@public.gmane.org>
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>

We really should get rid of the complete handler at some point :-)

Acked-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 78 +++++++++++++++++++++++++++---------
>  1 file changed, 60 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index ca281438a0ae..4924481451ca 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -122,9 +122,6 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
>  	/* Move from the global subdevice list to notifier's done */
>  	list_move(&sd->async_list, &notifier->done);
>  
> -	if (list_empty(&notifier->waiting) && notifier->complete)
> -		return notifier->complete(notifier);
> -
>  	return 0;
>  }
>  
> @@ -136,11 +133,27 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  	sd->asd = NULL;
>  }
>  
> +static void v4l2_async_notifier_unbind_all_subdevs(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_subdev *sd, *tmp;
> +
> +	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> +		if (notifier->unbind)
> +			notifier->unbind(notifier, sd, sd->asd);
> +
> +		v4l2_async_cleanup(sd);
> +
> +		list_move(&sd->async_list, &subdev_list);
> +	}
> +}
> +
>  int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  				 struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_subdev *sd, *tmp;
>  	struct v4l2_async_subdev *asd;
> +	int ret;
>  	int i;
>  
>  	if (!v4l2_dev || !notifier->num_subdevs ||
> @@ -185,19 +198,30 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  		}
>  	}
>  
> +	if (list_empty(&notifier->waiting) && notifier->complete) {
> +		ret = notifier->complete(notifier);
> +		if (ret)
> +			goto err_complete;
> +	}
> +
>  	/* Keep also completed notifiers on the list */
>  	list_add(&notifier->list, &notifier_list);
>  
>  	mutex_unlock(&list_lock);
>  
>  	return 0;
> +
> +err_complete:
> +	v4l2_async_notifier_unbind_all_subdevs(notifier);
> +
> +	mutex_unlock(&list_lock);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(v4l2_async_notifier_register);
>  
>  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
>  {
> -	struct v4l2_subdev *sd, *tmp;
> -
>  	if (!notifier->v4l2_dev)
>  		return;
>  
> @@ -205,14 +229,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
>  
>  	list_del(&notifier->list);
>  
> -	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> -		if (notifier->unbind)
> -			notifier->unbind(notifier, sd, sd->asd);
> -
> -		v4l2_async_cleanup(sd);
> -
> -		list_move(&sd->async_list, &subdev_list);
> -	}
> +	v4l2_async_notifier_unbind_all_subdevs(notifier);
>  
>  	mutex_unlock(&list_lock);
>  
> @@ -223,6 +240,7 @@ EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>  int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  {
>  	struct v4l2_async_notifier *notifier;
> +	int ret;
>  
>  	/*
>  	 * No reference taken. The reference is held by the device
> @@ -238,19 +256,43 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  
>  	list_for_each_entry(notifier, &notifier_list, list) {
>  		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
> -		if (asd) {
> -			int ret = v4l2_async_test_notify(notifier, sd, asd);
> -			mutex_unlock(&list_lock);
> -			return ret;
> -		}
> +		int ret;
> +
> +		if (!asd)
> +			continue;
> +
> +		ret = v4l2_async_test_notify(notifier, sd, asd);
> +		if (ret)
> +			goto err_unlock;
> +
> +		if (!list_empty(&notifier->waiting) || !notifier->complete)
> +			goto out_unlock;
> +
> +		ret = notifier->complete(notifier);
> +		if (ret)
> +			goto err_cleanup;
> +
> +		goto out_unlock;
>  	}
>  
>  	/* None matched, wait for hot-plugging */
>  	list_add(&sd->async_list, &subdev_list);
>  
> +out_unlock:
>  	mutex_unlock(&list_lock);
>  
>  	return 0;
> +
> +err_cleanup:
> +	if (notifier->unbind)
> +		notifier->unbind(notifier, sd, sd->asd);
> +
> +	v4l2_async_cleanup(sd);
> +
> +err_unlock:
> +	mutex_unlock(&list_lock);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(v4l2_async_register_subdev);
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 04/32] v4l: async: Fix notifier complete callback error handling
@ 2017-10-26 15:34         ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 15:34 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

Hi Sakari,

On 2017-10-26 10:53:14 +0300, Sakari Ailus wrote:
> The notifier complete callback may return an error. This error code was
> simply returned to the caller but never handled properly.
> 
> Move calling the complete callback function to the caller from
> v4l2_async_test_notify and undo the work that was done either in async
> sub-device or async notifier registration.
> 
> Reported-by: Russell King <rmk+kernel@armlinux.org.uk>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>

We really should get rid of the complete handler at some point :-)

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 78 +++++++++++++++++++++++++++---------
>  1 file changed, 60 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index ca281438a0ae..4924481451ca 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -122,9 +122,6 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
>  	/* Move from the global subdevice list to notifier's done */
>  	list_move(&sd->async_list, &notifier->done);
>  
> -	if (list_empty(&notifier->waiting) && notifier->complete)
> -		return notifier->complete(notifier);
> -
>  	return 0;
>  }
>  
> @@ -136,11 +133,27 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  	sd->asd = NULL;
>  }
>  
> +static void v4l2_async_notifier_unbind_all_subdevs(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_subdev *sd, *tmp;
> +
> +	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> +		if (notifier->unbind)
> +			notifier->unbind(notifier, sd, sd->asd);
> +
> +		v4l2_async_cleanup(sd);
> +
> +		list_move(&sd->async_list, &subdev_list);
> +	}
> +}
> +
>  int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  				 struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_subdev *sd, *tmp;
>  	struct v4l2_async_subdev *asd;
> +	int ret;
>  	int i;
>  
>  	if (!v4l2_dev || !notifier->num_subdevs ||
> @@ -185,19 +198,30 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  		}
>  	}
>  
> +	if (list_empty(&notifier->waiting) && notifier->complete) {
> +		ret = notifier->complete(notifier);
> +		if (ret)
> +			goto err_complete;
> +	}
> +
>  	/* Keep also completed notifiers on the list */
>  	list_add(&notifier->list, &notifier_list);
>  
>  	mutex_unlock(&list_lock);
>  
>  	return 0;
> +
> +err_complete:
> +	v4l2_async_notifier_unbind_all_subdevs(notifier);
> +
> +	mutex_unlock(&list_lock);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(v4l2_async_notifier_register);
>  
>  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
>  {
> -	struct v4l2_subdev *sd, *tmp;
> -
>  	if (!notifier->v4l2_dev)
>  		return;
>  
> @@ -205,14 +229,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
>  
>  	list_del(&notifier->list);
>  
> -	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> -		if (notifier->unbind)
> -			notifier->unbind(notifier, sd, sd->asd);
> -
> -		v4l2_async_cleanup(sd);
> -
> -		list_move(&sd->async_list, &subdev_list);
> -	}
> +	v4l2_async_notifier_unbind_all_subdevs(notifier);
>  
>  	mutex_unlock(&list_lock);
>  
> @@ -223,6 +240,7 @@ EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>  int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  {
>  	struct v4l2_async_notifier *notifier;
> +	int ret;
>  
>  	/*
>  	 * No reference taken. The reference is held by the device
> @@ -238,19 +256,43 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  
>  	list_for_each_entry(notifier, &notifier_list, list) {
>  		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
> -		if (asd) {
> -			int ret = v4l2_async_test_notify(notifier, sd, asd);
> -			mutex_unlock(&list_lock);
> -			return ret;
> -		}
> +		int ret;
> +
> +		if (!asd)
> +			continue;
> +
> +		ret = v4l2_async_test_notify(notifier, sd, asd);
> +		if (ret)
> +			goto err_unlock;
> +
> +		if (!list_empty(&notifier->waiting) || !notifier->complete)
> +			goto out_unlock;
> +
> +		ret = notifier->complete(notifier);
> +		if (ret)
> +			goto err_cleanup;
> +
> +		goto out_unlock;
>  	}
>  
>  	/* None matched, wait for hot-plugging */
>  	list_add(&sd->async_list, &subdev_list);
>  
> +out_unlock:
>  	mutex_unlock(&list_lock);
>  
>  	return 0;
> +
> +err_cleanup:
> +	if (notifier->unbind)
> +		notifier->unbind(notifier, sd, sd->asd);
> +
> +	v4l2_async_cleanup(sd);
> +
> +err_unlock:
> +	mutex_unlock(&list_lock);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(v4l2_async_register_subdev);
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 05/32] v4l: async: Correctly serialise async sub-device unregistration
  2017-10-26  7:53 ` [PATCH v16 05/32] v4l: async: Correctly serialise async sub-device unregistration Sakari Ailus
@ 2017-10-26 15:38       ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 15:38 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 2017-10-26 10:53:15 +0300, Sakari Ailus wrote:
> The check whether an async sub-device is bound to a notifier was performed
> without list_lock held, making it possible for another process to
> unbind the async sub-device before the sub-device unregistration function
> proceeds to take the lock.
> 
> Fix this by first acquiring the lock and then proceeding with the check.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 18 +++++++-----------
>  1 file changed, 7 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 4924481451ca..cde2cf2ab4b0 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -298,20 +298,16 @@ EXPORT_SYMBOL(v4l2_async_register_subdev);
>  
>  void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  {
> -	struct v4l2_async_notifier *notifier = sd->notifier;
> -
> -	if (!sd->asd) {
> -		if (!list_empty(&sd->async_list))
> -			v4l2_async_cleanup(sd);
> -		return;
> -	}
> -
>  	mutex_lock(&list_lock);
>  
> -	list_add(&sd->asd->list, &notifier->waiting);
> +	if (sd->asd) {
> +		struct v4l2_async_notifier *notifier = sd->notifier;
>  
> -	if (notifier->unbind)
> -		notifier->unbind(notifier, sd, sd->asd);
> +		list_add(&sd->asd->list, &notifier->waiting);
> +
> +		if (notifier->unbind)
> +			notifier->unbind(notifier, sd, sd->asd);
> +	}
>  
>  	v4l2_async_cleanup(sd);
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 05/32] v4l: async: Correctly serialise async sub-device unregistration
@ 2017-10-26 15:38       ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 15:38 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:15 +0300, Sakari Ailus wrote:
> The check whether an async sub-device is bound to a notifier was performed
> without list_lock held, making it possible for another process to
> unbind the async sub-device before the sub-device unregistration function
> proceeds to take the lock.
> 
> Fix this by first acquiring the lock and then proceeding with the check.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 18 +++++++-----------
>  1 file changed, 7 insertions(+), 11 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 4924481451ca..cde2cf2ab4b0 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -298,20 +298,16 @@ EXPORT_SYMBOL(v4l2_async_register_subdev);
>  
>  void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  {
> -	struct v4l2_async_notifier *notifier = sd->notifier;
> -
> -	if (!sd->asd) {
> -		if (!list_empty(&sd->async_list))
> -			v4l2_async_cleanup(sd);
> -		return;
> -	}
> -
>  	mutex_lock(&list_lock);
>  
> -	list_add(&sd->asd->list, &notifier->waiting);
> +	if (sd->asd) {
> +		struct v4l2_async_notifier *notifier = sd->notifier;
>  
> -	if (notifier->unbind)
> -		notifier->unbind(notifier, sd, sd->asd);
> +		list_add(&sd->asd->list, &notifier->waiting);
> +
> +		if (notifier->unbind)
> +			notifier->unbind(notifier, sd, sd->asd);
> +	}
>  
>  	v4l2_async_cleanup(sd);
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 06/32] v4l: async: Use more intuitive names for internal functions
  2017-10-26  7:53     ` Sakari Ailus
@ 2017-10-26 15:39         ` Niklas Söderlund
  -1 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 15:39 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 2017-10-26 10:53:16 +0300, Sakari Ailus wrote:
> Rename internal functions to make the names of the functions better
> describe what they do.
> 
> 	Old name			New name
> 	v4l2_async_test_notify	v4l2_async_match_notify
> 	v4l2_async_belongs	v4l2_async_find_match
> 
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
> Reviewed-by: Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
> Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 19 ++++++++++---------
>  1 file changed, 10 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index cde2cf2ab4b0..8b84fea50c2a 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -60,8 +60,8 @@ static LIST_HEAD(subdev_list);
>  static LIST_HEAD(notifier_list);
>  static DEFINE_MUTEX(list_lock);
>  
> -static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
> -						    struct v4l2_subdev *sd)
> +static struct v4l2_async_subdev *v4l2_async_find_match(
> +	struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd)
>  {
>  	bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *);
>  	struct v4l2_async_subdev *asd;
> @@ -95,9 +95,9 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *
>  	return NULL;
>  }
>  
> -static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
> -				  struct v4l2_subdev *sd,
> -				  struct v4l2_async_subdev *asd)
> +static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> +				   struct v4l2_subdev *sd,
> +				   struct v4l2_async_subdev *asd)
>  {
>  	int ret;
>  
> @@ -187,11 +187,11 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
>  		int ret;
>  
> -		asd = v4l2_async_belongs(notifier, sd);
> +		asd = v4l2_async_find_match(notifier, sd);
>  		if (!asd)
>  			continue;
>  
> -		ret = v4l2_async_test_notify(notifier, sd, asd);
> +		ret = v4l2_async_match_notify(notifier, sd, asd);
>  		if (ret < 0) {
>  			mutex_unlock(&list_lock);
>  			return ret;
> @@ -255,13 +255,14 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	INIT_LIST_HEAD(&sd->async_list);
>  
>  	list_for_each_entry(notifier, &notifier_list, list) {
> -		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
> +		struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
> +								      sd);
>  		int ret;
>  
>  		if (!asd)
>  			continue;
>  
> -		ret = v4l2_async_test_notify(notifier, sd, asd);
> +		ret = v4l2_async_match_notify(notifier, sd, asd);
>  		if (ret)
>  			goto err_unlock;
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 06/32] v4l: async: Use more intuitive names for internal functions
@ 2017-10-26 15:39         ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 15:39 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:16 +0300, Sakari Ailus wrote:
> Rename internal functions to make the names of the functions better
> describe what they do.
> 
> 	Old name			New name
> 	v4l2_async_test_notify	v4l2_async_match_notify
> 	v4l2_async_belongs	v4l2_async_find_match
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 19 ++++++++++---------
>  1 file changed, 10 insertions(+), 9 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index cde2cf2ab4b0..8b84fea50c2a 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -60,8 +60,8 @@ static LIST_HEAD(subdev_list);
>  static LIST_HEAD(notifier_list);
>  static DEFINE_MUTEX(list_lock);
>  
> -static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *notifier,
> -						    struct v4l2_subdev *sd)
> +static struct v4l2_async_subdev *v4l2_async_find_match(
> +	struct v4l2_async_notifier *notifier, struct v4l2_subdev *sd)
>  {
>  	bool (*match)(struct v4l2_subdev *, struct v4l2_async_subdev *);
>  	struct v4l2_async_subdev *asd;
> @@ -95,9 +95,9 @@ static struct v4l2_async_subdev *v4l2_async_belongs(struct v4l2_async_notifier *
>  	return NULL;
>  }
>  
> -static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
> -				  struct v4l2_subdev *sd,
> -				  struct v4l2_async_subdev *asd)
> +static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> +				   struct v4l2_subdev *sd,
> +				   struct v4l2_async_subdev *asd)
>  {
>  	int ret;
>  
> @@ -187,11 +187,11 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
>  		int ret;
>  
> -		asd = v4l2_async_belongs(notifier, sd);
> +		asd = v4l2_async_find_match(notifier, sd);
>  		if (!asd)
>  			continue;
>  
> -		ret = v4l2_async_test_notify(notifier, sd, asd);
> +		ret = v4l2_async_match_notify(notifier, sd, asd);
>  		if (ret < 0) {
>  			mutex_unlock(&list_lock);
>  			return ret;
> @@ -255,13 +255,14 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	INIT_LIST_HEAD(&sd->async_list);
>  
>  	list_for_each_entry(notifier, &notifier_list, list) {
> -		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
> +		struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
> +								      sd);
>  		int ret;
>  
>  		if (!asd)
>  			continue;
>  
> -		ret = v4l2_async_test_notify(notifier, sd, asd);
> +		ret = v4l2_async_match_notify(notifier, sd, asd);
>  		if (ret)
>  			goto err_unlock;
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 08/32] v4l: fwnode: Support generic parsing of graph endpoints in a device
  2017-10-26  7:53 ` [PATCH v16 08/32] v4l: fwnode: Support generic parsing of graph endpoints in a device Sakari Ailus
@ 2017-10-26 21:35   ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 21:35 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:18 +0300, Sakari Ailus wrote:
> Add two functions for parsing devices graph endpoints:
> v4l2_async_notifier_parse_fwnode_endpoints and
> v4l2_async_notifier_parse_fwnode_endpoints_by_port. The former iterates
> over all endpoints whereas the latter only iterates over the endpoints in
> a given port.
> 
> The former is mostly useful for existing drivers that currently implement
> the iteration over all the endpoints themselves whereas the latter is
> especially intended for devices with both sinks and sources: async
> sub-devices for external devices connected to the device's sources will
> have already been set up, or the external sub-devices are part of the
> master device.
> 
> Depends-on: ("device property: preserve usecount for node passed to of_fwnode_graph_get_port_parent()")
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c  |  31 ++++++
>  drivers/media/v4l2-core/v4l2-fwnode.c | 196 ++++++++++++++++++++++++++++++++++
>  include/media/v4l2-async.h            |  24 ++++-
>  include/media/v4l2-fwnode.h           | 118 ++++++++++++++++++++
>  4 files changed, 367 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 8b84fea50c2a..46aebfc75e43 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -22,6 +22,7 @@
>  
>  #include <media/v4l2-async.h>
>  #include <media/v4l2-device.h>
> +#include <media/v4l2-fwnode.h>
>  #include <media/v4l2-subdev.h>
>  
>  static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
> @@ -237,6 +238,36 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
>  }
>  EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>  
> +void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier)
> +{
> +	unsigned int i;
> +
> +	if (!notifier->max_subdevs)
> +		return;
> +
> +	for (i = 0; i < notifier->num_subdevs; i++) {
> +		struct v4l2_async_subdev *asd = notifier->subdevs[i];
> +
> +		switch (asd->match_type) {
> +		case V4L2_ASYNC_MATCH_FWNODE:
> +			fwnode_handle_put(asd->match.fwnode.fwnode);
> +			break;
> +		default:
> +			WARN_ON_ONCE(true);
> +			break;
> +		}
> +
> +		kfree(asd);
> +	}
> +
> +	notifier->max_subdevs = 0;
> +	notifier->num_subdevs = 0;
> +
> +	kvfree(notifier->subdevs);
> +	notifier->subdevs = NULL;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
> +
>  int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  {
>  	struct v4l2_async_notifier *notifier;
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 40b2fbfe8865..df0695b7bbcc 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -19,6 +19,7 @@
>   */
>  #include <linux/acpi.h>
>  #include <linux/kernel.h>
> +#include <linux/mm.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/property.h>
> @@ -26,6 +27,7 @@
>  #include <linux/string.h>
>  #include <linux/types.h>
>  
> +#include <media/v4l2-async.h>
>  #include <media/v4l2-fwnode.h>
>  
>  enum v4l2_fwnode_bus_type {
> @@ -388,6 +390,200 @@ void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
>  }
>  EXPORT_SYMBOL_GPL(v4l2_fwnode_put_link);
>  
> +static int v4l2_async_notifier_realloc(struct v4l2_async_notifier *notifier,
> +				       unsigned int max_subdevs)
> +{
> +	struct v4l2_async_subdev **subdevs;
> +
> +	if (max_subdevs <= notifier->max_subdevs)
> +		return 0;
> +
> +	subdevs = kvmalloc_array(
> +		max_subdevs, sizeof(*notifier->subdevs),
> +		GFP_KERNEL | __GFP_ZERO);
> +	if (!subdevs)
> +		return -ENOMEM;
> +
> +	if (notifier->subdevs) {
> +		memcpy(subdevs, notifier->subdevs,
> +		       sizeof(*subdevs) * notifier->num_subdevs);
> +
> +		kvfree(notifier->subdevs);
> +	}
> +
> +	notifier->subdevs = subdevs;
> +	notifier->max_subdevs = max_subdevs;
> +
> +	return 0;
> +}
> +
> +static int v4l2_async_notifier_fwnode_parse_endpoint(
> +	struct device *dev, struct v4l2_async_notifier *notifier,
> +	struct fwnode_handle *endpoint, unsigned int asd_struct_size,
> +	int (*parse_endpoint)(struct device *dev,
> +			    struct v4l2_fwnode_endpoint *vep,
> +			    struct v4l2_async_subdev *asd))
> +{
> +	struct v4l2_async_subdev *asd;
> +	struct v4l2_fwnode_endpoint *vep;
> +	int ret = 0;
> +
> +	asd = kzalloc(asd_struct_size, GFP_KERNEL);
> +	if (!asd)
> +		return -ENOMEM;
> +
> +	asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> +	asd->match.fwnode.fwnode =
> +		fwnode_graph_get_remote_port_parent(endpoint);
> +	if (!asd->match.fwnode.fwnode) {
> +		dev_warn(dev, "bad remote port parent\n");
> +		ret = -EINVAL;
> +		goto out_err;
> +	}
> +
> +	vep = v4l2_fwnode_endpoint_alloc_parse(endpoint);
> +	if (IS_ERR(vep)) {
> +		ret = PTR_ERR(vep);
> +		dev_warn(dev, "unable to parse V4L2 fwnode endpoint (%d)\n",
> +			 ret);
> +		goto out_err;
> +	}
> +
> +	ret = parse_endpoint ? parse_endpoint(dev, vep, asd) : 0;
> +	if (ret == -ENOTCONN)
> +		dev_dbg(dev, "ignoring port@%u/endpoint@%u\n", vep->base.port,
> +			vep->base.id);
> +	else if (ret < 0)
> +		dev_warn(dev,
> +			 "driver could not parse port@%u/endpoint@%u (%d)\n",
> +			 vep->base.port, vep->base.id, ret);
> +	v4l2_fwnode_endpoint_free(vep);
> +	if (ret < 0)
> +		goto out_err;
> +
> +	notifier->subdevs[notifier->num_subdevs] = asd;
> +	notifier->num_subdevs++;
> +
> +	return 0;
> +
> +out_err:
> +	fwnode_handle_put(asd->match.fwnode.fwnode);
> +	kfree(asd);
> +
> +	return ret == -ENOTCONN ? 0 : ret;
> +}
> +
> +static int __v4l2_async_notifier_parse_fwnode_endpoints(
> +	struct device *dev, struct v4l2_async_notifier *notifier,
> +	size_t asd_struct_size, unsigned int port, bool has_port,
> +	int (*parse_endpoint)(struct device *dev,
> +			    struct v4l2_fwnode_endpoint *vep,
> +			    struct v4l2_async_subdev *asd))
> +{
> +	struct fwnode_handle *fwnode;
> +	unsigned int max_subdevs = notifier->max_subdevs;
> +	int ret;
> +
> +	if (WARN_ON(asd_struct_size < sizeof(struct v4l2_async_subdev)))
> +		return -EINVAL;
> +
> +	for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
> +				     dev_fwnode(dev), fwnode)); ) {
> +		struct fwnode_handle *dev_fwnode;
> +		bool is_available;
> +
> +		dev_fwnode = fwnode_graph_get_port_parent(fwnode);
> +		is_available = fwnode_device_is_available(dev_fwnode);
> +		fwnode_handle_put(dev_fwnode);
> +		if (!is_available)
> +			continue;
> +
> +		if (has_port) {
> +			struct fwnode_endpoint ep;
> +
> +			ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> +			if (ret) {
> +				fwnode_handle_put(fwnode);
> +				return ret;
> +			}
> +
> +			if (ep.port != port)
> +				continue;
> +		}
> +		max_subdevs++;
> +	}
> +
> +	/* No subdevs to add? Return here. */
> +	if (max_subdevs == notifier->max_subdevs)
> +		return 0;
> +
> +	ret = v4l2_async_notifier_realloc(notifier, max_subdevs);
> +	if (ret)
> +		return ret;
> +
> +	for (fwnode = NULL; (fwnode = fwnode_graph_get_next_endpoint(
> +				     dev_fwnode(dev), fwnode)); ) {
> +		struct fwnode_handle *dev_fwnode;
> +		bool is_available;
> +
> +		dev_fwnode = fwnode_graph_get_port_parent(fwnode);
> +		is_available = fwnode_device_is_available(dev_fwnode);
> +		fwnode_handle_put(dev_fwnode);
> +
> +		if (!fwnode_device_is_available(dev_fwnode))
> +			continue;
> +
> +		if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
> +			ret = -EINVAL;
> +			break;
> +		}
> +
> +		if (has_port) {
> +			struct fwnode_endpoint ep;
> +
> +			ret = fwnode_graph_parse_endpoint(fwnode, &ep);
> +			if (ret)
> +				break;
> +
> +			if (ep.port != port)
> +				continue;
> +		}
> +
> +		ret = v4l2_async_notifier_fwnode_parse_endpoint(
> +			dev, notifier, fwnode, asd_struct_size, parse_endpoint);
> +		if (ret < 0)
> +			break;
> +	}
> +
> +	fwnode_handle_put(fwnode);
> +
> +	return ret;
> +}
> +
> +int v4l2_async_notifier_parse_fwnode_endpoints(
> +	struct device *dev, struct v4l2_async_notifier *notifier,
> +	size_t asd_struct_size,
> +	int (*parse_endpoint)(struct device *dev,
> +			    struct v4l2_fwnode_endpoint *vep,
> +			    struct v4l2_async_subdev *asd))
> +{
> +	return __v4l2_async_notifier_parse_fwnode_endpoints(
> +		dev, notifier, asd_struct_size, 0, false, parse_endpoint);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints);
> +
> +int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
> +	struct device *dev, struct v4l2_async_notifier *notifier,
> +	size_t asd_struct_size, unsigned int port,
> +	int (*parse_endpoint)(struct device *dev,
> +			    struct v4l2_fwnode_endpoint *vep,
> +			    struct v4l2_async_subdev *asd))
> +{
> +	return __v4l2_async_notifier_parse_fwnode_endpoints(
> +		dev, notifier, asd_struct_size, port, true, parse_endpoint);
> +}
> +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
>  MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index c69d8c8a66d0..329aeebd1a80 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -18,7 +18,6 @@ struct device;
>  struct device_node;
>  struct v4l2_device;
>  struct v4l2_subdev;
> -struct v4l2_async_notifier;
>  
>  /* A random max subdevice number, used to allocate an array on stack */
>  #define V4L2_MAX_SUBDEVS 128U
> @@ -50,6 +49,10 @@ enum v4l2_async_match_type {
>   * @match:	union of per-bus type matching data sets
>   * @list:	used to link struct v4l2_async_subdev objects, waiting to be
>   *		probed, to a notifier->waiting list
> + *
> + * When this struct is used as a member in a driver specific struct,
> + * the driver specific struct shall contain the &struct
> + * v4l2_async_subdev as its first member.
>   */
>  struct v4l2_async_subdev {
>  	enum v4l2_async_match_type match_type;
> @@ -78,7 +81,8 @@ struct v4l2_async_subdev {
>  /**
>   * struct v4l2_async_notifier - v4l2_device notifier data
>   *
> - * @num_subdevs: number of subdevices
> + * @num_subdevs: number of subdevices used in the subdevs array
> + * @max_subdevs: number of subdevices allocated in the subdevs array
>   * @subdevs:	array of pointers to subdevice descriptors
>   * @v4l2_dev:	pointer to struct v4l2_device
>   * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
> @@ -90,6 +94,7 @@ struct v4l2_async_subdev {
>   */
>  struct v4l2_async_notifier {
>  	unsigned int num_subdevs;
> +	unsigned int max_subdevs;
>  	struct v4l2_async_subdev **subdevs;
>  	struct v4l2_device *v4l2_dev;
>  	struct list_head waiting;
> @@ -121,6 +126,21 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
>  
>  /**
> + * v4l2_async_notifier_cleanup - clean up notifier resources
> + * @notifier: the notifier the resources of which are to be cleaned up
> + *
> + * Release memory resources related to a notifier, including the async
> + * sub-devices allocated for the purposes of the notifier but not the notifier
> + * itself. The user is responsible for calling this function to clean up the
> + * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints.
> + *
> + * There is no harm from calling v4l2_async_notifier_cleanup in other
> + * cases as long as its memory has been zeroed after it has been
> + * allocated.
> + */
> +void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier);
> +
> +/**
>   * v4l2_async_register_subdev - registers a sub-device to the asynchronous
>   * 	subdevice framework
>   *
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index 7adec9851d9e..ac605af9b877 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -25,6 +25,8 @@
>  #include <media/v4l2-mediabus.h>
>  
>  struct fwnode_handle;
> +struct v4l2_async_notifier;
> +struct v4l2_async_subdev;
>  
>  #define V4L2_FWNODE_CSI2_MAX_DATA_LANES	4
>  
> @@ -122,4 +124,120 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
>  			   struct v4l2_fwnode_link *link);
>  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
>  
> +/**
> + * v4l2_async_notifier_parse_fwnode_endpoints - Parse V4L2 fwnode endpoints in a
> + *						device node
> + * @dev: the device the endpoints of which are to be parsed
> + * @notifier: notifier for @dev
> + * @asd_struct_size: size of the driver's async sub-device struct, including
> + *		     sizeof(struct v4l2_async_subdev). The &struct
> + *		     v4l2_async_subdev shall be the first member of
> + *		     the driver's async sub-device struct, i.e. both
> + *		     begin at the same memory address.
> + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> + *		    endpoint. Optional.
> + *		    Return: %0 on success
> + *			    %-ENOTCONN if the endpoint is to be skipped but this
> + *				       should not be considered as an error
> + *			    %-EINVAL if the endpoint configuration is invalid
> + *
> + * Parse the fwnode endpoints of the @dev device and populate the async sub-
> + * devices array of the notifier. The @parse_endpoint callback function is
> + * called for each endpoint with the corresponding async sub-device pointer to
> + * let the caller initialize the driver-specific part of the async sub-device
> + * structure.
> + *
> + * The notifier memory shall be zeroed before this function is called on the
> + * notifier.
> + *
> + * This function may not be called on a registered notifier and may be called on
> + * a notifier only once.
> + *
> + * Do not change the notifier's subdevs array, take references to the subdevs
> + * array itself or change the notifier's num_subdevs field. This is because this
> + * function allocates and reallocates the subdevs array based on parsing
> + * endpoints.
> + *
> + * The &struct v4l2_fwnode_endpoint passed to the callback function
> + * @parse_endpoint is released once the function is finished. If there is a need
> + * to retain that configuration, the user needs to allocate memory for it.
> + *
> + * Any notifier populated using this function must be released with a call to
> + * v4l2_async_notifier_cleanup() after it has been unregistered and the async
> + * sub-devices are no longer in use, even if the function returned an error.
> + *
> + * Return: %0 on success, including when no async sub-devices are found
> + *	   %-ENOMEM if memory allocation failed
> + *	   %-EINVAL if graph or endpoint parsing failed
> + *	   Other error codes as returned by @parse_endpoint
> + */
> +int v4l2_async_notifier_parse_fwnode_endpoints(
> +	struct device *dev, struct v4l2_async_notifier *notifier,
> +	size_t asd_struct_size,
> +	int (*parse_endpoint)(struct device *dev,
> +			      struct v4l2_fwnode_endpoint *vep,
> +			      struct v4l2_async_subdev *asd));
> +
> +/**
> + * v4l2_async_notifier_parse_fwnode_endpoints_by_port - Parse V4L2 fwnode
> + *							endpoints of a port in a
> + *							device node
> + * @dev: the device the endpoints of which are to be parsed
> + * @notifier: notifier for @dev
> + * @asd_struct_size: size of the driver's async sub-device struct, including
> + *		     sizeof(struct v4l2_async_subdev). The &struct
> + *		     v4l2_async_subdev shall be the first member of
> + *		     the driver's async sub-device struct, i.e. both
> + *		     begin at the same memory address.
> + * @port: port number where endpoints are to be parsed
> + * @parse_endpoint: Driver's callback function called on each V4L2 fwnode
> + *		    endpoint. Optional.
> + *		    Return: %0 on success
> + *			    %-ENOTCONN if the endpoint is to be skipped but this
> + *				       should not be considered as an error
> + *			    %-EINVAL if the endpoint configuration is invalid
> + *
> + * This function is just like v4l2_async_notifier_parse_fwnode_endpoints() with
> + * the exception that it only parses endpoints in a given port. This is useful
> + * on devices that have both sinks and sources: the async sub-devices connected
> + * to sources have already been configured by another driver (on capture
> + * devices). In this case the driver must know which ports to parse.
> + *
> + * Parse the fwnode endpoints of the @dev device on a given @port and populate
> + * the async sub-devices array of the notifier. The @parse_endpoint callback
> + * function is called for each endpoint with the corresponding async sub-device
> + * pointer to let the caller initialize the driver-specific part of the async
> + * sub-device structure.
> + *
> + * The notifier memory shall be zeroed before this function is called on the
> + * notifier the first time.
> + *
> + * This function may not be called on a registered notifier and may be called on
> + * a notifier only once per port.
> + *
> + * Do not change the notifier's subdevs array, take references to the subdevs
> + * array itself or change the notifier's num_subdevs field. This is because this
> + * function allocates and reallocates the subdevs array based on parsing
> + * endpoints.
> + *
> + * The &struct v4l2_fwnode_endpoint passed to the callback function
> + * @parse_endpoint is released once the function is finished. If there is a need
> + * to retain that configuration, the user needs to allocate memory for it.
> + *
> + * Any notifier populated using this function must be released with a call to
> + * v4l2_async_notifier_cleanup() after it has been unregistered and the async
> + * sub-devices are no longer in use, even if the function returned an error.
> + *
> + * Return: %0 on success, including when no async sub-devices are found
> + *	   %-ENOMEM if memory allocation failed
> + *	   %-EINVAL if graph or endpoint parsing failed
> + *	   Other error codes as returned by @parse_endpoint
> + */
> +int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
> +	struct device *dev, struct v4l2_async_notifier *notifier,
> +	size_t asd_struct_size, unsigned int port,
> +	int (*parse_endpoint)(struct device *dev,
> +			      struct v4l2_fwnode_endpoint *vep,
> +			      struct v4l2_async_subdev *asd));
> +
>  #endif /* _V4L2_FWNODE_H */
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 13/32] v4l: async: Move async subdev notifier operations to a separate structure
  2017-10-26  7:53 ` [PATCH v16 13/32] v4l: async: Move async subdev notifier operations to a separate structure Sakari Ailus
@ 2017-10-26 21:44   ` Niklas Söderlund
  2017-10-27 14:47   ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 21:44 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:23 +0300, Sakari Ailus wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> The async subdev notifier .bound(), .unbind() and .complete() operations
> are function pointers stored directly in the v4l2_async_subdev
> structure. As the structure isn't immutable, this creates a potential
> security risk as the function pointers are mutable.
> 
> To fix this, move the function pointers to a new
> v4l2_async_subdev_operations structure that can be made const in
> drivers.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/platform/am437x/am437x-vpfe.c    |  8 +++++--
>  drivers/media/platform/atmel/atmel-isc.c       | 10 ++++++---
>  drivers/media/platform/atmel/atmel-isi.c       | 10 ++++++---
>  drivers/media/platform/davinci/vpif_capture.c  |  8 +++++--
>  drivers/media/platform/davinci/vpif_display.c  |  8 +++++--
>  drivers/media/platform/exynos4-is/media-dev.c  |  8 +++++--
>  drivers/media/platform/omap3isp/isp.c          |  6 +++++-
>  drivers/media/platform/pxa_camera.c            |  8 +++++--
>  drivers/media/platform/qcom/camss-8x16/camss.c |  8 +++++--
>  drivers/media/platform/rcar-vin/rcar-core.c    | 10 ++++++---
>  drivers/media/platform/rcar_drif.c             | 10 ++++++---
>  drivers/media/platform/soc_camera/soc_camera.c | 14 ++++++------
>  drivers/media/platform/stm32/stm32-dcmi.c      | 10 ++++++---
>  drivers/media/platform/ti-vpe/cal.c            |  8 +++++--
>  drivers/media/platform/xilinx/xilinx-vipp.c    |  8 +++++--
>  drivers/media/v4l2-core/v4l2-async.c           | 30 ++++++++++++--------------
>  drivers/staging/media/imx/imx-media-dev.c      |  8 +++++--
>  include/media/v4l2-async.h                     | 29 ++++++++++++++++---------
>  18 files changed, 135 insertions(+), 66 deletions(-)
> 
> diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
> index dfcc484cab89..0997c640191d 100644
> --- a/drivers/media/platform/am437x/am437x-vpfe.c
> +++ b/drivers/media/platform/am437x/am437x-vpfe.c
> @@ -2417,6 +2417,11 @@ static int vpfe_async_complete(struct v4l2_async_notifier *notifier)
>  	return vpfe_probe_complete(vpfe);
>  }
>  
> +static const struct v4l2_async_notifier_operations vpfe_async_ops = {
> +	.bound = vpfe_async_bound,
> +	.complete = vpfe_async_complete,
> +};
> +
>  static struct vpfe_config *
>  vpfe_get_pdata(struct platform_device *pdev)
>  {
> @@ -2590,8 +2595,7 @@ static int vpfe_probe(struct platform_device *pdev)
>  
>  	vpfe->notifier.subdevs = vpfe->cfg->asd;
>  	vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd);
> -	vpfe->notifier.bound = vpfe_async_bound;
> -	vpfe->notifier.complete = vpfe_async_complete;
> +	vpfe->notifier.ops = &vpfe_async_ops;
>  	ret = v4l2_async_notifier_register(&vpfe->v4l2_dev,
>  						&vpfe->notifier);
>  	if (ret) {
> diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c
> index 2f8e345d297e..382fe355e616 100644
> --- a/drivers/media/platform/atmel/atmel-isc.c
> +++ b/drivers/media/platform/atmel/atmel-isc.c
> @@ -1637,6 +1637,12 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
>  	return 0;
>  }
>  
> +static const struct v4l2_async_notifier_operations isc_async_ops = {
> +	.bound = isc_async_bound,
> +	.unbind = isc_async_unbind,
> +	.complete = isc_async_complete,
> +};
> +
>  static void isc_subdev_cleanup(struct isc_device *isc)
>  {
>  	struct isc_subdev_entity *subdev_entity;
> @@ -1849,9 +1855,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
>  	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
>  		subdev_entity->notifier.subdevs = &subdev_entity->asd;
>  		subdev_entity->notifier.num_subdevs = 1;
> -		subdev_entity->notifier.bound = isc_async_bound;
> -		subdev_entity->notifier.unbind = isc_async_unbind;
> -		subdev_entity->notifier.complete = isc_async_complete;
> +		subdev_entity->notifier.ops = &isc_async_ops;
>  
>  		ret = v4l2_async_notifier_register(&isc->v4l2_dev,
>  						   &subdev_entity->notifier);
> diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
> index 463c0146915e..e900995143a3 100644
> --- a/drivers/media/platform/atmel/atmel-isi.c
> +++ b/drivers/media/platform/atmel/atmel-isi.c
> @@ -1103,6 +1103,12 @@ static int isi_graph_notify_bound(struct v4l2_async_notifier *notifier,
>  	return 0;
>  }
>  
> +static const struct v4l2_async_notifier_operations isi_graph_notify_ops = {
> +	.bound = isi_graph_notify_bound,
> +	.unbind = isi_graph_notify_unbind,
> +	.complete = isi_graph_notify_complete,
> +};
> +
>  static int isi_graph_parse(struct atmel_isi *isi, struct device_node *node)
>  {
>  	struct device_node *ep = NULL;
> @@ -1150,9 +1156,7 @@ static int isi_graph_init(struct atmel_isi *isi)
>  
>  	isi->notifier.subdevs = subdevs;
>  	isi->notifier.num_subdevs = 1;
> -	isi->notifier.bound = isi_graph_notify_bound;
> -	isi->notifier.unbind = isi_graph_notify_unbind;
> -	isi->notifier.complete = isi_graph_notify_complete;
> +	isi->notifier.ops = &isi_graph_notify_ops;
>  
>  	ret = v4l2_async_notifier_register(&isi->v4l2_dev, &isi->notifier);
>  	if (ret < 0) {
> diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
> index 0ef36cec21d1..a89367ab1e06 100644
> --- a/drivers/media/platform/davinci/vpif_capture.c
> +++ b/drivers/media/platform/davinci/vpif_capture.c
> @@ -1500,6 +1500,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)
>  	return vpif_probe_complete();
>  }
>  
> +static const struct v4l2_async_notifier_operations vpif_async_ops = {
> +	.bound = vpif_async_bound,
> +	.complete = vpif_async_complete,
> +};
> +
>  static struct vpif_capture_config *
>  vpif_capture_get_pdata(struct platform_device *pdev)
>  {
> @@ -1691,8 +1696,7 @@ static __init int vpif_probe(struct platform_device *pdev)
>  	} else {
>  		vpif_obj.notifier.subdevs = vpif_obj.config->asd;
>  		vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
> -		vpif_obj.notifier.bound = vpif_async_bound;
> -		vpif_obj.notifier.complete = vpif_async_complete;
> +		vpif_obj.notifier.ops = &vpif_async_ops;
>  		err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
>  						   &vpif_obj.notifier);
>  		if (err) {
> diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
> index 56fe4e5b396e..ff2f75a328c9 100644
> --- a/drivers/media/platform/davinci/vpif_display.c
> +++ b/drivers/media/platform/davinci/vpif_display.c
> @@ -1232,6 +1232,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)
>  	return vpif_probe_complete();
>  }
>  
> +static const struct v4l2_async_notifier_operations vpif_async_ops = {
> +	.bound = vpif_async_bound,
> +	.complete = vpif_async_complete,
> +};
> +
>  /*
>   * vpif_probe: This function creates device entries by register itself to the
>   * V4L2 driver and initializes fields of each channel objects
> @@ -1313,8 +1318,7 @@ static __init int vpif_probe(struct platform_device *pdev)
>  	} else {
>  		vpif_obj.notifier.subdevs = vpif_obj.config->asd;
>  		vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
> -		vpif_obj.notifier.bound = vpif_async_bound;
> -		vpif_obj.notifier.complete = vpif_async_complete;
> +		vpif_obj.notifier.ops = &vpif_async_ops;
>  		err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
>  						   &vpif_obj.notifier);
>  		if (err) {
> diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
> index d4656d5175d7..c15596b56dc9 100644
> --- a/drivers/media/platform/exynos4-is/media-dev.c
> +++ b/drivers/media/platform/exynos4-is/media-dev.c
> @@ -1405,6 +1405,11 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
>  	return media_device_register(&fmd->media_dev);
>  }
>  
> +static const struct v4l2_async_notifier_operations subdev_notifier_ops = {
> +	.bound = subdev_notifier_bound,
> +	.complete = subdev_notifier_complete,
> +};
> +
>  static int fimc_md_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> @@ -1479,8 +1484,7 @@ static int fimc_md_probe(struct platform_device *pdev)
>  	if (fmd->num_sensors > 0) {
>  		fmd->subdev_notifier.subdevs = fmd->async_subdevs;
>  		fmd->subdev_notifier.num_subdevs = fmd->num_sensors;
> -		fmd->subdev_notifier.bound = subdev_notifier_bound;
> -		fmd->subdev_notifier.complete = subdev_notifier_complete;
> +		fmd->subdev_notifier.ops = &subdev_notifier_ops;
>  		fmd->num_sensors = 0;
>  
>  		ret = v4l2_async_notifier_register(&fmd->v4l2_dev,
> diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
> index 35687c9707e0..b7ff3842afc0 100644
> --- a/drivers/media/platform/omap3isp/isp.c
> +++ b/drivers/media/platform/omap3isp/isp.c
> @@ -2171,6 +2171,10 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
>  	return media_device_register(&isp->media_dev);
>  }
>  
> +static const struct v4l2_async_notifier_operations isp_subdev_notifier_ops = {
> +	.complete = isp_subdev_notifier_complete,
> +};
> +
>  /*
>   * isp_probe - Probe ISP platform device
>   * @pdev: Pointer to ISP platform device
> @@ -2341,7 +2345,7 @@ static int isp_probe(struct platform_device *pdev)
>  	if (ret < 0)
>  		goto error_register_entities;
>  
> -	isp->notifier.complete = isp_subdev_notifier_complete;
> +	isp->notifier.ops = &isp_subdev_notifier_ops;
>  
>  	ret = v4l2_async_notifier_register(&isp->v4l2_dev, &isp->notifier);
>  	if (ret)
> diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
> index edca993c2b1f..9d3f0cb1d95a 100644
> --- a/drivers/media/platform/pxa_camera.c
> +++ b/drivers/media/platform/pxa_camera.c
> @@ -2221,6 +2221,11 @@ static void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier,
>  	mutex_unlock(&pcdev->mlock);
>  }
>  
> +static const struct v4l2_async_notifier_operations pxa_camera_sensor_ops = {
> +	.bound = pxa_camera_sensor_bound,
> +	.unbind = pxa_camera_sensor_unbind,
> +};
> +
>  /*
>   * Driver probe, remove, suspend and resume operations
>   */
> @@ -2489,8 +2494,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
>  	pcdev->asds[0] = &pcdev->asd;
>  	pcdev->notifier.subdevs = pcdev->asds;
>  	pcdev->notifier.num_subdevs = 1;
> -	pcdev->notifier.bound = pxa_camera_sensor_bound;
> -	pcdev->notifier.unbind = pxa_camera_sensor_unbind;
> +	pcdev->notifier.ops = &pxa_camera_sensor_ops;
>  
>  	if (!of_have_populated_dt())
>  		pcdev->asd.match_type = V4L2_ASYNC_MATCH_I2C;
> diff --git a/drivers/media/platform/qcom/camss-8x16/camss.c b/drivers/media/platform/qcom/camss-8x16/camss.c
> index a3760b5dd1d1..390a42c17b66 100644
> --- a/drivers/media/platform/qcom/camss-8x16/camss.c
> +++ b/drivers/media/platform/qcom/camss-8x16/camss.c
> @@ -601,6 +601,11 @@ static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async)
>  	return media_device_register(&camss->media_dev);
>  }
>  
> +static const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = {
> +	.bound = camss_subdev_notifier_bound,
> +	.complete = camss_subdev_notifier_complete,
> +};
> +
>  static const struct media_device_ops camss_media_ops = {
>  	.link_notify = v4l2_pipeline_link_notify,
>  };
> @@ -655,8 +660,7 @@ static int camss_probe(struct platform_device *pdev)
>  		goto err_register_entities;
>  
>  	if (camss->notifier.num_subdevs) {
> -		camss->notifier.bound = camss_subdev_notifier_bound;
> -		camss->notifier.complete = camss_subdev_notifier_complete;
> +		camss->notifier.ops = &camss_subdev_notifier_ops;
>  
>  		ret = v4l2_async_notifier_register(&camss->v4l2_dev,
>  						   &camss->notifier);
> diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
> index 380288658601..108d776f3265 100644
> --- a/drivers/media/platform/rcar-vin/rcar-core.c
> +++ b/drivers/media/platform/rcar-vin/rcar-core.c
> @@ -134,6 +134,12 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
>  
>  	return 0;
>  }
> +static const struct v4l2_async_notifier_operations rvin_digital_notify_ops = {
> +	.bound = rvin_digital_notify_bound,
> +	.unbind = rvin_digital_notify_unbind,
> +	.complete = rvin_digital_notify_complete,
> +};
> +
>  
>  static int rvin_digital_parse_v4l2(struct device *dev,
>  				   struct v4l2_fwnode_endpoint *vep,
> @@ -183,9 +189,7 @@ static int rvin_digital_graph_init(struct rvin_dev *vin)
>  	vin_dbg(vin, "Found digital subdevice %pOF\n",
>  		to_of_node(vin->digital->asd.match.fwnode.fwnode));
>  
> -	vin->notifier.bound = rvin_digital_notify_bound;
> -	vin->notifier.unbind = rvin_digital_notify_unbind;
> -	vin->notifier.complete = rvin_digital_notify_complete;
> +	vin->notifier.ops = &rvin_digital_notify_ops;
>  	ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
>  	if (ret < 0) {
>  		vin_err(vin, "Notifier registration failed\n");
> diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
> index 2c6afd38b78a..63c94f4028a7 100644
> --- a/drivers/media/platform/rcar_drif.c
> +++ b/drivers/media/platform/rcar_drif.c
> @@ -1185,6 +1185,12 @@ static int rcar_drif_notify_complete(struct v4l2_async_notifier *notifier)
>  	return ret;
>  }
>  
> +static const struct v4l2_async_notifier_operations rcar_drif_notify_ops = {
> +	.bound = rcar_drif_notify_bound,
> +	.unbind = rcar_drif_notify_unbind,
> +	.complete = rcar_drif_notify_complete,
> +};
> +
>  /* Read endpoint properties */
>  static void rcar_drif_get_ep_properties(struct rcar_drif_sdr *sdr,
>  					struct fwnode_handle *fwnode)
> @@ -1347,9 +1353,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr)
>  	if (ret)
>  		goto error;
>  
> -	sdr->notifier.bound = rcar_drif_notify_bound;
> -	sdr->notifier.unbind = rcar_drif_notify_unbind;
> -	sdr->notifier.complete = rcar_drif_notify_complete;
> +	sdr->notifier.ops = &rcar_drif_notify_ops;
>  
>  	/* Register notifier */
>  	ret = v4l2_async_notifier_register(&sdr->v4l2_dev, &sdr->notifier);
> diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
> index 1f3c450c7a69..916ff68b73d4 100644
> --- a/drivers/media/platform/soc_camera/soc_camera.c
> +++ b/drivers/media/platform/soc_camera/soc_camera.c
> @@ -1391,6 +1391,12 @@ static int soc_camera_async_complete(struct v4l2_async_notifier *notifier)
>  	return 0;
>  }
>  
> +static const struct v4l2_async_notifier_operations soc_camera_async_ops = {
> +	.bound = soc_camera_async_bound,
> +	.unbind = soc_camera_async_unbind,
> +	.complete = soc_camera_async_complete,
> +};
> +
>  static int scan_async_group(struct soc_camera_host *ici,
>  			    struct v4l2_async_subdev **asd, unsigned int size)
>  {
> @@ -1437,9 +1443,7 @@ static int scan_async_group(struct soc_camera_host *ici,
>  
>  	sasc->notifier.subdevs = asd;
>  	sasc->notifier.num_subdevs = size;
> -	sasc->notifier.bound = soc_camera_async_bound;
> -	sasc->notifier.unbind = soc_camera_async_unbind;
> -	sasc->notifier.complete = soc_camera_async_complete;
> +	sasc->notifier.ops = &soc_camera_async_ops;
>  
>  	icd->sasc = sasc;
>  	icd->parent = ici->v4l2_dev.dev;
> @@ -1537,9 +1541,7 @@ static int soc_of_bind(struct soc_camera_host *ici,
>  
>  	sasc->notifier.subdevs = &info->subdev;
>  	sasc->notifier.num_subdevs = 1;
> -	sasc->notifier.bound = soc_camera_async_bound;
> -	sasc->notifier.unbind = soc_camera_async_unbind;
> -	sasc->notifier.complete = soc_camera_async_complete;
> +	sasc->notifier.ops = &soc_camera_async_ops;
>  
>  	icd->sasc = sasc;
>  	icd->parent = ici->v4l2_dev.dev;
> diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
> index 35ba6f211b79..ac4c450a6c7d 100644
> --- a/drivers/media/platform/stm32/stm32-dcmi.c
> +++ b/drivers/media/platform/stm32/stm32-dcmi.c
> @@ -1495,6 +1495,12 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier,
>  	return 0;
>  }
>  
> +static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = {
> +	.bound = dcmi_graph_notify_bound,
> +	.unbind = dcmi_graph_notify_unbind,
> +	.complete = dcmi_graph_notify_complete,
> +};
> +
>  static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node)
>  {
>  	struct device_node *ep = NULL;
> @@ -1542,9 +1548,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
>  
>  	dcmi->notifier.subdevs = subdevs;
>  	dcmi->notifier.num_subdevs = 1;
> -	dcmi->notifier.bound = dcmi_graph_notify_bound;
> -	dcmi->notifier.unbind = dcmi_graph_notify_unbind;
> -	dcmi->notifier.complete = dcmi_graph_notify_complete;
> +	dcmi->notifier.ops = &dcmi_graph_notify_ops;
>  
>  	ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier);
>  	if (ret < 0) {
> diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c
> index 42e383a48ffe..8b586c864524 100644
> --- a/drivers/media/platform/ti-vpe/cal.c
> +++ b/drivers/media/platform/ti-vpe/cal.c
> @@ -1522,6 +1522,11 @@ static int cal_async_complete(struct v4l2_async_notifier *notifier)
>  	return 0;
>  }
>  
> +static const struct v4l2_async_notifier_operations cal_async_ops = {
> +	.bound = cal_async_bound,
> +	.complete = cal_async_complete,
> +};
> +
>  static int cal_complete_ctx(struct cal_ctx *ctx)
>  {
>  	struct video_device *vfd;
> @@ -1736,8 +1741,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
>  	ctx->asd_list[0] = asd;
>  	ctx->notifier.subdevs = ctx->asd_list;
>  	ctx->notifier.num_subdevs = 1;
> -	ctx->notifier.bound = cal_async_bound;
> -	ctx->notifier.complete = cal_async_complete;
> +	ctx->notifier.ops = &cal_async_ops;
>  	ret = v4l2_async_notifier_register(&ctx->v4l2_dev,
>  					   &ctx->notifier);
>  	if (ret) {
> diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
> index ebfdf334d99c..d881cf09876d 100644
> --- a/drivers/media/platform/xilinx/xilinx-vipp.c
> +++ b/drivers/media/platform/xilinx/xilinx-vipp.c
> @@ -351,6 +351,11 @@ static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
>  	return -EINVAL;
>  }
>  
> +static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = {
> +	.bound = xvip_graph_notify_bound,
> +	.complete = xvip_graph_notify_complete,
> +};
> +
>  static int xvip_graph_parse_one(struct xvip_composite_device *xdev,
>  				struct device_node *node)
>  {
> @@ -548,8 +553,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
>  
>  	xdev->notifier.subdevs = subdevs;
>  	xdev->notifier.num_subdevs = num_subdevs;
> -	xdev->notifier.bound = xvip_graph_notify_bound;
> -	xdev->notifier.complete = xvip_graph_notify_complete;
> +	xdev->notifier.ops = &xvip_graph_notify_ops;
>  
>  	ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier);
>  	if (ret < 0) {
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 46aebfc75e43..9d6fc5f25619 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -102,16 +102,16 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  {
>  	int ret;
>  
> -	if (notifier->bound) {
> -		ret = notifier->bound(notifier, sd, asd);
> +	if (notifier->ops->bound) {
> +		ret = notifier->ops->bound(notifier, sd, asd);
>  		if (ret < 0)
>  			return ret;
>  	}
>  
>  	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
>  	if (ret < 0) {
> -		if (notifier->unbind)
> -			notifier->unbind(notifier, sd, asd);
> +		if (notifier->ops->unbind)
> +			notifier->ops->unbind(notifier, sd, asd);
>  		return ret;
>  	}
>  
> @@ -140,9 +140,8 @@ static void v4l2_async_notifier_unbind_all_subdevs(
>  	struct v4l2_subdev *sd, *tmp;
>  
>  	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> -		if (notifier->unbind)
> -			notifier->unbind(notifier, sd, sd->asd);
> -
> +		if (notifier->ops->unbind)
> +			notifier->ops->unbind(notifier, sd, sd->asd);
>  		v4l2_async_cleanup(sd);
>  
>  		list_move(&sd->async_list, &subdev_list);
> @@ -199,8 +198,8 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  		}
>  	}
>  
> -	if (list_empty(&notifier->waiting) && notifier->complete) {
> -		ret = notifier->complete(notifier);
> +	if (list_empty(&notifier->waiting) && notifier->ops->complete) {
> +		ret = notifier->ops->complete(notifier);
>  		if (ret)
>  			goto err_complete;
>  	}
> @@ -297,10 +296,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  		if (ret)
>  			goto err_unlock;
>  
> -		if (!list_empty(&notifier->waiting) || !notifier->complete)
> +		if (!list_empty(&notifier->waiting) || !notifier->ops->complete)
>  			goto out_unlock;
>  
> -		ret = notifier->complete(notifier);
> +		ret = notifier->ops->complete(notifier);
>  		if (ret)
>  			goto err_cleanup;
>  
> @@ -316,9 +315,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	return 0;
>  
>  err_cleanup:
> -	if (notifier->unbind)
> -		notifier->unbind(notifier, sd, sd->asd);
> -
> +	if (notifier->ops->unbind)
> +		notifier->ops->unbind(notifier, sd, sd->asd);
>  	v4l2_async_cleanup(sd);
>  
>  err_unlock:
> @@ -337,8 +335,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  
>  		list_add(&sd->asd->list, &notifier->waiting);
>  
> -		if (notifier->unbind)
> -			notifier->unbind(notifier, sd, sd->asd);
> +		if (notifier->ops->unbind)
> +			notifier->ops->unbind(notifier, sd, sd->asd);
>  	}
>  
>  	v4l2_async_cleanup(sd);
> diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
> index b55e5ebba8b4..47c4c954fed5 100644
> --- a/drivers/staging/media/imx/imx-media-dev.c
> +++ b/drivers/staging/media/imx/imx-media-dev.c
> @@ -440,6 +440,11 @@ static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
>  	return media_device_register(&imxmd->md);
>  }
>  
> +static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
> +	.bound = imx_media_subdev_bound,
> +	.complete = imx_media_probe_complete,
> +};
> +
>  /*
>   * adds controls to a video device from an entity subdevice.
>   * Continues upstream from the entity's sink pads.
> @@ -608,8 +613,7 @@ static int imx_media_probe(struct platform_device *pdev)
>  
>  	/* prepare the async subdev notifier and register it */
>  	imxmd->subdev_notifier.subdevs = imxmd->async_ptrs;
> -	imxmd->subdev_notifier.bound = imx_media_subdev_bound;
> -	imxmd->subdev_notifier.complete = imx_media_probe_complete;
> +	imxmd->subdev_notifier.ops = &imx_media_subdev_ops;
>  	ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
>  					   &imxmd->subdev_notifier);
>  	if (ret) {
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 329aeebd1a80..68606afb5ef9 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -18,6 +18,7 @@ struct device;
>  struct device_node;
>  struct v4l2_device;
>  struct v4l2_subdev;
> +struct v4l2_async_notifier;
>  
>  /* A random max subdevice number, used to allocate an array on stack */
>  #define V4L2_MAX_SUBDEVS 128U
> @@ -79,8 +80,25 @@ struct v4l2_async_subdev {
>  };
>  
>  /**
> + * struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations
> + * @bound:	a subdevice driver has successfully probed one of the subdevices
> + * @complete:	all subdevices have been probed successfully
> + * @unbind:	a subdevice is leaving
> + */
> +struct v4l2_async_notifier_operations {
> +	int (*bound)(struct v4l2_async_notifier *notifier,
> +		     struct v4l2_subdev *subdev,
> +		     struct v4l2_async_subdev *asd);
> +	int (*complete)(struct v4l2_async_notifier *notifier);
> +	void (*unbind)(struct v4l2_async_notifier *notifier,
> +		       struct v4l2_subdev *subdev,
> +		       struct v4l2_async_subdev *asd);
> +};
> +
> +/**
>   * struct v4l2_async_notifier - v4l2_device notifier data
>   *
> + * @ops:	notifier operations
>   * @num_subdevs: number of subdevices used in the subdevs array
>   * @max_subdevs: number of subdevices allocated in the subdevs array
>   * @subdevs:	array of pointers to subdevice descriptors
> @@ -88,11 +106,9 @@ struct v4l2_async_subdev {
>   * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
>   * @done:	list of struct v4l2_subdev, already probed
>   * @list:	member in a global list of notifiers
> - * @bound:	a subdevice driver has successfully probed one of subdevices
> - * @complete:	all subdevices have been probed successfully
> - * @unbind:	a subdevice is leaving
>   */
>  struct v4l2_async_notifier {
> +	const struct v4l2_async_notifier_operations *ops;
>  	unsigned int num_subdevs;
>  	unsigned int max_subdevs;
>  	struct v4l2_async_subdev **subdevs;
> @@ -100,13 +116,6 @@ struct v4l2_async_notifier {
>  	struct list_head waiting;
>  	struct list_head done;
>  	struct list_head list;
> -	int (*bound)(struct v4l2_async_notifier *notifier,
> -		     struct v4l2_subdev *subdev,
> -		     struct v4l2_async_subdev *asd);
> -	int (*complete)(struct v4l2_async_notifier *notifier);
> -	void (*unbind)(struct v4l2_async_notifier *notifier,
> -		       struct v4l2_subdev *subdev,
> -		       struct v4l2_async_subdev *asd);
>  };
>  
>  /**
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 14/32] v4l: async: Introduce helpers for calling async ops callbacks
  2017-10-26  7:53 ` [PATCH v16 14/32] v4l: async: Introduce helpers for calling async ops callbacks Sakari Ailus
@ 2017-10-26 21:46   ` Niklas Söderlund
  2017-10-27 14:48   ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 21:46 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:24 +0300, Sakari Ailus wrote:
> Add three helper functions to call async operations callbacks. Besides
> simplifying callbacks, this allows async notifiers to have no ops set,
> i.e. it can be left NULL.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 56 +++++++++++++++++++++++++-----------
>  1 file changed, 39 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 9d6fc5f25619..e170682dae78 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -25,6 +25,34 @@
>  #include <media/v4l2-fwnode.h>
>  #include <media/v4l2-subdev.h>
>  
> +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
> +					  struct v4l2_subdev *subdev,
> +					  struct v4l2_async_subdev *asd)
> +{
> +	if (!n->ops || !n->ops->bound)
> +		return 0;
> +
> +	return n->ops->bound(n, subdev, asd);
> +}
> +
> +static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
> +					    struct v4l2_subdev *subdev,
> +					    struct v4l2_async_subdev *asd)
> +{
> +	if (!n->ops || !n->ops->unbind)
> +		return;
> +
> +	n->ops->unbind(n, subdev, asd);
> +}
> +
> +static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
> +{
> +	if (!n->ops || !n->ops->complete)
> +		return 0;
> +
> +	return n->ops->complete(n);
> +}
> +
>  static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
>  {
>  #if IS_ENABLED(CONFIG_I2C)
> @@ -102,16 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  {
>  	int ret;
>  
> -	if (notifier->ops->bound) {
> -		ret = notifier->ops->bound(notifier, sd, asd);
> -		if (ret < 0)
> -			return ret;
> -	}
> +	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
> +	if (ret < 0)
> +		return ret;
>  
>  	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
>  	if (ret < 0) {
> -		if (notifier->ops->unbind)
> -			notifier->ops->unbind(notifier, sd, asd);
> +		v4l2_async_notifier_call_unbind(notifier, sd, asd);
>  		return ret;
>  	}
>  
> @@ -140,8 +165,7 @@ static void v4l2_async_notifier_unbind_all_subdevs(
>  	struct v4l2_subdev *sd, *tmp;
>  
>  	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> -		if (notifier->ops->unbind)
> -			notifier->ops->unbind(notifier, sd, sd->asd);
> +		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>  		v4l2_async_cleanup(sd);
>  
>  		list_move(&sd->async_list, &subdev_list);
> @@ -198,8 +222,8 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  		}
>  	}
>  
> -	if (list_empty(&notifier->waiting) && notifier->ops->complete) {
> -		ret = notifier->ops->complete(notifier);
> +	if (list_empty(&notifier->waiting)) {
> +		ret = v4l2_async_notifier_call_complete(notifier);
>  		if (ret)
>  			goto err_complete;
>  	}
> @@ -296,10 +320,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  		if (ret)
>  			goto err_unlock;
>  
> -		if (!list_empty(&notifier->waiting) || !notifier->ops->complete)
> +		if (!list_empty(&notifier->waiting))
>  			goto out_unlock;
>  
> -		ret = notifier->ops->complete(notifier);
> +		ret = v4l2_async_notifier_call_complete(notifier);
>  		if (ret)
>  			goto err_cleanup;
>  
> @@ -315,8 +339,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	return 0;
>  
>  err_cleanup:
> -	if (notifier->ops->unbind)
> -		notifier->ops->unbind(notifier, sd, sd->asd);
> +	v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>  	v4l2_async_cleanup(sd);
>  
>  err_unlock:
> @@ -335,8 +358,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  
>  		list_add(&sd->asd->list, &notifier->waiting);
>  
> -		if (notifier->ops->unbind)
> -			notifier->ops->unbind(notifier, sd, sd->asd);
> +		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>  	}
>  
>  	v4l2_async_cleanup(sd);
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 15/32] v4l: async: Register sub-devices before calling bound callback
  2017-10-26  7:53 ` [PATCH v16 15/32] v4l: async: Register sub-devices before calling bound callback Sakari Ailus
@ 2017-10-26 21:52       ` Niklas Söderlund
  2017-10-27 14:49   ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 21:52 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 2017-10-26 10:53:25 +0300, Sakari Ailus wrote:
> Register the sub-device before calling the notifier's bound callback.
> Doing this the other way around is problematic as the struct v4l2_device
> has not assigned for the sub-device yet and may be required by the bound
> callback.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index e170682dae78..46db85685894 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -130,13 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  {
>  	int ret;
>  
> -	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
> +	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
>  	if (ret < 0)
>  		return ret;
>  
> -	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> +	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
>  	if (ret < 0) {
> -		v4l2_async_notifier_call_unbind(notifier, sd, asd);
> +		v4l2_device_unregister_subdev(sd);
>  		return ret;
>  	}
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 15/32] v4l: async: Register sub-devices before calling bound callback
@ 2017-10-26 21:52       ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 21:52 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:25 +0300, Sakari Ailus wrote:
> Register the sub-device before calling the notifier's bound callback.
> Doing this the other way around is problematic as the struct v4l2_device
> has not assigned for the sub-device yet and may be required by the bound
> callback.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index e170682dae78..46db85685894 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -130,13 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  {
>  	int ret;
>  
> -	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
> +	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
>  	if (ret < 0)
>  		return ret;
>  
> -	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> +	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
>  	if (ret < 0) {
> -		v4l2_async_notifier_call_unbind(notifier, sd, asd);
> +		v4l2_device_unregister_subdev(sd);
>  		return ret;
>  	}
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 16/32] v4l: async: Allow async notifier register call succeed with no subdevs
  2017-10-26  7:53 ` [PATCH v16 16/32] v4l: async: Allow async notifier register call succeed with no subdevs Sakari Ailus
@ 2017-10-26 22:00       ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 22:00 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

On 2017-10-26 10:53:26 +0300, Sakari Ailus wrote:
> The information on how many async sub-devices would be bindable to a
> notifier is typically dependent on information from platform firmware and
> it's not driver's business to be aware of that.
> 
> Many V4L2 main drivers are perfectly usable (and useful) without async
> sub-devices and so if there aren't any around, just proceed call the
> notifier's complete callback immediately without registering the notifier
> itself.
> 
> If a driver needs to check whether there are async sub-devices available,
> it can be done by inspecting the notifier's num_subdevs field which tells
> the number of async sub-devices.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas-1zkq55x86MTxsAP9Fp7wbw@public.gmane.org>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 46db85685894..1b536d68cedf 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -180,14 +180,22 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  	int ret;
>  	int i;
>  
> -	if (!v4l2_dev || !notifier->num_subdevs ||
> -	    notifier->num_subdevs > V4L2_MAX_SUBDEVS)
> +	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
>  		return -EINVAL;
>  
>  	notifier->v4l2_dev = v4l2_dev;
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> +	if (!notifier->num_subdevs) {
> +		int ret;
> +
> +		ret = v4l2_async_notifier_call_complete(notifier);
> +		notifier->v4l2_dev = NULL;
> +
> +		return ret;
> +	}
> +
>  	for (i = 0; i < notifier->num_subdevs; i++) {
>  		asd = notifier->subdevs[i];
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 16/32] v4l: async: Allow async notifier register call succeed with no subdevs
@ 2017-10-26 22:00       ` Niklas Söderlund
  0 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 22:00 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:26 +0300, Sakari Ailus wrote:
> The information on how many async sub-devices would be bindable to a
> notifier is typically dependent on information from platform firmware and
> it's not driver's business to be aware of that.
> 
> Many V4L2 main drivers are perfectly usable (and useful) without async
> sub-devices and so if there aren't any around, just proceed call the
> notifier's complete callback immediately without registering the notifier
> itself.
> 
> If a driver needs to check whether there are async sub-devices available,
> it can be done by inspecting the notifier's num_subdevs field which tells
> the number of async sub-devices.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 46db85685894..1b536d68cedf 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -180,14 +180,22 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  	int ret;
>  	int i;
>  
> -	if (!v4l2_dev || !notifier->num_subdevs ||
> -	    notifier->num_subdevs > V4L2_MAX_SUBDEVS)
> +	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
>  		return -EINVAL;
>  
>  	notifier->v4l2_dev = v4l2_dev;
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> +	if (!notifier->num_subdevs) {
> +		int ret;
> +
> +		ret = v4l2_async_notifier_call_complete(notifier);
> +		notifier->v4l2_dev = NULL;
> +
> +		return ret;
> +	}
> +
>  	for (i = 0; i < notifier->num_subdevs; i++) {
>  		asd = notifier->subdevs[i];
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 17/32] v4l: async: Prepare for async sub-device notifiers
  2017-10-26  7:53 ` [PATCH v16 17/32] v4l: async: Prepare for async sub-device notifiers Sakari Ailus
@ 2017-10-26 22:10   ` Niklas Söderlund
  2017-10-27  8:10     ` Niklas Söderlund
  2017-10-27  8:26   ` [PATCH v16.1 " Sakari Ailus
  1 sibling, 1 reply; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-26 22:10 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:27 +0300, Sakari Ailus wrote:
> Refactor the V4L2 async framework a little in preparation for async
> sub-device notifiers. This avoids making some structural changes in the
> patch actually implementing sub-device notifiers, making that patch easier
> to review.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 71 ++++++++++++++++++++++++++----------
>  1 file changed, 52 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 1b536d68cedf..eb31d96254d1 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
>  }
>  
>  static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> +				   struct v4l2_device *v4l2_dev,
>  				   struct v4l2_subdev *sd,
>  				   struct v4l2_async_subdev *asd)
>  {
>  	int ret;
>  
> -	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> +	ret = v4l2_device_register_subdev(v4l2_dev, sd);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -151,6 +152,31 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  	return 0;
>  }
>  
> +/* Test all async sub-devices in a notifier for a match. */
> +static int v4l2_async_notifier_try_all_subdevs(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
> +	struct v4l2_subdev *sd, *tmp;
> +
> +	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> +		struct v4l2_async_subdev *asd;
> +		int ret;
> +
> +		asd = v4l2_async_find_match(notifier, sd);
> +		if (!asd)
> +			continue;
> +
> +		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
> +		if (ret < 0) {
> +			mutex_unlock(&list_lock);
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +
>  static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  {
>  	v4l2_device_unregister_subdev(sd);
> @@ -172,18 +198,15 @@ static void v4l2_async_notifier_unbind_all_subdevs(
>  	}
>  }
>  
> -int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> -				 struct v4l2_async_notifier *notifier)
> +static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  {
> -	struct v4l2_subdev *sd, *tmp;
>  	struct v4l2_async_subdev *asd;
>  	int ret;
>  	int i;
>  
> -	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
> +	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
>  		return -EINVAL;
>  
> -	notifier->v4l2_dev = v4l2_dev;
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> @@ -216,18 +239,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  
>  	mutex_lock(&list_lock);
>  
> -	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> -		int ret;
> -
> -		asd = v4l2_async_find_match(notifier, sd);
> -		if (!asd)
> -			continue;
> -
> -		ret = v4l2_async_match_notify(notifier, sd, asd);
> -		if (ret < 0) {
> -			mutex_unlock(&list_lock);
> -			return ret;
> -		}
> +	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> +	if (ret) {
> +		mutex_unlock(&list_lock);
> +		return ret;
>  	}
>  
>  	if (list_empty(&notifier->waiting)) {
> @@ -250,6 +265,23 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  
>  	return ret;
>  }
> +
> +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> +				 struct v4l2_async_notifier *notifier)
> +{
> +	int ret;
> +
> +	if (WARN_ON(!v4l2_dev))
> +		return -EINVAL;
> +
> +	notifier->v4l2_dev = v4l2_dev;
> +
> +	ret = __v4l2_async_notifier_register(notifier);
> +	if (ret)
> +		notifier->v4l2_dev = NULL;
> +
> +	return ret;
> +}
>  EXPORT_SYMBOL(v4l2_async_notifier_register);
>  
>  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> @@ -324,7 +356,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  		if (!asd)
>  			continue;
>  
> -		ret = v4l2_async_match_notify(notifier, sd, asd);
> +		ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd,
> +					      asd);
>  		if (ret)
>  			goto err_unlock;
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 17/32] v4l: async: Prepare for async sub-device notifiers
  2017-10-26 22:10   ` Niklas Söderlund
@ 2017-10-27  8:10     ` Niklas Söderlund
  2017-10-27  8:30       ` Sakari Ailus
  0 siblings, 1 reply; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-27  8:10 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

Hi Sakari,

On 2017-10-27 00:10:51 +0200, Niklas Söderlund wrote:
> On 2017-10-26 10:53:27 +0300, Sakari Ailus wrote:
> > Refactor the V4L2 async framework a little in preparation for async
> > sub-device notifiers. This avoids making some structural changes in the
> > patch actually implementing sub-device notifiers, making that patch easier
> > to review.
> > 
> > Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> > Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> 
> Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

I'm sorry I acted to soon, I think I found a small issue with this 
patch, see bellow. With that fixed feel free to attach my ack.

> 
> > ---
> >  drivers/media/v4l2-core/v4l2-async.c | 71 ++++++++++++++++++++++++++----------
> >  1 file changed, 52 insertions(+), 19 deletions(-)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index 1b536d68cedf..eb31d96254d1 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
> >  }
> >  
> >  static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> > +				   struct v4l2_device *v4l2_dev,
> >  				   struct v4l2_subdev *sd,
> >  				   struct v4l2_async_subdev *asd)
> >  {
> >  	int ret;
> >  
> > -	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> > +	ret = v4l2_device_register_subdev(v4l2_dev, sd);
> >  	if (ret < 0)
> >  		return ret;
> >  
> > @@ -151,6 +152,31 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> >  	return 0;
> >  }
> >  
> > +/* Test all async sub-devices in a notifier for a match. */
> > +static int v4l2_async_notifier_try_all_subdevs(
> > +	struct v4l2_async_notifier *notifier)
> > +{
> > +	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
> > +	struct v4l2_subdev *sd, *tmp;
> > +
> > +	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> > +		struct v4l2_async_subdev *asd;
> > +		int ret;
> > +
> > +		asd = v4l2_async_find_match(notifier, sd);
> > +		if (!asd)
> > +			continue;
> > +
> > +		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
> > +		if (ret < 0) {
> > +			mutex_unlock(&list_lock);

The mutex should not be unlocked here, as the caller will also unlock it 
if ret is none zero. You fix this in 18/32 so the end result is OK but I 
think its better to fix this in this patch.

> > +			return ret;
> > +		}
> > +	}
> > +
> > +	return 0;
> > +}
> > +
> >  static void v4l2_async_cleanup(struct v4l2_subdev *sd)
> >  {
> >  	v4l2_device_unregister_subdev(sd);
> > @@ -172,18 +198,15 @@ static void v4l2_async_notifier_unbind_all_subdevs(
> >  	}
> >  }
> >  
> > -int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> > -				 struct v4l2_async_notifier *notifier)
> > +static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  {
> > -	struct v4l2_subdev *sd, *tmp;
> >  	struct v4l2_async_subdev *asd;
> >  	int ret;
> >  	int i;
> >  
> > -	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
> > +	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
> >  		return -EINVAL;
> >  
> > -	notifier->v4l2_dev = v4l2_dev;
> >  	INIT_LIST_HEAD(&notifier->waiting);
> >  	INIT_LIST_HEAD(&notifier->done);
> >  
> > @@ -216,18 +239,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> >  
> >  	mutex_lock(&list_lock);
> >  
> > -	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> > -		int ret;
> > -
> > -		asd = v4l2_async_find_match(notifier, sd);
> > -		if (!asd)
> > -			continue;
> > -
> > -		ret = v4l2_async_match_notify(notifier, sd, asd);
> > -		if (ret < 0) {
> > -			mutex_unlock(&list_lock);
> > -			return ret;
> > -		}
> > +	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> > +	if (ret) {
> > +		mutex_unlock(&list_lock);
> > +		return ret;
> >  	}
> >  
> >  	if (list_empty(&notifier->waiting)) {
> > @@ -250,6 +265,23 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> >  
> >  	return ret;
> >  }
> > +
> > +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> > +				 struct v4l2_async_notifier *notifier)
> > +{
> > +	int ret;
> > +
> > +	if (WARN_ON(!v4l2_dev))
> > +		return -EINVAL;
> > +
> > +	notifier->v4l2_dev = v4l2_dev;
> > +
> > +	ret = __v4l2_async_notifier_register(notifier);
> > +	if (ret)
> > +		notifier->v4l2_dev = NULL;
> > +
> > +	return ret;
> > +}
> >  EXPORT_SYMBOL(v4l2_async_notifier_register);
> >  
> >  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> > @@ -324,7 +356,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
> >  		if (!asd)
> >  			continue;
> >  
> > -		ret = v4l2_async_match_notify(notifier, sd, asd);
> > +		ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd,
> > +					      asd);
> >  		if (ret)
> >  			goto err_unlock;
> >  
> > -- 
> > 2.11.0
> > 
> 
> -- 
> Regards,
> Niklas Söderlund

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* [PATCH v16.1 17/32] v4l: async: Prepare for async sub-device notifiers
  2017-10-26  7:53 ` [PATCH v16 17/32] v4l: async: Prepare for async sub-device notifiers Sakari Ailus
  2017-10-26 22:10   ` Niklas Söderlund
@ 2017-10-27  8:26   ` Sakari Ailus
  2017-10-27  8:36     ` Niklas Söderlund
  2017-10-27 14:50     ` Sebastian Reichel
  1 sibling, 2 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-27  8:26 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart, pavel, sre

Refactor the V4L2 async framework a little in preparation for async
sub-device notifiers. This avoids making some structural changes in the
patch actually implementing sub-device notifiers, making that patch easier
to review.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 69 ++++++++++++++++++++++++++----------
 1 file changed, 50 insertions(+), 19 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 1b536d68cedf..6265717769d2 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
 }
 
 static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
+				   struct v4l2_device *v4l2_dev,
 				   struct v4l2_subdev *sd,
 				   struct v4l2_async_subdev *asd)
 {
 	int ret;
 
-	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
+	ret = v4l2_device_register_subdev(v4l2_dev, sd);
 	if (ret < 0)
 		return ret;
 
@@ -151,6 +152,29 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 	return 0;
 }
 
+/* Test all async sub-devices in a notifier for a match. */
+static int v4l2_async_notifier_try_all_subdevs(
+	struct v4l2_async_notifier *notifier)
+{
+	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
+	struct v4l2_subdev *sd, *tmp;
+
+	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
+		struct v4l2_async_subdev *asd;
+		int ret;
+
+		asd = v4l2_async_find_match(notifier, sd);
+		if (!asd)
+			continue;
+
+		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
+		if (ret < 0)
+			return ret;
+	}
+
+	return 0;
+}
+
 static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 {
 	v4l2_device_unregister_subdev(sd);
@@ -172,18 +196,15 @@ static void v4l2_async_notifier_unbind_all_subdevs(
 	}
 }
 
-int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
-				 struct v4l2_async_notifier *notifier)
+static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 {
-	struct v4l2_subdev *sd, *tmp;
 	struct v4l2_async_subdev *asd;
 	int ret;
 	int i;
 
-	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
+	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
 		return -EINVAL;
 
-	notifier->v4l2_dev = v4l2_dev;
 	INIT_LIST_HEAD(&notifier->waiting);
 	INIT_LIST_HEAD(&notifier->done);
 
@@ -216,18 +237,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 
 	mutex_lock(&list_lock);
 
-	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
-		int ret;
-
-		asd = v4l2_async_find_match(notifier, sd);
-		if (!asd)
-			continue;
-
-		ret = v4l2_async_match_notify(notifier, sd, asd);
-		if (ret < 0) {
-			mutex_unlock(&list_lock);
-			return ret;
-		}
+	ret = v4l2_async_notifier_try_all_subdevs(notifier);
+	if (ret) {
+		mutex_unlock(&list_lock);
+		return ret;
 	}
 
 	if (list_empty(&notifier->waiting)) {
@@ -250,6 +263,23 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 
 	return ret;
 }
+
+int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
+				 struct v4l2_async_notifier *notifier)
+{
+	int ret;
+
+	if (WARN_ON(!v4l2_dev))
+		return -EINVAL;
+
+	notifier->v4l2_dev = v4l2_dev;
+
+	ret = __v4l2_async_notifier_register(notifier);
+	if (ret)
+		notifier->v4l2_dev = NULL;
+
+	return ret;
+}
 EXPORT_SYMBOL(v4l2_async_notifier_register);
 
 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
@@ -324,7 +354,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 		if (!asd)
 			continue;
 
-		ret = v4l2_async_match_notify(notifier, sd, asd);
+		ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd,
+					      asd);
 		if (ret)
 			goto err_unlock;
 
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* [PATCH v16.1 18/32] v4l: async: Allow binding notifiers to sub-devices
  2017-10-26  7:53 ` [PATCH v16 18/32] v4l: async: Allow binding notifiers to sub-devices Sakari Ailus
@ 2017-10-27  8:27   ` Sakari Ailus
  2017-10-27  8:44     ` Niklas Söderlund
  2017-10-29 22:19     ` Sebastian Reichel
  0 siblings, 2 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-27  8:27 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart, pavel, sre

Registering a notifier has required the knowledge of struct v4l2_device
for the reason that sub-devices generally are registered to the
v4l2_device (as well as the media device, also available through
v4l2_device).

This information is not available for sub-device drivers at probe time.

What this patch does is that it allows registering notifiers without
having v4l2_device around. Instead the sub-device pointer is stored in the
notifier. Once the sub-device of the driver that registered the notifier
is registered, the notifier will gain the knowledge of the v4l2_device,
and the binding of async sub-devices from the sub-device driver's notifier
may proceed.

The complete callback of the root notifier will be called only when the
v4l2_device is available and no notifier has pending sub-devices to bind.
No complete callbacks are supported for sub-device notifiers.

Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
---
 drivers/media/v4l2-core/v4l2-async.c | 212 ++++++++++++++++++++++++++++-------
 include/media/v4l2-async.h           |  19 +++-
 2 files changed, 189 insertions(+), 42 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index 6265717769d2..ed539c4fd5dc 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -124,11 +124,87 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
 	return NULL;
 }
 
+/* Find the sub-device notifier registered by a sub-device driver. */
+static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier(
+	struct v4l2_subdev *sd)
+{
+	struct v4l2_async_notifier *n;
+
+	list_for_each_entry(n, &notifier_list, list)
+		if (n->sd == sd)
+			return n;
+
+	return NULL;
+}
+
+/* Get v4l2_device related to the notifier if one can be found. */
+static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev(
+	struct v4l2_async_notifier *notifier)
+{
+	while (notifier->parent)
+		notifier = notifier->parent;
+
+	return notifier->v4l2_dev;
+}
+
+/*
+ * Return true if all child sub-device notifiers are complete, false otherwise.
+ */
+static bool v4l2_async_notifier_can_complete(
+	struct v4l2_async_notifier *notifier)
+{
+	struct v4l2_subdev *sd;
+
+	if (!list_empty(&notifier->waiting))
+		return false;
+
+	list_for_each_entry(sd, &notifier->done, async_list) {
+		struct v4l2_async_notifier *subdev_notifier =
+			v4l2_async_find_subdev_notifier(sd);
+
+		if (subdev_notifier &&
+		    !v4l2_async_notifier_can_complete(subdev_notifier))
+			return false;
+	}
+
+	return true;
+}
+
+/*
+ * Complete the master notifier if possible. This is done when all async
+ * sub-devices have been bound; v4l2_device is also available then.
+ */
+static int v4l2_async_notifier_try_complete(
+	struct v4l2_async_notifier *notifier)
+{
+	/* Quick check whether there are still more sub-devices here. */
+	if (!list_empty(&notifier->waiting))
+		return 0;
+
+	/* Check the entire notifier tree; find the root notifier first. */
+	while (notifier->parent)
+		notifier = notifier->parent;
+
+	/* This is root if it has v4l2_dev. */
+	if (!notifier->v4l2_dev)
+		return 0;
+
+	/* Is everything ready? */
+	if (!v4l2_async_notifier_can_complete(notifier))
+		return 0;
+
+	return v4l2_async_notifier_call_complete(notifier);
+}
+
+static int v4l2_async_notifier_try_all_subdevs(
+	struct v4l2_async_notifier *notifier);
+
 static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 				   struct v4l2_device *v4l2_dev,
 				   struct v4l2_subdev *sd,
 				   struct v4l2_async_subdev *asd)
 {
+	struct v4l2_async_notifier *subdev_notifier;
 	int ret;
 
 	ret = v4l2_device_register_subdev(v4l2_dev, sd);
@@ -149,17 +225,36 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
 	/* Move from the global subdevice list to notifier's done */
 	list_move(&sd->async_list, &notifier->done);
 
-	return 0;
+	/*
+	 * See if the sub-device has a notifier. If not, return here.
+	 */
+	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
+	if (!subdev_notifier || subdev_notifier->parent)
+		return 0;
+
+	/*
+	 * Proceed with checking for the sub-device notifier's async
+	 * sub-devices, and return the result. The error will be handled by the
+	 * caller.
+	 */
+	subdev_notifier->parent = notifier;
+
+	return v4l2_async_notifier_try_all_subdevs(subdev_notifier);
 }
 
 /* Test all async sub-devices in a notifier for a match. */
 static int v4l2_async_notifier_try_all_subdevs(
 	struct v4l2_async_notifier *notifier)
 {
-	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
-	struct v4l2_subdev *sd, *tmp;
+	struct v4l2_device *v4l2_dev =
+		v4l2_async_notifier_find_v4l2_dev(notifier);
+	struct v4l2_subdev *sd;
+
+	if (!v4l2_dev)
+		return 0;
 
-	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
+again:
+	list_for_each_entry(sd, &subdev_list, async_list) {
 		struct v4l2_async_subdev *asd;
 		int ret;
 
@@ -170,6 +265,14 @@ static int v4l2_async_notifier_try_all_subdevs(
 		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
 		if (ret < 0)
 			return ret;
+
+		/*
+		 * v4l2_async_match_notify() may lead to registering a
+		 * new notifier and thus changing the async subdevs
+		 * list. In order to proceed safely from here, restart
+		 * parsing the list from the beginning.
+		 */
+		goto again;
 	}
 
 	return 0;
@@ -183,17 +286,26 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
 	sd->asd = NULL;
 }
 
+/* Unbind all sub-devices in the notifier tree. */
 static void v4l2_async_notifier_unbind_all_subdevs(
 	struct v4l2_async_notifier *notifier)
 {
 	struct v4l2_subdev *sd, *tmp;
 
 	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
+		struct v4l2_async_notifier *subdev_notifier =
+			v4l2_async_find_subdev_notifier(sd);
+
+		if (subdev_notifier)
+			v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
+
 		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
 		v4l2_async_cleanup(sd);
 
 		list_move(&sd->async_list, &subdev_list);
 	}
+
+	notifier->parent = NULL;
 }
 
 static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
@@ -208,15 +320,6 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	INIT_LIST_HEAD(&notifier->waiting);
 	INIT_LIST_HEAD(&notifier->done);
 
-	if (!notifier->num_subdevs) {
-		int ret;
-
-		ret = v4l2_async_notifier_call_complete(notifier);
-		notifier->v4l2_dev = NULL;
-
-		return ret;
-	}
-
 	for (i = 0; i < notifier->num_subdevs; i++) {
 		asd = notifier->subdevs[i];
 
@@ -238,16 +341,12 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	mutex_lock(&list_lock);
 
 	ret = v4l2_async_notifier_try_all_subdevs(notifier);
-	if (ret) {
-		mutex_unlock(&list_lock);
-		return ret;
-	}
+	if (ret)
+		goto err_unbind;
 
-	if (list_empty(&notifier->waiting)) {
-		ret = v4l2_async_notifier_call_complete(notifier);
-		if (ret)
-			goto err_complete;
-	}
+	ret = v4l2_async_notifier_try_complete(notifier);
+	if (ret)
+		goto err_unbind;
 
 	/* Keep also completed notifiers on the list */
 	list_add(&notifier->list, &notifier_list);
@@ -256,7 +355,10 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 
 	return 0;
 
-err_complete:
+err_unbind:
+	/*
+	 * On failure, unbind all sub-devices registered through this notifier.
+	 */
 	v4l2_async_notifier_unbind_all_subdevs(notifier);
 
 	mutex_unlock(&list_lock);
@@ -269,7 +371,7 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 {
 	int ret;
 
-	if (WARN_ON(!v4l2_dev))
+	if (WARN_ON(!v4l2_dev || notifier->sd))
 		return -EINVAL;
 
 	notifier->v4l2_dev = v4l2_dev;
@@ -282,20 +384,39 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 }
 EXPORT_SYMBOL(v4l2_async_notifier_register);
 
+int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
+					struct v4l2_async_notifier *notifier)
+{
+	int ret;
+
+	if (WARN_ON(!sd || notifier->v4l2_dev))
+		return -EINVAL;
+
+	notifier->sd = sd;
+
+	ret = __v4l2_async_notifier_register(notifier);
+	if (ret)
+		notifier->sd = NULL;
+
+	return ret;
+}
+EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
+
 void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
 {
-	if (!notifier->v4l2_dev)
+	if (!notifier->v4l2_dev && !notifier->sd)
 		return;
 
 	mutex_lock(&list_lock);
 
-	list_del(&notifier->list);
-
 	v4l2_async_notifier_unbind_all_subdevs(notifier);
 
-	mutex_unlock(&list_lock);
-
+	notifier->sd = NULL;
 	notifier->v4l2_dev = NULL;
+
+	list_del(&notifier->list);
+
+	mutex_unlock(&list_lock);
 }
 EXPORT_SYMBOL(v4l2_async_notifier_unregister);
 
@@ -331,6 +452,7 @@ EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
 
 int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 {
+	struct v4l2_async_notifier *subdev_notifier;
 	struct v4l2_async_notifier *notifier;
 	int ret;
 
@@ -347,24 +469,26 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 	INIT_LIST_HEAD(&sd->async_list);
 
 	list_for_each_entry(notifier, &notifier_list, list) {
-		struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
-								      sd);
+		struct v4l2_device *v4l2_dev =
+			v4l2_async_notifier_find_v4l2_dev(notifier);
+		struct v4l2_async_subdev *asd;
 		int ret;
 
+		if (!v4l2_dev)
+			continue;
+
+		asd = v4l2_async_find_match(notifier, sd);
 		if (!asd)
 			continue;
 
 		ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd,
 					      asd);
 		if (ret)
-			goto err_unlock;
-
-		if (!list_empty(&notifier->waiting))
-			goto out_unlock;
+			goto err_unbind;
 
-		ret = v4l2_async_notifier_call_complete(notifier);
+		ret = v4l2_async_notifier_try_complete(notifier);
 		if (ret)
-			goto err_cleanup;
+			goto err_unbind;
 
 		goto out_unlock;
 	}
@@ -377,11 +501,19 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
 
 	return 0;
 
-err_cleanup:
-	v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
+err_unbind:
+	/*
+	 * Complete failed. Unbind the sub-devices bound through registering
+	 * this async sub-device.
+	 */
+	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
+	if (subdev_notifier)
+		v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
+
+	if (sd->asd)
+		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
 	v4l2_async_cleanup(sd);
 
-err_unlock:
 	mutex_unlock(&list_lock);
 
 	return ret;
diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
index 68606afb5ef9..17c4ac7c73e8 100644
--- a/include/media/v4l2-async.h
+++ b/include/media/v4l2-async.h
@@ -82,7 +82,8 @@ struct v4l2_async_subdev {
 /**
  * struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations
  * @bound:	a subdevice driver has successfully probed one of the subdevices
- * @complete:	all subdevices have been probed successfully
+ * @complete:	All subdevices have been probed successfully. The complete
+ *		callback is only executed for the root notifier.
  * @unbind:	a subdevice is leaving
  */
 struct v4l2_async_notifier_operations {
@@ -102,7 +103,9 @@ struct v4l2_async_notifier_operations {
  * @num_subdevs: number of subdevices used in the subdevs array
  * @max_subdevs: number of subdevices allocated in the subdevs array
  * @subdevs:	array of pointers to subdevice descriptors
- * @v4l2_dev:	pointer to struct v4l2_device
+ * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
+ * @sd:		sub-device that registered the notifier, NULL otherwise
+ * @parent:	parent notifier
  * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
  * @done:	list of struct v4l2_subdev, already probed
  * @list:	member in a global list of notifiers
@@ -113,6 +116,8 @@ struct v4l2_async_notifier {
 	unsigned int max_subdevs;
 	struct v4l2_async_subdev **subdevs;
 	struct v4l2_device *v4l2_dev;
+	struct v4l2_subdev *sd;
+	struct v4l2_async_notifier *parent;
 	struct list_head waiting;
 	struct list_head done;
 	struct list_head list;
@@ -128,6 +133,16 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
 				 struct v4l2_async_notifier *notifier);
 
 /**
+ * v4l2_async_subdev_notifier_register - registers a subdevice asynchronous
+ *					 notifier for a sub-device
+ *
+ * @sd: pointer to &struct v4l2_subdev
+ * @notifier: pointer to &struct v4l2_async_notifier
+ */
+int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
+					struct v4l2_async_notifier *notifier);
+
+/**
  * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier
  *
  * @notifier: pointer to &struct v4l2_async_notifier
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 17/32] v4l: async: Prepare for async sub-device notifiers
  2017-10-27  8:10     ` Niklas Söderlund
@ 2017-10-27  8:30       ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-27  8:30 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, linux-media, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, sre, linux-acpi, devicetree

On Fri, Oct 27, 2017 at 10:10:02AM +0200, Niklas Söderlund wrote:
> > > @@ -151,6 +152,31 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> > >  	return 0;
> > >  }
> > >  
> > > +/* Test all async sub-devices in a notifier for a match. */
> > > +static int v4l2_async_notifier_try_all_subdevs(
> > > +	struct v4l2_async_notifier *notifier)
> > > +{
> > > +	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
> > > +	struct v4l2_subdev *sd, *tmp;
> > > +
> > > +	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> > > +		struct v4l2_async_subdev *asd;
> > > +		int ret;
> > > +
> > > +		asd = v4l2_async_find_match(notifier, sd);
> > > +		if (!asd)
> > > +			continue;
> > > +
> > > +		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
> > > +		if (ret < 0) {
> > > +			mutex_unlock(&list_lock);
> 
> The mutex should not be unlocked here, as the caller will also unlock it 
> if ret is none zero. You fix this in 18/32 so the end result is OK but I 
> think its better to fix this in this patch.

Good catch. I've sent v16.1 of these and forgot the change log. There are
no other changes than fixing this, i.e. the end result is the same.

-- 
Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16.1 17/32] v4l: async: Prepare for async sub-device notifiers
  2017-10-27  8:26   ` [PATCH v16.1 " Sakari Ailus
@ 2017-10-27  8:36     ` Niklas Söderlund
  2017-10-27 14:50     ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-27  8:36 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel, sre

Hi Sakari,

Thanks for your patch.

On 2017-10-27 11:26:29 +0300, Sakari Ailus wrote:
> Refactor the V4L2 async framework a little in preparation for async
> sub-device notifiers. This avoids making some structural changes in the
> patch actually implementing sub-device notifiers, making that patch easier
> to review.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 69 ++++++++++++++++++++++++++----------
>  1 file changed, 50 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 1b536d68cedf..6265717769d2 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
>  }
>  
>  static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> +				   struct v4l2_device *v4l2_dev,
>  				   struct v4l2_subdev *sd,
>  				   struct v4l2_async_subdev *asd)
>  {
>  	int ret;
>  
> -	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> +	ret = v4l2_device_register_subdev(v4l2_dev, sd);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -151,6 +152,29 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  	return 0;
>  }
>  
> +/* Test all async sub-devices in a notifier for a match. */
> +static int v4l2_async_notifier_try_all_subdevs(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
> +	struct v4l2_subdev *sd, *tmp;
> +
> +	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> +		struct v4l2_async_subdev *asd;
> +		int ret;
> +
> +		asd = v4l2_async_find_match(notifier, sd);
> +		if (!asd)
> +			continue;
> +
> +		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  {
>  	v4l2_device_unregister_subdev(sd);
> @@ -172,18 +196,15 @@ static void v4l2_async_notifier_unbind_all_subdevs(
>  	}
>  }
>  
> -int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> -				 struct v4l2_async_notifier *notifier)
> +static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  {
> -	struct v4l2_subdev *sd, *tmp;
>  	struct v4l2_async_subdev *asd;
>  	int ret;
>  	int i;
>  
> -	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
> +	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
>  		return -EINVAL;
>  
> -	notifier->v4l2_dev = v4l2_dev;
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> @@ -216,18 +237,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  
>  	mutex_lock(&list_lock);
>  
> -	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> -		int ret;
> -
> -		asd = v4l2_async_find_match(notifier, sd);
> -		if (!asd)
> -			continue;
> -
> -		ret = v4l2_async_match_notify(notifier, sd, asd);
> -		if (ret < 0) {
> -			mutex_unlock(&list_lock);
> -			return ret;
> -		}
> +	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> +	if (ret) {
> +		mutex_unlock(&list_lock);
> +		return ret;
>  	}
>  
>  	if (list_empty(&notifier->waiting)) {
> @@ -250,6 +263,23 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  
>  	return ret;
>  }
> +
> +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> +				 struct v4l2_async_notifier *notifier)
> +{
> +	int ret;
> +
> +	if (WARN_ON(!v4l2_dev))
> +		return -EINVAL;
> +
> +	notifier->v4l2_dev = v4l2_dev;
> +
> +	ret = __v4l2_async_notifier_register(notifier);
> +	if (ret)
> +		notifier->v4l2_dev = NULL;
> +
> +	return ret;
> +}
>  EXPORT_SYMBOL(v4l2_async_notifier_register);
>  
>  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> @@ -324,7 +354,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  		if (!asd)
>  			continue;
>  
> -		ret = v4l2_async_match_notify(notifier, sd, asd);
> +		ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd,
> +					      asd);
>  		if (ret)
>  			goto err_unlock;
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16.1 18/32] v4l: async: Allow binding notifiers to sub-devices
  2017-10-27  8:27   ` [PATCH v16.1 " Sakari Ailus
@ 2017-10-27  8:44     ` Niklas Söderlund
  2017-10-29 22:19     ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-27  8:44 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel, sre

On 2017-10-27 11:27:09 +0300, Sakari Ailus wrote:
> Registering a notifier has required the knowledge of struct v4l2_device
> for the reason that sub-devices generally are registered to the
> v4l2_device (as well as the media device, also available through
> v4l2_device).
> 
> This information is not available for sub-device drivers at probe time.
> 
> What this patch does is that it allows registering notifiers without
> having v4l2_device around. Instead the sub-device pointer is stored in the
> notifier. Once the sub-device of the driver that registered the notifier
> is registered, the notifier will gain the knowledge of the v4l2_device,
> and the binding of async sub-devices from the sub-device driver's notifier
> may proceed.
> 
> The complete callback of the root notifier will be called only when the
> v4l2_device is available and no notifier has pending sub-devices to bind.
> No complete callbacks are supported for sub-device notifiers.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c | 212 ++++++++++++++++++++++++++++-------
>  include/media/v4l2-async.h           |  19 +++-
>  2 files changed, 189 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 6265717769d2..ed539c4fd5dc 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -124,11 +124,87 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
>  	return NULL;
>  }
>  
> +/* Find the sub-device notifier registered by a sub-device driver. */
> +static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier(
> +	struct v4l2_subdev *sd)
> +{
> +	struct v4l2_async_notifier *n;
> +
> +	list_for_each_entry(n, &notifier_list, list)
> +		if (n->sd == sd)
> +			return n;
> +
> +	return NULL;
> +}
> +
> +/* Get v4l2_device related to the notifier if one can be found. */
> +static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	while (notifier->parent)
> +		notifier = notifier->parent;
> +
> +	return notifier->v4l2_dev;
> +}
> +
> +/*
> + * Return true if all child sub-device notifiers are complete, false otherwise.
> + */
> +static bool v4l2_async_notifier_can_complete(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_subdev *sd;
> +
> +	if (!list_empty(&notifier->waiting))
> +		return false;
> +
> +	list_for_each_entry(sd, &notifier->done, async_list) {
> +		struct v4l2_async_notifier *subdev_notifier =
> +			v4l2_async_find_subdev_notifier(sd);
> +
> +		if (subdev_notifier &&
> +		    !v4l2_async_notifier_can_complete(subdev_notifier))
> +			return false;
> +	}
> +
> +	return true;
> +}
> +
> +/*
> + * Complete the master notifier if possible. This is done when all async
> + * sub-devices have been bound; v4l2_device is also available then.
> + */
> +static int v4l2_async_notifier_try_complete(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	/* Quick check whether there are still more sub-devices here. */
> +	if (!list_empty(&notifier->waiting))
> +		return 0;
> +
> +	/* Check the entire notifier tree; find the root notifier first. */
> +	while (notifier->parent)
> +		notifier = notifier->parent;
> +
> +	/* This is root if it has v4l2_dev. */
> +	if (!notifier->v4l2_dev)
> +		return 0;
> +
> +	/* Is everything ready? */
> +	if (!v4l2_async_notifier_can_complete(notifier))
> +		return 0;
> +
> +	return v4l2_async_notifier_call_complete(notifier);
> +}
> +
> +static int v4l2_async_notifier_try_all_subdevs(
> +	struct v4l2_async_notifier *notifier);
> +
>  static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  				   struct v4l2_device *v4l2_dev,
>  				   struct v4l2_subdev *sd,
>  				   struct v4l2_async_subdev *asd)
>  {
> +	struct v4l2_async_notifier *subdev_notifier;
>  	int ret;
>  
>  	ret = v4l2_device_register_subdev(v4l2_dev, sd);
> @@ -149,17 +225,36 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  	/* Move from the global subdevice list to notifier's done */
>  	list_move(&sd->async_list, &notifier->done);
>  
> -	return 0;
> +	/*
> +	 * See if the sub-device has a notifier. If not, return here.
> +	 */
> +	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
> +	if (!subdev_notifier || subdev_notifier->parent)
> +		return 0;
> +
> +	/*
> +	 * Proceed with checking for the sub-device notifier's async
> +	 * sub-devices, and return the result. The error will be handled by the
> +	 * caller.
> +	 */
> +	subdev_notifier->parent = notifier;
> +
> +	return v4l2_async_notifier_try_all_subdevs(subdev_notifier);
>  }
>  
>  /* Test all async sub-devices in a notifier for a match. */
>  static int v4l2_async_notifier_try_all_subdevs(
>  	struct v4l2_async_notifier *notifier)
>  {
> -	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
> -	struct v4l2_subdev *sd, *tmp;
> +	struct v4l2_device *v4l2_dev =
> +		v4l2_async_notifier_find_v4l2_dev(notifier);
> +	struct v4l2_subdev *sd;
> +
> +	if (!v4l2_dev)
> +		return 0;
>  
> -	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> +again:
> +	list_for_each_entry(sd, &subdev_list, async_list) {
>  		struct v4l2_async_subdev *asd;
>  		int ret;
>  
> @@ -170,6 +265,14 @@ static int v4l2_async_notifier_try_all_subdevs(
>  		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
>  		if (ret < 0)
>  			return ret;
> +
> +		/*
> +		 * v4l2_async_match_notify() may lead to registering a
> +		 * new notifier and thus changing the async subdevs
> +		 * list. In order to proceed safely from here, restart
> +		 * parsing the list from the beginning.
> +		 */
> +		goto again;
>  	}
>  
>  	return 0;
> @@ -183,17 +286,26 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  	sd->asd = NULL;
>  }
>  
> +/* Unbind all sub-devices in the notifier tree. */
>  static void v4l2_async_notifier_unbind_all_subdevs(
>  	struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_subdev *sd, *tmp;
>  
>  	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> +		struct v4l2_async_notifier *subdev_notifier =
> +			v4l2_async_find_subdev_notifier(sd);
> +
> +		if (subdev_notifier)
> +			v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
> +
>  		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>  		v4l2_async_cleanup(sd);
>  
>  		list_move(&sd->async_list, &subdev_list);
>  	}
> +
> +	notifier->parent = NULL;
>  }
>  
>  static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> @@ -208,15 +320,6 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> -	if (!notifier->num_subdevs) {
> -		int ret;
> -
> -		ret = v4l2_async_notifier_call_complete(notifier);
> -		notifier->v4l2_dev = NULL;
> -
> -		return ret;
> -	}
> -
>  	for (i = 0; i < notifier->num_subdevs; i++) {
>  		asd = notifier->subdevs[i];
>  
> @@ -238,16 +341,12 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  	mutex_lock(&list_lock);
>  
>  	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> -	if (ret) {
> -		mutex_unlock(&list_lock);
> -		return ret;
> -	}
> +	if (ret)
> +		goto err_unbind;
>  
> -	if (list_empty(&notifier->waiting)) {
> -		ret = v4l2_async_notifier_call_complete(notifier);
> -		if (ret)
> -			goto err_complete;
> -	}
> +	ret = v4l2_async_notifier_try_complete(notifier);
> +	if (ret)
> +		goto err_unbind;
>  
>  	/* Keep also completed notifiers on the list */
>  	list_add(&notifier->list, &notifier_list);
> @@ -256,7 +355,10 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  
>  	return 0;
>  
> -err_complete:
> +err_unbind:
> +	/*
> +	 * On failure, unbind all sub-devices registered through this notifier.
> +	 */
>  	v4l2_async_notifier_unbind_all_subdevs(notifier);
>  
>  	mutex_unlock(&list_lock);
> @@ -269,7 +371,7 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  {
>  	int ret;
>  
> -	if (WARN_ON(!v4l2_dev))
> +	if (WARN_ON(!v4l2_dev || notifier->sd))
>  		return -EINVAL;
>  
>  	notifier->v4l2_dev = v4l2_dev;
> @@ -282,20 +384,39 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  }
>  EXPORT_SYMBOL(v4l2_async_notifier_register);
>  
> +int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
> +					struct v4l2_async_notifier *notifier)
> +{
> +	int ret;
> +
> +	if (WARN_ON(!sd || notifier->v4l2_dev))
> +		return -EINVAL;
> +
> +	notifier->sd = sd;
> +
> +	ret = __v4l2_async_notifier_register(notifier);
> +	if (ret)
> +		notifier->sd = NULL;
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
> +
>  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
>  {
> -	if (!notifier->v4l2_dev)
> +	if (!notifier->v4l2_dev && !notifier->sd)
>  		return;
>  
>  	mutex_lock(&list_lock);
>  
> -	list_del(&notifier->list);
> -
>  	v4l2_async_notifier_unbind_all_subdevs(notifier);
>  
> -	mutex_unlock(&list_lock);
> -
> +	notifier->sd = NULL;
>  	notifier->v4l2_dev = NULL;
> +
> +	list_del(&notifier->list);
> +
> +	mutex_unlock(&list_lock);
>  }
>  EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>  
> @@ -331,6 +452,7 @@ EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
>  
>  int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  {
> +	struct v4l2_async_notifier *subdev_notifier;
>  	struct v4l2_async_notifier *notifier;
>  	int ret;
>  
> @@ -347,24 +469,26 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	INIT_LIST_HEAD(&sd->async_list);
>  
>  	list_for_each_entry(notifier, &notifier_list, list) {
> -		struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
> -								      sd);
> +		struct v4l2_device *v4l2_dev =
> +			v4l2_async_notifier_find_v4l2_dev(notifier);
> +		struct v4l2_async_subdev *asd;
>  		int ret;
>  
> +		if (!v4l2_dev)
> +			continue;
> +
> +		asd = v4l2_async_find_match(notifier, sd);
>  		if (!asd)
>  			continue;
>  
>  		ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd,
>  					      asd);
>  		if (ret)
> -			goto err_unlock;
> -
> -		if (!list_empty(&notifier->waiting))
> -			goto out_unlock;
> +			goto err_unbind;
>  
> -		ret = v4l2_async_notifier_call_complete(notifier);
> +		ret = v4l2_async_notifier_try_complete(notifier);
>  		if (ret)
> -			goto err_cleanup;
> +			goto err_unbind;
>  
>  		goto out_unlock;
>  	}
> @@ -377,11 +501,19 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  
>  	return 0;
>  
> -err_cleanup:
> -	v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
> +err_unbind:
> +	/*
> +	 * Complete failed. Unbind the sub-devices bound through registering
> +	 * this async sub-device.
> +	 */
> +	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
> +	if (subdev_notifier)
> +		v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
> +
> +	if (sd->asd)
> +		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>  	v4l2_async_cleanup(sd);
>  
> -err_unlock:
>  	mutex_unlock(&list_lock);
>  
>  	return ret;
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 68606afb5ef9..17c4ac7c73e8 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -82,7 +82,8 @@ struct v4l2_async_subdev {
>  /**
>   * struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations
>   * @bound:	a subdevice driver has successfully probed one of the subdevices
> - * @complete:	all subdevices have been probed successfully
> + * @complete:	All subdevices have been probed successfully. The complete
> + *		callback is only executed for the root notifier.
>   * @unbind:	a subdevice is leaving
>   */
>  struct v4l2_async_notifier_operations {
> @@ -102,7 +103,9 @@ struct v4l2_async_notifier_operations {
>   * @num_subdevs: number of subdevices used in the subdevs array
>   * @max_subdevs: number of subdevices allocated in the subdevs array
>   * @subdevs:	array of pointers to subdevice descriptors
> - * @v4l2_dev:	pointer to struct v4l2_device
> + * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
> + * @sd:		sub-device that registered the notifier, NULL otherwise
> + * @parent:	parent notifier
>   * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
>   * @done:	list of struct v4l2_subdev, already probed
>   * @list:	member in a global list of notifiers
> @@ -113,6 +116,8 @@ struct v4l2_async_notifier {
>  	unsigned int max_subdevs;
>  	struct v4l2_async_subdev **subdevs;
>  	struct v4l2_device *v4l2_dev;
> +	struct v4l2_subdev *sd;
> +	struct v4l2_async_notifier *parent;
>  	struct list_head waiting;
>  	struct list_head done;
>  	struct list_head list;
> @@ -128,6 +133,16 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  				 struct v4l2_async_notifier *notifier);
>  
>  /**
> + * v4l2_async_subdev_notifier_register - registers a subdevice asynchronous
> + *					 notifier for a sub-device
> + *
> + * @sd: pointer to &struct v4l2_subdev
> + * @notifier: pointer to &struct v4l2_async_notifier
> + */
> +int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
> +					struct v4l2_async_notifier *notifier);
> +
> +/**
>   * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier
>   *
>   * @notifier: pointer to &struct v4l2_async_notifier
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers
  2017-10-26  7:53 ` [PATCH v16 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers Sakari Ailus
@ 2017-10-27  9:52   ` Niklas Söderlund
       [not found]     ` <20171027095227.GA8854-ofJ5d6taAgIKcZgyrm77+z0dHWC0CY5B@public.gmane.org>
  2017-10-27 10:53   ` [PATCH v16.1 " Sakari Ailus
  1 sibling, 1 reply; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-27  9:52 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

Hi Sakari,

Thanks for your patch.

On 2017-10-26 10:53:29 +0300, Sakari Ailus wrote:
> 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>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---
>  drivers/media/v4l2-core/v4l2-async.c | 82 +++++++++++++++++++++++++++++++++---
>  1 file changed, 77 insertions(+), 5 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index ed539c4fd5dc..b4e88eef195f 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -308,8 +308,71 @@ static void v4l2_async_notifier_unbind_all_subdevs(
>  	notifier->parent = NULL;
>  }
>  
> +/* See if an fwnode can be found in a notifier's lists. */
> +static bool __v4l2_async_notifier_fwnode_has_async_subdev(
> +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
> +{
> +	struct v4l2_async_subdev *asd;
> +	struct v4l2_subdev *sd;
> +
> +	list_for_each_entry(asd, &notifier->waiting, list) {
> +		if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> +			continue;
> +
> +		if (asd->match.fwnode.fwnode == fwnode)
> +			return true;
> +	}
> +
> +	list_for_each_entry(sd, &notifier->done, async_list) {
> +		if (WARN_ON(!sd->asd))
> +			continue;
> +
> +		if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> +			continue;
> +
> +		if (sd->asd->match.fwnode.fwnode == fwnode)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +/*
> + * Find out whether an async sub-device was set up for an fwnode already or
> + * whether it exists in a given notifier before @this_index.
> + */
> +static bool v4l2_async_notifier_fwnode_has_async_subdev(
> +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
> +	unsigned int this_index)
> +{
> +	unsigned int j;
> +
> +	lockdep_assert_held(&list_lock);
> +
> +	/* Check that an fwnode is not being added more than once. */
> +	for (j = 0; j < this_index; j++) {
> +		struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
> +		struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
> +
> +		if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
> +		    asd->match.fwnode.fwnode ==
> +		    other_asd->match.fwnode.fwnode)
> +			return true;
> +	}
> +
> +	/* Check than an fwnode did not exist in other notifiers. */
> +	list_for_each_entry(notifier, &notifier_list, list)
> +		if (__v4l2_async_notifier_fwnode_has_async_subdev(
> +			    notifier, fwnode))
> +			return true;
> +
> +	return false;
> +}
> +
>  static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  {
> +	struct device *dev =
> +		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
>  	struct v4l2_async_subdev *asd;
>  	int ret;
>  	int i;
> @@ -320,6 +383,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> +	mutex_lock(&list_lock);
> +
>  	for (i = 0; i < notifier->num_subdevs; i++) {
>  		asd = notifier->subdevs[i];
>  
> @@ -327,19 +392,25 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  		case V4L2_ASYNC_MATCH_CUSTOM:
>  		case V4L2_ASYNC_MATCH_DEVNAME:
>  		case V4L2_ASYNC_MATCH_I2C:
> +			break;
>  		case V4L2_ASYNC_MATCH_FWNODE:
> +			if (v4l2_async_notifier_fwnode_has_async_subdev(
> +				    notifier, asd->match.fwnode.fwnode, i)) {
> +				dev_err(dev,
> +					"fwnode has already been registered or in notifier's subdev list\n");
> +				ret = -EEXIST;
> +				goto out_unlock;

You store the error code in ret before the jump, but in the out_unlock 
path ret is not considered and 0 is always returned.

> +			}
>  			break;
>  		default:
> -			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
> -				"Invalid match type %u on %p\n",
> +			dev_err(dev, "Invalid match type %u on %p\n",
>  				asd->match_type, asd);
> -			return -EINVAL;
> +			ret = -EINVAL;
> +			goto out_unlock;

Same here.

>  		}
>  		list_add_tail(&asd->list, &notifier->waiting);
>  	}
>  
> -	mutex_lock(&list_lock);
> -
>  	ret = v4l2_async_notifier_try_all_subdevs(notifier);
>  	if (ret)
>  		goto err_unbind;
> @@ -351,6 +422,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  	/* Keep also completed notifiers on the list */
>  	list_add(&notifier->list, &notifier_list);
>  
> +out_unlock:
>  	mutex_unlock(&list_lock);
>  
>  	return 0;
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers
  2017-10-27  9:52   ` Niklas Söderlund
@ 2017-10-27 10:06         ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-27 10:06 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, linux-media-u79uwXL29TY76Z2rM5mHXA,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	sre-DgEjT+Ai2ygdnm+yROfE0A, linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

Hi Niklas,

On Fri, Oct 27, 2017 at 11:52:27AM +0200, Niklas Söderlund wrote:
> Hi Sakari,
> 
> Thanks for your patch.
> 
> On 2017-10-26 10:53:29 +0300, Sakari Ailus wrote:
> > 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-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> > Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> > ---
> >  drivers/media/v4l2-core/v4l2-async.c | 82 +++++++++++++++++++++++++++++++++---
> >  1 file changed, 77 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index ed539c4fd5dc..b4e88eef195f 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -308,8 +308,71 @@ static void v4l2_async_notifier_unbind_all_subdevs(
> >  	notifier->parent = NULL;
> >  }
> >  
> > +/* See if an fwnode can be found in a notifier's lists. */
> > +static bool __v4l2_async_notifier_fwnode_has_async_subdev(
> > +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
> > +{
> > +	struct v4l2_async_subdev *asd;
> > +	struct v4l2_subdev *sd;
> > +
> > +	list_for_each_entry(asd, &notifier->waiting, list) {
> > +		if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> > +			continue;
> > +
> > +		if (asd->match.fwnode.fwnode == fwnode)
> > +			return true;
> > +	}
> > +
> > +	list_for_each_entry(sd, &notifier->done, async_list) {
> > +		if (WARN_ON(!sd->asd))
> > +			continue;
> > +
> > +		if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> > +			continue;
> > +
> > +		if (sd->asd->match.fwnode.fwnode == fwnode)
> > +			return true;
> > +	}
> > +
> > +	return false;
> > +}
> > +
> > +/*
> > + * Find out whether an async sub-device was set up for an fwnode already or
> > + * whether it exists in a given notifier before @this_index.
> > + */
> > +static bool v4l2_async_notifier_fwnode_has_async_subdev(
> > +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
> > +	unsigned int this_index)
> > +{
> > +	unsigned int j;
> > +
> > +	lockdep_assert_held(&list_lock);
> > +
> > +	/* Check that an fwnode is not being added more than once. */
> > +	for (j = 0; j < this_index; j++) {
> > +		struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
> > +		struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
> > +
> > +		if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
> > +		    asd->match.fwnode.fwnode ==
> > +		    other_asd->match.fwnode.fwnode)
> > +			return true;
> > +	}
> > +
> > +	/* Check than an fwnode did not exist in other notifiers. */
> > +	list_for_each_entry(notifier, &notifier_list, list)
> > +		if (__v4l2_async_notifier_fwnode_has_async_subdev(
> > +			    notifier, fwnode))
> > +			return true;
> > +
> > +	return false;
> > +}
> > +
> >  static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  {
> > +	struct device *dev =
> > +		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
> >  	struct v4l2_async_subdev *asd;
> >  	int ret;
> >  	int i;
> > @@ -320,6 +383,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  	INIT_LIST_HEAD(&notifier->waiting);
> >  	INIT_LIST_HEAD(&notifier->done);
> >  
> > +	mutex_lock(&list_lock);
> > +
> >  	for (i = 0; i < notifier->num_subdevs; i++) {
> >  		asd = notifier->subdevs[i];
> >  
> > @@ -327,19 +392,25 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  		case V4L2_ASYNC_MATCH_CUSTOM:
> >  		case V4L2_ASYNC_MATCH_DEVNAME:
> >  		case V4L2_ASYNC_MATCH_I2C:
> > +			break;
> >  		case V4L2_ASYNC_MATCH_FWNODE:
> > +			if (v4l2_async_notifier_fwnode_has_async_subdev(
> > +				    notifier, asd->match.fwnode.fwnode, i)) {
> > +				dev_err(dev,
> > +					"fwnode has already been registered or in notifier's subdev list\n");
> > +				ret = -EEXIST;
> > +				goto out_unlock;
> 
> You store the error code in ret before the jump, but in the out_unlock 
> path ret is not considered and 0 is always returned.
> 
> > +			}
> >  			break;
> >  		default:
> > -			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
> > -				"Invalid match type %u on %p\n",
> > +			dev_err(dev, "Invalid match type %u on %p\n",
> >  				asd->match_type, asd);
> > -			return -EINVAL;
> > +			ret = -EINVAL;
> > +			goto out_unlock;
> 
> Same here.

Good catch! How about this change on top of the patch? It makes return
value checks a little bit safer, too.

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index b4e88eef195f..a33a68e5417b 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -412,12 +412,13 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	}
 
 	ret = v4l2_async_notifier_try_all_subdevs(notifier);
-	if (ret)
+	if (ret < 0)
 		goto err_unbind;
 
 	ret = v4l2_async_notifier_try_complete(notifier);
-	if (ret)
+	if (ret < 0)
 		goto err_unbind;
+	ret = 0;
 
 	/* Keep also completed notifiers on the list */
 	list_add(&notifier->list, &notifier_list);
@@ -425,7 +426,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 out_unlock:
 	mutex_unlock(&list_lock);
 
-	return 0;
+	return ret;
 
 err_unbind:
 	/*

> 
> >  		}
> >  		list_add_tail(&asd->list, &notifier->waiting);
> >  	}
> >  
> > -	mutex_lock(&list_lock);
> > -
> >  	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> >  	if (ret)
> >  		goto err_unbind;
> > @@ -351,6 +422,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  	/* Keep also completed notifiers on the list */
> >  	list_add(&notifier->list, &notifier_list);
> >  
> > +out_unlock:
> >  	mutex_unlock(&list_lock);
> >  
> >  	return 0;

-- 
Sakari Ailus
e-mail: sakari.ailus-X3B1VOXEql0@public.gmane.org
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers
@ 2017-10-27 10:06         ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-27 10:06 UTC (permalink / raw)
  To: Niklas Söderlund
  Cc: Sakari Ailus, linux-media, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, sre, linux-acpi, devicetree

Hi Niklas,

On Fri, Oct 27, 2017 at 11:52:27AM +0200, Niklas Söderlund wrote:
> Hi Sakari,
> 
> Thanks for your patch.
> 
> On 2017-10-26 10:53:29 +0300, Sakari Ailus wrote:
> > 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>
> > Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > ---
> >  drivers/media/v4l2-core/v4l2-async.c | 82 +++++++++++++++++++++++++++++++++---
> >  1 file changed, 77 insertions(+), 5 deletions(-)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index ed539c4fd5dc..b4e88eef195f 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -308,8 +308,71 @@ static void v4l2_async_notifier_unbind_all_subdevs(
> >  	notifier->parent = NULL;
> >  }
> >  
> > +/* See if an fwnode can be found in a notifier's lists. */
> > +static bool __v4l2_async_notifier_fwnode_has_async_subdev(
> > +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
> > +{
> > +	struct v4l2_async_subdev *asd;
> > +	struct v4l2_subdev *sd;
> > +
> > +	list_for_each_entry(asd, &notifier->waiting, list) {
> > +		if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> > +			continue;
> > +
> > +		if (asd->match.fwnode.fwnode == fwnode)
> > +			return true;
> > +	}
> > +
> > +	list_for_each_entry(sd, &notifier->done, async_list) {
> > +		if (WARN_ON(!sd->asd))
> > +			continue;
> > +
> > +		if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> > +			continue;
> > +
> > +		if (sd->asd->match.fwnode.fwnode == fwnode)
> > +			return true;
> > +	}
> > +
> > +	return false;
> > +}
> > +
> > +/*
> > + * Find out whether an async sub-device was set up for an fwnode already or
> > + * whether it exists in a given notifier before @this_index.
> > + */
> > +static bool v4l2_async_notifier_fwnode_has_async_subdev(
> > +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
> > +	unsigned int this_index)
> > +{
> > +	unsigned int j;
> > +
> > +	lockdep_assert_held(&list_lock);
> > +
> > +	/* Check that an fwnode is not being added more than once. */
> > +	for (j = 0; j < this_index; j++) {
> > +		struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
> > +		struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
> > +
> > +		if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
> > +		    asd->match.fwnode.fwnode ==
> > +		    other_asd->match.fwnode.fwnode)
> > +			return true;
> > +	}
> > +
> > +	/* Check than an fwnode did not exist in other notifiers. */
> > +	list_for_each_entry(notifier, &notifier_list, list)
> > +		if (__v4l2_async_notifier_fwnode_has_async_subdev(
> > +			    notifier, fwnode))
> > +			return true;
> > +
> > +	return false;
> > +}
> > +
> >  static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  {
> > +	struct device *dev =
> > +		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
> >  	struct v4l2_async_subdev *asd;
> >  	int ret;
> >  	int i;
> > @@ -320,6 +383,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  	INIT_LIST_HEAD(&notifier->waiting);
> >  	INIT_LIST_HEAD(&notifier->done);
> >  
> > +	mutex_lock(&list_lock);
> > +
> >  	for (i = 0; i < notifier->num_subdevs; i++) {
> >  		asd = notifier->subdevs[i];
> >  
> > @@ -327,19 +392,25 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  		case V4L2_ASYNC_MATCH_CUSTOM:
> >  		case V4L2_ASYNC_MATCH_DEVNAME:
> >  		case V4L2_ASYNC_MATCH_I2C:
> > +			break;
> >  		case V4L2_ASYNC_MATCH_FWNODE:
> > +			if (v4l2_async_notifier_fwnode_has_async_subdev(
> > +				    notifier, asd->match.fwnode.fwnode, i)) {
> > +				dev_err(dev,
> > +					"fwnode has already been registered or in notifier's subdev list\n");
> > +				ret = -EEXIST;
> > +				goto out_unlock;
> 
> You store the error code in ret before the jump, but in the out_unlock 
> path ret is not considered and 0 is always returned.
> 
> > +			}
> >  			break;
> >  		default:
> > -			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
> > -				"Invalid match type %u on %p\n",
> > +			dev_err(dev, "Invalid match type %u on %p\n",
> >  				asd->match_type, asd);
> > -			return -EINVAL;
> > +			ret = -EINVAL;
> > +			goto out_unlock;
> 
> Same here.

Good catch! How about this change on top of the patch? It makes return
value checks a little bit safer, too.

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index b4e88eef195f..a33a68e5417b 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -412,12 +412,13 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	}
 
 	ret = v4l2_async_notifier_try_all_subdevs(notifier);
-	if (ret)
+	if (ret < 0)
 		goto err_unbind;
 
 	ret = v4l2_async_notifier_try_complete(notifier);
-	if (ret)
+	if (ret < 0)
 		goto err_unbind;
+	ret = 0;
 
 	/* Keep also completed notifiers on the list */
 	list_add(&notifier->list, &notifier_list);
@@ -425,7 +426,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 out_unlock:
 	mutex_unlock(&list_lock);
 
-	return 0;
+	return ret;
 
 err_unbind:
 	/*

> 
> >  		}
> >  		list_add_tail(&asd->list, &notifier->waiting);
> >  	}
> >  
> > -	mutex_lock(&list_lock);
> > -
> >  	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> >  	if (ret)
> >  		goto err_unbind;
> > @@ -351,6 +422,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  	/* Keep also completed notifiers on the list */
> >  	list_add(&notifier->list, &notifier_list);
> >  
> > +out_unlock:
> >  	mutex_unlock(&list_lock);
> >  
> >  	return 0;

-- 
Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers
  2017-10-27 10:06         ` Sakari Ailus
  (?)
@ 2017-10-27 10:26         ` Niklas Söderlund
  -1 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-27 10:26 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: Sakari Ailus, linux-media, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, sre, linux-acpi, devicetree

Hi Sakari,

On 2017-10-27 13:06:09 +0300, Sakari Ailus wrote:
> Hi Niklas,
> 
> On Fri, Oct 27, 2017 at 11:52:27AM +0200, Niklas Söderlund wrote:
> > Hi Sakari,
> > 
> > Thanks for your patch.
> > 
> > On 2017-10-26 10:53:29 +0300, Sakari Ailus wrote:
> > > 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>
> > > Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > > ---
> > >  drivers/media/v4l2-core/v4l2-async.c | 82 +++++++++++++++++++++++++++++++++---
> > >  1 file changed, 77 insertions(+), 5 deletions(-)
> > > 
> > > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > > index ed539c4fd5dc..b4e88eef195f 100644
> > > --- a/drivers/media/v4l2-core/v4l2-async.c
> > > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > > @@ -308,8 +308,71 @@ static void v4l2_async_notifier_unbind_all_subdevs(
> > >  	notifier->parent = NULL;
> > >  }
> > >  
> > > +/* See if an fwnode can be found in a notifier's lists. */
> > > +static bool __v4l2_async_notifier_fwnode_has_async_subdev(
> > > +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
> > > +{
> > > +	struct v4l2_async_subdev *asd;
> > > +	struct v4l2_subdev *sd;
> > > +
> > > +	list_for_each_entry(asd, &notifier->waiting, list) {
> > > +		if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> > > +			continue;
> > > +
> > > +		if (asd->match.fwnode.fwnode == fwnode)
> > > +			return true;
> > > +	}
> > > +
> > > +	list_for_each_entry(sd, &notifier->done, async_list) {
> > > +		if (WARN_ON(!sd->asd))
> > > +			continue;
> > > +
> > > +		if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> > > +			continue;
> > > +
> > > +		if (sd->asd->match.fwnode.fwnode == fwnode)
> > > +			return true;
> > > +	}
> > > +
> > > +	return false;
> > > +}
> > > +
> > > +/*
> > > + * Find out whether an async sub-device was set up for an fwnode already or
> > > + * whether it exists in a given notifier before @this_index.
> > > + */
> > > +static bool v4l2_async_notifier_fwnode_has_async_subdev(
> > > +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
> > > +	unsigned int this_index)
> > > +{
> > > +	unsigned int j;
> > > +
> > > +	lockdep_assert_held(&list_lock);
> > > +
> > > +	/* Check that an fwnode is not being added more than once. */
> > > +	for (j = 0; j < this_index; j++) {
> > > +		struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
> > > +		struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
> > > +
> > > +		if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
> > > +		    asd->match.fwnode.fwnode ==
> > > +		    other_asd->match.fwnode.fwnode)
> > > +			return true;
> > > +	}
> > > +
> > > +	/* Check than an fwnode did not exist in other notifiers. */
> > > +	list_for_each_entry(notifier, &notifier_list, list)
> > > +		if (__v4l2_async_notifier_fwnode_has_async_subdev(
> > > +			    notifier, fwnode))
> > > +			return true;
> > > +
> > > +	return false;
> > > +}
> > > +
> > >  static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> > >  {
> > > +	struct device *dev =
> > > +		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
> > >  	struct v4l2_async_subdev *asd;
> > >  	int ret;
> > >  	int i;
> > > @@ -320,6 +383,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> > >  	INIT_LIST_HEAD(&notifier->waiting);
> > >  	INIT_LIST_HEAD(&notifier->done);
> > >  
> > > +	mutex_lock(&list_lock);
> > > +
> > >  	for (i = 0; i < notifier->num_subdevs; i++) {
> > >  		asd = notifier->subdevs[i];
> > >  
> > > @@ -327,19 +392,25 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> > >  		case V4L2_ASYNC_MATCH_CUSTOM:
> > >  		case V4L2_ASYNC_MATCH_DEVNAME:
> > >  		case V4L2_ASYNC_MATCH_I2C:
> > > +			break;
> > >  		case V4L2_ASYNC_MATCH_FWNODE:
> > > +			if (v4l2_async_notifier_fwnode_has_async_subdev(
> > > +				    notifier, asd->match.fwnode.fwnode, i)) {
> > > +				dev_err(dev,
> > > +					"fwnode has already been registered or in notifier's subdev list\n");
> > > +				ret = -EEXIST;
> > > +				goto out_unlock;
> > 
> > You store the error code in ret before the jump, but in the out_unlock 
> > path ret is not considered and 0 is always returned.
> > 
> > > +			}
> > >  			break;
> > >  		default:
> > > -			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
> > > -				"Invalid match type %u on %p\n",
> > > +			dev_err(dev, "Invalid match type %u on %p\n",
> > >  				asd->match_type, asd);
> > > -			return -EINVAL;
> > > +			ret = -EINVAL;
> > > +			goto out_unlock;
> > 
> > Same here.
> 
> Good catch! How about this change on top of the patch? It makes return
> value checks a little bit safer, too.

I'm happy whit this change, feel free to add

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index b4e88eef195f..a33a68e5417b 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -412,12 +412,13 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  	}
>  
>  	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> -	if (ret)
> +	if (ret < 0)
>  		goto err_unbind;
>  
>  	ret = v4l2_async_notifier_try_complete(notifier);
> -	if (ret)
> +	if (ret < 0)
>  		goto err_unbind;
> +	ret = 0;
>  
>  	/* Keep also completed notifiers on the list */
>  	list_add(&notifier->list, &notifier_list);
> @@ -425,7 +426,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  out_unlock:
>  	mutex_unlock(&list_lock);
>  
> -	return 0;
> +	return ret;
>  
>  err_unbind:
>  	/*
> 
> > 
> > >  		}
> > >  		list_add_tail(&asd->list, &notifier->waiting);
> > >  	}
> > >  
> > > -	mutex_lock(&list_lock);
> > > -
> > >  	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> > >  	if (ret)
> > >  		goto err_unbind;
> > > @@ -351,6 +422,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> > >  	/* Keep also completed notifiers on the list */
> > >  	list_add(&notifier->list, &notifier_list);
> > >  
> > > +out_unlock:
> > >  	mutex_unlock(&list_lock);
> > >  
> > >  	return 0;
> 
> -- 
> Sakari Ailus
> e-mail: sakari.ailus@iki.fi

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 23/32] v4l: fwnode: Add a helper function for parsing generic references
  2017-10-26  7:53 ` [PATCH v16 23/32] v4l: fwnode: Add a helper function for parsing generic references Sakari Ailus
@ 2017-10-27 10:30   ` Niklas Söderlund
  2017-10-29 22:53   ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-27 10:30 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:33 +0300, Sakari Ailus wrote:
> Add function v4l2_fwnode_reference_parse() for parsing them as async
> sub-devices. This can be done on e.g. flash or lens async sub-devices that
> are not part of but are associated with a sensor.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-fwnode.c | 69 +++++++++++++++++++++++++++++++++++
>  1 file changed, 69 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 65bdcd59744a..edd2e8d983a1 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -509,6 +509,75 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
>  }
>  EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
>  
> +/*
> + * v4l2_fwnode_reference_parse - parse references for async sub-devices
> + * @dev: the device node the properties of which are parsed for references
> + * @notifier: the async notifier where the async subdevs will be added
> + * @prop: the name of the property
> + *
> + * Return: 0 on success
> + *	   -ENOENT if no entries were found
> + *	   -ENOMEM if memory allocation failed
> + *	   -EINVAL if property parsing failed
> + */
> +static int v4l2_fwnode_reference_parse(
> +	struct device *dev, struct v4l2_async_notifier *notifier,
> +	const char *prop)
> +{
> +	struct fwnode_reference_args args;
> +	unsigned int index;
> +	int ret;
> +
> +	for (index = 0;
> +	     !(ret = fwnode_property_get_reference_args(
> +		       dev_fwnode(dev), prop, NULL, 0, index, &args));
> +	     index++)
> +		fwnode_handle_put(args.fwnode);
> +
> +	if (!index)
> +		return -ENOENT;
> +
> +	/*
> +	 * Note that right now both -ENODATA and -ENOENT may signal
> +	 * out-of-bounds access. Return the error in cases other than that.
> +	 */
> +	if (ret != -ENOENT && ret != -ENODATA)
> +		return ret;
> +
> +	ret = v4l2_async_notifier_realloc(notifier,
> +					  notifier->num_subdevs + index);
> +	if (ret)
> +		return ret;
> +
> +	for (index = 0; !fwnode_property_get_reference_args(
> +		     dev_fwnode(dev), prop, NULL, 0, index, &args);
> +	     index++) {
> +		struct v4l2_async_subdev *asd;
> +
> +		if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
> +			ret = -EINVAL;
> +			goto error;
> +		}
> +
> +		asd = kzalloc(sizeof(*asd), GFP_KERNEL);
> +		if (!asd) {
> +			ret = -ENOMEM;
> +			goto error;
> +		}
> +
> +		notifier->subdevs[notifier->num_subdevs] = asd;
> +		asd->match.fwnode.fwnode = args.fwnode;
> +		asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> +		notifier->num_subdevs++;
> +	}
> +
> +	return 0;
> +
> +error:
> +	fwnode_handle_put(args.fwnode);
> +	return ret;
> +}
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
>  MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* [PATCH v16.1 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers
  2017-10-26  7:53 ` [PATCH v16 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers Sakari Ailus
  2017-10-27  9:52   ` Niklas Söderlund
@ 2017-10-27 10:53   ` Sakari Ailus
  2017-10-29 22:25     ` Sebastian Reichel
  2017-10-30 13:09     ` [PATCH v16.2 " Sakari Ailus
  1 sibling, 2 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-27 10:53 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart, pavel, sre

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>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
---
 drivers/media/v4l2-core/v4l2-async.c | 89 ++++++++++++++++++++++++++++++++----
 1 file changed, 81 insertions(+), 8 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index ed539c4fd5dc..a33a68e5417b 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -308,8 +308,71 @@ static void v4l2_async_notifier_unbind_all_subdevs(
 	notifier->parent = NULL;
 }
 
+/* See if an fwnode can be found in a notifier's lists. */
+static bool __v4l2_async_notifier_fwnode_has_async_subdev(
+	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
+{
+	struct v4l2_async_subdev *asd;
+	struct v4l2_subdev *sd;
+
+	list_for_each_entry(asd, &notifier->waiting, list) {
+		if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
+			continue;
+
+		if (asd->match.fwnode.fwnode == fwnode)
+			return true;
+	}
+
+	list_for_each_entry(sd, &notifier->done, async_list) {
+		if (WARN_ON(!sd->asd))
+			continue;
+
+		if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
+			continue;
+
+		if (sd->asd->match.fwnode.fwnode == fwnode)
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * Find out whether an async sub-device was set up for an fwnode already or
+ * whether it exists in a given notifier before @this_index.
+ */
+static bool v4l2_async_notifier_fwnode_has_async_subdev(
+	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
+	unsigned int this_index)
+{
+	unsigned int j;
+
+	lockdep_assert_held(&list_lock);
+
+	/* Check that an fwnode is not being added more than once. */
+	for (j = 0; j < this_index; j++) {
+		struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
+		struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
+
+		if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
+		    asd->match.fwnode.fwnode ==
+		    other_asd->match.fwnode.fwnode)
+			return true;
+	}
+
+	/* Check than an fwnode did not exist in other notifiers. */
+	list_for_each_entry(notifier, &notifier_list, list)
+		if (__v4l2_async_notifier_fwnode_has_async_subdev(
+			    notifier, fwnode))
+			return true;
+
+	return false;
+}
+
 static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 {
+	struct device *dev =
+		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
 	struct v4l2_async_subdev *asd;
 	int ret;
 	int i;
@@ -320,6 +383,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	INIT_LIST_HEAD(&notifier->waiting);
 	INIT_LIST_HEAD(&notifier->done);
 
+	mutex_lock(&list_lock);
+
 	for (i = 0; i < notifier->num_subdevs; i++) {
 		asd = notifier->subdevs[i];
 
@@ -327,33 +392,41 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 		case V4L2_ASYNC_MATCH_CUSTOM:
 		case V4L2_ASYNC_MATCH_DEVNAME:
 		case V4L2_ASYNC_MATCH_I2C:
+			break;
 		case V4L2_ASYNC_MATCH_FWNODE:
+			if (v4l2_async_notifier_fwnode_has_async_subdev(
+				    notifier, asd->match.fwnode.fwnode, i)) {
+				dev_err(dev,
+					"fwnode has already been registered or in notifier's subdev list\n");
+				ret = -EEXIST;
+				goto out_unlock;
+			}
 			break;
 		default:
-			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
-				"Invalid match type %u on %p\n",
+			dev_err(dev, "Invalid match type %u on %p\n",
 				asd->match_type, asd);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto out_unlock;
 		}
 		list_add_tail(&asd->list, &notifier->waiting);
 	}
 
-	mutex_lock(&list_lock);
-
 	ret = v4l2_async_notifier_try_all_subdevs(notifier);
-	if (ret)
+	if (ret < 0)
 		goto err_unbind;
 
 	ret = v4l2_async_notifier_try_complete(notifier);
-	if (ret)
+	if (ret < 0)
 		goto err_unbind;
+	ret = 0;
 
 	/* Keep also completed notifiers on the list */
 	list_add(&notifier->list, &notifier_list);
 
+out_unlock:
 	mutex_unlock(&list_lock);
 
-	return 0;
+	return ret;
 
 err_unbind:
 	/*
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 26/32] v4l: fwnode: Add a convenience function for registering sensors
  2017-10-26  7:53     ` Sakari Ailus
  (?)
@ 2017-10-27 13:06     ` Niklas Söderlund
  -1 siblings, 0 replies; 107+ messages in thread
From: Niklas Söderlund @ 2017-10-27 13:06 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, maxime.ripard, hverkuil, laurent.pinchart, pavel,
	sre, linux-acpi, devicetree

On 2017-10-26 10:53:36 +0300, Sakari Ailus wrote:
> Add a convenience function for parsing firmware for information on related
> devices using v4l2_async_notifier_parse_fwnode_sensor_common() registering
> the notifier and finally the async sub-device itself.
> 
> This should be useful for sensor drivers that do not have device specific
> requirements related to firmware information parsing or the async
> framework.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>

Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>

> ---
>  drivers/media/v4l2-core/v4l2-async.c  | 19 ++++++++++++----
>  drivers/media/v4l2-core/v4l2-fwnode.c | 41 +++++++++++++++++++++++++++++++++++
>  include/media/v4l2-async.h            | 22 +++++++++++++++++++
>  include/media/v4l2-subdev.h           |  3 +++
>  4 files changed, 81 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index b4e88eef195f..e81a72b8d46e 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -474,19 +474,25 @@ int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
>  }
>  EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
>  
> -void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> +static void __v4l2_async_notifier_unregister(
> +	struct v4l2_async_notifier *notifier)
>  {
> -	if (!notifier->v4l2_dev && !notifier->sd)
> +	if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
>  		return;
>  
> -	mutex_lock(&list_lock);
> -
>  	v4l2_async_notifier_unbind_all_subdevs(notifier);
>  
>  	notifier->sd = NULL;
>  	notifier->v4l2_dev = NULL;
>  
>  	list_del(&notifier->list);
> +}
> +
> +void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> +{
> +	mutex_lock(&list_lock);
> +
> +	__v4l2_async_notifier_unregister(notifier);
>  
>  	mutex_unlock(&list_lock);
>  }
> @@ -596,6 +602,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  {
>  	mutex_lock(&list_lock);
>  
> +	__v4l2_async_notifier_unregister(sd->subdev_notifier);
> +	v4l2_async_notifier_cleanup(sd->subdev_notifier);
> +	kfree(sd->subdev_notifier);
> +	sd->subdev_notifier = NULL;
> +
>  	if (sd->asd) {
>  		struct v4l2_async_notifier *notifier = sd->notifier;
>  
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 1234bd1a2f49..82af608fd626 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -29,6 +29,7 @@
>  
>  #include <media/v4l2-async.h>
>  #include <media/v4l2-fwnode.h>
> +#include <media/v4l2-subdev.h>
>  
>  enum v4l2_fwnode_bus_type {
>  	V4L2_FWNODE_BUS_TYPE_GUESS = 0,
> @@ -900,6 +901,46 @@ int v4l2_async_notifier_parse_fwnode_sensor_common(
>  }
>  EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
>  
> +int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
> +{
> +	struct v4l2_async_notifier *notifier;
> +	int ret;
> +
> +	if (WARN_ON(!sd->dev))
> +		return -ENODEV;
> +
> +	notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
> +	if (!notifier)
> +		return -ENOMEM;
> +
> +	ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
> +							     notifier);
> +	if (ret < 0)
> +		goto out_cleanup;
> +
> +	ret = v4l2_async_subdev_notifier_register(sd, notifier);
> +	if (ret < 0)
> +		goto out_cleanup;
> +
> +	ret = v4l2_async_register_subdev(sd);
> +	if (ret < 0)
> +		goto out_unregister;
> +
> +	sd->subdev_notifier = notifier;
> +
> +	return 0;
> +
> +out_unregister:
> +	v4l2_async_notifier_unregister(notifier);
> +
> +out_cleanup:
> +	v4l2_async_notifier_cleanup(notifier);
> +	kfree(notifier);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
>  MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 8d8cfc3f3100..6152434cbe82 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -174,6 +174,28 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier);
>  int v4l2_async_register_subdev(struct v4l2_subdev *sd);
>  
>  /**
> + * v4l2_async_register_subdev_sensor_common - registers a sensor sub-device to
> + *					      the asynchronous sub-device
> + *					      framework and parse set up common
> + *					      sensor related devices
> + *
> + * @sd: pointer to struct &v4l2_subdev
> + *
> + * This function is just like v4l2_async_register_subdev() with the exception
> + * that calling it will also parse firmware interfaces for remote references
> + * using v4l2_async_notifier_parse_fwnode_sensor_common() and registers the
> + * async sub-devices. The sub-device is similarly unregistered by calling
> + * v4l2_async_unregister_subdev().
> + *
> + * While registered, the subdev module is marked as in-use.
> + *
> + * An error is returned if the module is no longer loaded on any attempts
> + * to register it.
> + */
> +int __must_check v4l2_async_register_subdev_sensor_common(
> +	struct v4l2_subdev *sd);
> +
> +/**
>   * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous
>   * 	subdevice framework
>   *
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index e83872078376..ec399c770301 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -793,6 +793,8 @@ struct v4l2_subdev_platform_data {
>   *	list.
>   * @asd: Pointer to respective &struct v4l2_async_subdev.
>   * @notifier: Pointer to the managing notifier.
> + * @subdev_notifier: A sub-device notifier implicitly registered for the sub-
> + *		     device using v4l2_device_register_sensor_subdev().
>   * @pdata: common part of subdevice platform data
>   *
>   * Each instance of a subdev driver should create this struct, either
> @@ -823,6 +825,7 @@ struct v4l2_subdev {
>  	struct list_head async_list;
>  	struct v4l2_async_subdev *asd;
>  	struct v4l2_async_notifier *notifier;
> +	struct v4l2_async_notifier *subdev_notifier;
>  	struct v4l2_subdev_platform_data *pdata;
>  };
>  
> -- 
> 2.11.0
> 

-- 
Regards,
Niklas Söderlund

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 27/32] dt: bindings: smiapp: Document lens-focus and flash-leds properties
  2017-10-26  7:53     ` Sakari Ailus
  (?)
@ 2017-10-27 14:38     ` Rob Herring
  -1 siblings, 0 replies; 107+ messages in thread
From: Rob Herring @ 2017-10-27 14:38 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, sre, linux-acpi, devicetree

On Thu, Oct 26, 2017 at 10:53:37AM +0300, Sakari Ailus wrote:
> Document optional lens-focus and flash-leds properties for the smiapp
> driver.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> ---
>  Documentation/devicetree/bindings/media/i2c/nokia,smia.txt | 2 ++
>  1 file changed, 2 insertions(+)

Acked-by: Rob Herring <robh@kernel.org>

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 04/32] v4l: async: Fix notifier complete callback error handling
  2017-10-26  7:53     ` Sakari Ailus
  (?)
  (?)
@ 2017-10-27 14:46     ` Sebastian Reichel
  -1 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:46 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 4830 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:14AM +0300, Sakari Ailus wrote:
> The notifier complete callback may return an error. This error code was
> simply returned to the caller but never handled properly.
> 
> Move calling the complete callback function to the caller from
> v4l2_async_test_notify and undo the work that was done either in async
> sub-device or async notifier registration.
> 
> Reported-by: Russell King <rmk+kernel@armlinux.org.uk>
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/v4l2-core/v4l2-async.c | 78 +++++++++++++++++++++++++++---------
>  1 file changed, 60 insertions(+), 18 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index ca281438a0ae..4924481451ca 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -122,9 +122,6 @@ static int v4l2_async_test_notify(struct v4l2_async_notifier *notifier,
>  	/* Move from the global subdevice list to notifier's done */
>  	list_move(&sd->async_list, &notifier->done);
>  
> -	if (list_empty(&notifier->waiting) && notifier->complete)
> -		return notifier->complete(notifier);
> -
>  	return 0;
>  }
>  
> @@ -136,11 +133,27 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  	sd->asd = NULL;
>  }
>  
> +static void v4l2_async_notifier_unbind_all_subdevs(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_subdev *sd, *tmp;
> +
> +	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> +		if (notifier->unbind)
> +			notifier->unbind(notifier, sd, sd->asd);
> +
> +		v4l2_async_cleanup(sd);
> +
> +		list_move(&sd->async_list, &subdev_list);
> +	}
> +}
> +
>  int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  				 struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_subdev *sd, *tmp;
>  	struct v4l2_async_subdev *asd;
> +	int ret;
>  	int i;
>  
>  	if (!v4l2_dev || !notifier->num_subdevs ||
> @@ -185,19 +198,30 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  		}
>  	}
>  
> +	if (list_empty(&notifier->waiting) && notifier->complete) {
> +		ret = notifier->complete(notifier);
> +		if (ret)
> +			goto err_complete;
> +	}
> +
>  	/* Keep also completed notifiers on the list */
>  	list_add(&notifier->list, &notifier_list);
>  
>  	mutex_unlock(&list_lock);
>  
>  	return 0;
> +
> +err_complete:
> +	v4l2_async_notifier_unbind_all_subdevs(notifier);
> +
> +	mutex_unlock(&list_lock);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(v4l2_async_notifier_register);
>  
>  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
>  {
> -	struct v4l2_subdev *sd, *tmp;
> -
>  	if (!notifier->v4l2_dev)
>  		return;
>  
> @@ -205,14 +229,7 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
>  
>  	list_del(&notifier->list);
>  
> -	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> -		if (notifier->unbind)
> -			notifier->unbind(notifier, sd, sd->asd);
> -
> -		v4l2_async_cleanup(sd);
> -
> -		list_move(&sd->async_list, &subdev_list);
> -	}
> +	v4l2_async_notifier_unbind_all_subdevs(notifier);
>  
>  	mutex_unlock(&list_lock);
>  
> @@ -223,6 +240,7 @@ EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>  int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  {
>  	struct v4l2_async_notifier *notifier;
> +	int ret;
>  
>  	/*
>  	 * No reference taken. The reference is held by the device
> @@ -238,19 +256,43 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  
>  	list_for_each_entry(notifier, &notifier_list, list) {
>  		struct v4l2_async_subdev *asd = v4l2_async_belongs(notifier, sd);
> -		if (asd) {
> -			int ret = v4l2_async_test_notify(notifier, sd, asd);
> -			mutex_unlock(&list_lock);
> -			return ret;
> -		}
> +		int ret;
> +
> +		if (!asd)
> +			continue;
> +
> +		ret = v4l2_async_test_notify(notifier, sd, asd);
> +		if (ret)
> +			goto err_unlock;
> +
> +		if (!list_empty(&notifier->waiting) || !notifier->complete)
> +			goto out_unlock;
> +
> +		ret = notifier->complete(notifier);
> +		if (ret)
> +			goto err_cleanup;
> +
> +		goto out_unlock;
>  	}
>  
>  	/* None matched, wait for hot-plugging */
>  	list_add(&sd->async_list, &subdev_list);
>  
> +out_unlock:
>  	mutex_unlock(&list_lock);
>  
>  	return 0;
> +
> +err_cleanup:
> +	if (notifier->unbind)
> +		notifier->unbind(notifier, sd, sd->asd);
> +
> +	v4l2_async_cleanup(sd);
> +
> +err_unlock:
> +	mutex_unlock(&list_lock);
> +
> +	return ret;
>  }
>  EXPORT_SYMBOL(v4l2_async_register_subdev);
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 09/32] omap3isp: Use generic parser for parsing fwnode endpoints
  2017-10-26  7:53 ` [PATCH v16 09/32] omap3isp: Use generic parser for parsing fwnode endpoints Sakari Ailus
@ 2017-10-27 14:46       ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:46 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 9580 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:19AM +0300, Sakari Ailus wrote:
> Instead of using a custom driver implementation, use
> v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints
> of the device.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> Reviewed-by: Laurent Pinchart <laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw@public.gmane.org>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>

-- Sebastian

>  drivers/media/platform/omap3isp/isp.c | 121 +++++++++++-----------------------
>  drivers/media/platform/omap3isp/isp.h |   5 +-
>  2 files changed, 40 insertions(+), 86 deletions(-)
> 
> diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
> index 1a428fe9f070..97a5206b6ddc 100644
> --- a/drivers/media/platform/omap3isp/isp.c
> +++ b/drivers/media/platform/omap3isp/isp.c
> @@ -2001,6 +2001,7 @@ static int isp_remove(struct platform_device *pdev)
>  	__omap3isp_put(isp, false);
>  
>  	media_entity_enum_cleanup(&isp->crashed);
> +	v4l2_async_notifier_cleanup(&isp->notifier);
>  
>  	return 0;
>  }
> @@ -2011,44 +2012,41 @@ enum isp_of_phy {
>  	ISP_OF_PHY_CSIPHY2,
>  };
>  
> -static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
> -			    struct isp_async_subdev *isd)
> +static int isp_fwnode_parse(struct device *dev,
> +			    struct v4l2_fwnode_endpoint *vep,
> +			    struct v4l2_async_subdev *asd)
>  {
> +	struct isp_async_subdev *isd =
> +		container_of(asd, struct isp_async_subdev, asd);
>  	struct isp_bus_cfg *buscfg = &isd->bus;
> -	struct v4l2_fwnode_endpoint vep;
> -	unsigned int i;
> -	int ret;
>  	bool csi1 = false;
> -
> -	ret = v4l2_fwnode_endpoint_parse(fwnode, &vep);
> -	if (ret)
> -		return ret;
> +	unsigned int i;
>  
>  	dev_dbg(dev, "parsing endpoint %pOF, interface %u\n",
> -		to_of_node(fwnode), vep.base.port);
> +		to_of_node(vep->base.local_fwnode), vep->base.port);
>  
> -	switch (vep.base.port) {
> +	switch (vep->base.port) {
>  	case ISP_OF_PHY_PARALLEL:
>  		buscfg->interface = ISP_INTERFACE_PARALLEL;
>  		buscfg->bus.parallel.data_lane_shift =
> -			vep.bus.parallel.data_shift;
> +			vep->bus.parallel.data_shift;
>  		buscfg->bus.parallel.clk_pol =
> -			!!(vep.bus.parallel.flags
> +			!!(vep->bus.parallel.flags
>  			   & V4L2_MBUS_PCLK_SAMPLE_FALLING);
>  		buscfg->bus.parallel.hs_pol =
> -			!!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
> +			!!(vep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
>  		buscfg->bus.parallel.vs_pol =
> -			!!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
> +			!!(vep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
>  		buscfg->bus.parallel.fld_pol =
> -			!!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
> +			!!(vep->bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
>  		buscfg->bus.parallel.data_pol =
> -			!!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
> -		buscfg->bus.parallel.bt656 = vep.bus_type == V4L2_MBUS_BT656;
> +			!!(vep->bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
> +		buscfg->bus.parallel.bt656 = vep->bus_type == V4L2_MBUS_BT656;
>  		break;
>  
>  	case ISP_OF_PHY_CSIPHY1:
>  	case ISP_OF_PHY_CSIPHY2:
> -		switch (vep.bus_type) {
> +		switch (vep->bus_type) {
>  		case V4L2_MBUS_CCP2:
>  		case V4L2_MBUS_CSI1:
>  			dev_dbg(dev, "CSI-1/CCP-2 configuration\n");
> @@ -2060,11 +2058,11 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
>  			break;
>  		default:
>  			dev_err(dev, "unsupported bus type %u\n",
> -				vep.bus_type);
> +				vep->bus_type);
>  			return -EINVAL;
>  		}
>  
> -		switch (vep.base.port) {
> +		switch (vep->base.port) {
>  		case ISP_OF_PHY_CSIPHY1:
>  			if (csi1)
>  				buscfg->interface = ISP_INTERFACE_CCP2B_PHY1;
> @@ -2080,47 +2078,47 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
>  		}
>  		if (csi1) {
>  			buscfg->bus.ccp2.lanecfg.clk.pos =
> -				vep.bus.mipi_csi1.clock_lane;
> +				vep->bus.mipi_csi1.clock_lane;
>  			buscfg->bus.ccp2.lanecfg.clk.pol =
> -				vep.bus.mipi_csi1.lane_polarity[0];
> +				vep->bus.mipi_csi1.lane_polarity[0];
>  			dev_dbg(dev, "clock lane polarity %u, pos %u\n",
>  				buscfg->bus.ccp2.lanecfg.clk.pol,
>  				buscfg->bus.ccp2.lanecfg.clk.pos);
>  
>  			buscfg->bus.ccp2.lanecfg.data[0].pos =
> -				vep.bus.mipi_csi1.data_lane;
> +				vep->bus.mipi_csi1.data_lane;
>  			buscfg->bus.ccp2.lanecfg.data[0].pol =
> -				vep.bus.mipi_csi1.lane_polarity[1];
> +				vep->bus.mipi_csi1.lane_polarity[1];
>  
>  			dev_dbg(dev, "data lane polarity %u, pos %u\n",
>  				buscfg->bus.ccp2.lanecfg.data[0].pol,
>  				buscfg->bus.ccp2.lanecfg.data[0].pos);
>  
>  			buscfg->bus.ccp2.strobe_clk_pol =
> -				vep.bus.mipi_csi1.clock_inv;
> -			buscfg->bus.ccp2.phy_layer = vep.bus.mipi_csi1.strobe;
> +				vep->bus.mipi_csi1.clock_inv;
> +			buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe;
>  			buscfg->bus.ccp2.ccp2_mode =
> -				vep.bus_type == V4L2_MBUS_CCP2;
> +				vep->bus_type == V4L2_MBUS_CCP2;
>  			buscfg->bus.ccp2.vp_clk_pol = 1;
>  
>  			buscfg->bus.ccp2.crc = 1;
>  		} else {
>  			buscfg->bus.csi2.lanecfg.clk.pos =
> -				vep.bus.mipi_csi2.clock_lane;
> +				vep->bus.mipi_csi2.clock_lane;
>  			buscfg->bus.csi2.lanecfg.clk.pol =
> -				vep.bus.mipi_csi2.lane_polarities[0];
> +				vep->bus.mipi_csi2.lane_polarities[0];
>  			dev_dbg(dev, "clock lane polarity %u, pos %u\n",
>  				buscfg->bus.csi2.lanecfg.clk.pol,
>  				buscfg->bus.csi2.lanecfg.clk.pos);
>  
>  			buscfg->bus.csi2.num_data_lanes =
> -				vep.bus.mipi_csi2.num_data_lanes;
> +				vep->bus.mipi_csi2.num_data_lanes;
>  
>  			for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) {
>  				buscfg->bus.csi2.lanecfg.data[i].pos =
> -					vep.bus.mipi_csi2.data_lanes[i];
> +					vep->bus.mipi_csi2.data_lanes[i];
>  				buscfg->bus.csi2.lanecfg.data[i].pol =
> -					vep.bus.mipi_csi2.lane_polarities[i + 1];
> +					vep->bus.mipi_csi2.lane_polarities[i + 1];
>  				dev_dbg(dev,
>  					"data lane %u polarity %u, pos %u\n", i,
>  					buscfg->bus.csi2.lanecfg.data[i].pol,
> @@ -2137,57 +2135,13 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
>  
>  	default:
>  		dev_warn(dev, "%pOF: invalid interface %u\n",
> -			 to_of_node(fwnode), vep.base.port);
> +			 to_of_node(vep->base.local_fwnode), vep->base.port);
>  		return -EINVAL;
>  	}
>  
>  	return 0;
>  }
>  
> -static int isp_fwnodes_parse(struct device *dev,
> -			     struct v4l2_async_notifier *notifier)
> -{
> -	struct fwnode_handle *fwnode = NULL;
> -
> -	notifier->subdevs = devm_kcalloc(
> -		dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), GFP_KERNEL);
> -	if (!notifier->subdevs)
> -		return -ENOMEM;
> -
> -	while (notifier->num_subdevs < ISP_MAX_SUBDEVS &&
> -	       (fwnode = fwnode_graph_get_next_endpoint(
> -			of_fwnode_handle(dev->of_node), fwnode))) {
> -		struct isp_async_subdev *isd;
> -
> -		isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL);
> -		if (!isd)
> -			goto error;
> -
> -		if (isp_fwnode_parse(dev, fwnode, isd)) {
> -			devm_kfree(dev, isd);
> -			continue;
> -		}
> -
> -		notifier->subdevs[notifier->num_subdevs] = &isd->asd;
> -
> -		isd->asd.match.fwnode.fwnode =
> -			fwnode_graph_get_remote_port_parent(fwnode);
> -		if (!isd->asd.match.fwnode.fwnode) {
> -			dev_warn(dev, "bad remote port parent\n");
> -			goto error;
> -		}
> -
> -		isd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
> -		notifier->num_subdevs++;
> -	}
> -
> -	return notifier->num_subdevs;
> -
> -error:
> -	fwnode_handle_put(fwnode);
> -	return -EINVAL;
> -}
> -
>  static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
>  {
>  	struct isp_device *isp = container_of(async, struct isp_device,
> @@ -2256,15 +2210,17 @@ static int isp_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> -	ret = isp_fwnodes_parse(&pdev->dev, &isp->notifier);
> -	if (ret < 0)
> -		return ret;
> -
>  	isp->autoidle = autoidle;
>  
>  	mutex_init(&isp->isp_mutex);
>  	spin_lock_init(&isp->stat_lock);
>  
> +	ret = v4l2_async_notifier_parse_fwnode_endpoints(
> +		&pdev->dev, &isp->notifier, sizeof(struct isp_async_subdev),
> +		isp_fwnode_parse);
> +	if (ret < 0)
> +		goto error;
> +
>  	isp->dev = &pdev->dev;
>  	isp->ref_count = 0;
>  
> @@ -2406,6 +2362,7 @@ static int isp_probe(struct platform_device *pdev)
>  	isp_xclk_cleanup(isp);
>  	__omap3isp_put(isp, false);
>  error:
> +	v4l2_async_notifier_cleanup(&isp->notifier);
>  	mutex_destroy(&isp->isp_mutex);
>  
>  	return ret;
> diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
> index e528df6efc09..8b9043db94b3 100644
> --- a/drivers/media/platform/omap3isp/isp.h
> +++ b/drivers/media/platform/omap3isp/isp.h
> @@ -220,14 +220,11 @@ struct isp_device {
>  
>  	unsigned int sbl_resources;
>  	unsigned int subclk_resources;
> -
> -#define ISP_MAX_SUBDEVS		8
> -	struct v4l2_subdev *subdevs[ISP_MAX_SUBDEVS];
>  };
>  
>  struct isp_async_subdev {
> -	struct isp_bus_cfg bus;
>  	struct v4l2_async_subdev asd;
> +	struct isp_bus_cfg bus;
>  };
>  
>  #define v4l2_subdev_to_bus_cfg(sd) \
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 09/32] omap3isp: Use generic parser for parsing fwnode endpoints
@ 2017-10-27 14:46       ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:46 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 9479 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:19AM +0300, Sakari Ailus wrote:
> Instead of using a custom driver implementation, use
> v4l2_async_notifier_parse_fwnode_endpoints() to parse the fwnode endpoints
> of the device.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Reviewed-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/platform/omap3isp/isp.c | 121 +++++++++++-----------------------
>  drivers/media/platform/omap3isp/isp.h |   5 +-
>  2 files changed, 40 insertions(+), 86 deletions(-)
> 
> diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
> index 1a428fe9f070..97a5206b6ddc 100644
> --- a/drivers/media/platform/omap3isp/isp.c
> +++ b/drivers/media/platform/omap3isp/isp.c
> @@ -2001,6 +2001,7 @@ static int isp_remove(struct platform_device *pdev)
>  	__omap3isp_put(isp, false);
>  
>  	media_entity_enum_cleanup(&isp->crashed);
> +	v4l2_async_notifier_cleanup(&isp->notifier);
>  
>  	return 0;
>  }
> @@ -2011,44 +2012,41 @@ enum isp_of_phy {
>  	ISP_OF_PHY_CSIPHY2,
>  };
>  
> -static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
> -			    struct isp_async_subdev *isd)
> +static int isp_fwnode_parse(struct device *dev,
> +			    struct v4l2_fwnode_endpoint *vep,
> +			    struct v4l2_async_subdev *asd)
>  {
> +	struct isp_async_subdev *isd =
> +		container_of(asd, struct isp_async_subdev, asd);
>  	struct isp_bus_cfg *buscfg = &isd->bus;
> -	struct v4l2_fwnode_endpoint vep;
> -	unsigned int i;
> -	int ret;
>  	bool csi1 = false;
> -
> -	ret = v4l2_fwnode_endpoint_parse(fwnode, &vep);
> -	if (ret)
> -		return ret;
> +	unsigned int i;
>  
>  	dev_dbg(dev, "parsing endpoint %pOF, interface %u\n",
> -		to_of_node(fwnode), vep.base.port);
> +		to_of_node(vep->base.local_fwnode), vep->base.port);
>  
> -	switch (vep.base.port) {
> +	switch (vep->base.port) {
>  	case ISP_OF_PHY_PARALLEL:
>  		buscfg->interface = ISP_INTERFACE_PARALLEL;
>  		buscfg->bus.parallel.data_lane_shift =
> -			vep.bus.parallel.data_shift;
> +			vep->bus.parallel.data_shift;
>  		buscfg->bus.parallel.clk_pol =
> -			!!(vep.bus.parallel.flags
> +			!!(vep->bus.parallel.flags
>  			   & V4L2_MBUS_PCLK_SAMPLE_FALLING);
>  		buscfg->bus.parallel.hs_pol =
> -			!!(vep.bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
> +			!!(vep->bus.parallel.flags & V4L2_MBUS_VSYNC_ACTIVE_LOW);
>  		buscfg->bus.parallel.vs_pol =
> -			!!(vep.bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
> +			!!(vep->bus.parallel.flags & V4L2_MBUS_HSYNC_ACTIVE_LOW);
>  		buscfg->bus.parallel.fld_pol =
> -			!!(vep.bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
> +			!!(vep->bus.parallel.flags & V4L2_MBUS_FIELD_EVEN_LOW);
>  		buscfg->bus.parallel.data_pol =
> -			!!(vep.bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
> -		buscfg->bus.parallel.bt656 = vep.bus_type == V4L2_MBUS_BT656;
> +			!!(vep->bus.parallel.flags & V4L2_MBUS_DATA_ACTIVE_LOW);
> +		buscfg->bus.parallel.bt656 = vep->bus_type == V4L2_MBUS_BT656;
>  		break;
>  
>  	case ISP_OF_PHY_CSIPHY1:
>  	case ISP_OF_PHY_CSIPHY2:
> -		switch (vep.bus_type) {
> +		switch (vep->bus_type) {
>  		case V4L2_MBUS_CCP2:
>  		case V4L2_MBUS_CSI1:
>  			dev_dbg(dev, "CSI-1/CCP-2 configuration\n");
> @@ -2060,11 +2058,11 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
>  			break;
>  		default:
>  			dev_err(dev, "unsupported bus type %u\n",
> -				vep.bus_type);
> +				vep->bus_type);
>  			return -EINVAL;
>  		}
>  
> -		switch (vep.base.port) {
> +		switch (vep->base.port) {
>  		case ISP_OF_PHY_CSIPHY1:
>  			if (csi1)
>  				buscfg->interface = ISP_INTERFACE_CCP2B_PHY1;
> @@ -2080,47 +2078,47 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
>  		}
>  		if (csi1) {
>  			buscfg->bus.ccp2.lanecfg.clk.pos =
> -				vep.bus.mipi_csi1.clock_lane;
> +				vep->bus.mipi_csi1.clock_lane;
>  			buscfg->bus.ccp2.lanecfg.clk.pol =
> -				vep.bus.mipi_csi1.lane_polarity[0];
> +				vep->bus.mipi_csi1.lane_polarity[0];
>  			dev_dbg(dev, "clock lane polarity %u, pos %u\n",
>  				buscfg->bus.ccp2.lanecfg.clk.pol,
>  				buscfg->bus.ccp2.lanecfg.clk.pos);
>  
>  			buscfg->bus.ccp2.lanecfg.data[0].pos =
> -				vep.bus.mipi_csi1.data_lane;
> +				vep->bus.mipi_csi1.data_lane;
>  			buscfg->bus.ccp2.lanecfg.data[0].pol =
> -				vep.bus.mipi_csi1.lane_polarity[1];
> +				vep->bus.mipi_csi1.lane_polarity[1];
>  
>  			dev_dbg(dev, "data lane polarity %u, pos %u\n",
>  				buscfg->bus.ccp2.lanecfg.data[0].pol,
>  				buscfg->bus.ccp2.lanecfg.data[0].pos);
>  
>  			buscfg->bus.ccp2.strobe_clk_pol =
> -				vep.bus.mipi_csi1.clock_inv;
> -			buscfg->bus.ccp2.phy_layer = vep.bus.mipi_csi1.strobe;
> +				vep->bus.mipi_csi1.clock_inv;
> +			buscfg->bus.ccp2.phy_layer = vep->bus.mipi_csi1.strobe;
>  			buscfg->bus.ccp2.ccp2_mode =
> -				vep.bus_type == V4L2_MBUS_CCP2;
> +				vep->bus_type == V4L2_MBUS_CCP2;
>  			buscfg->bus.ccp2.vp_clk_pol = 1;
>  
>  			buscfg->bus.ccp2.crc = 1;
>  		} else {
>  			buscfg->bus.csi2.lanecfg.clk.pos =
> -				vep.bus.mipi_csi2.clock_lane;
> +				vep->bus.mipi_csi2.clock_lane;
>  			buscfg->bus.csi2.lanecfg.clk.pol =
> -				vep.bus.mipi_csi2.lane_polarities[0];
> +				vep->bus.mipi_csi2.lane_polarities[0];
>  			dev_dbg(dev, "clock lane polarity %u, pos %u\n",
>  				buscfg->bus.csi2.lanecfg.clk.pol,
>  				buscfg->bus.csi2.lanecfg.clk.pos);
>  
>  			buscfg->bus.csi2.num_data_lanes =
> -				vep.bus.mipi_csi2.num_data_lanes;
> +				vep->bus.mipi_csi2.num_data_lanes;
>  
>  			for (i = 0; i < buscfg->bus.csi2.num_data_lanes; i++) {
>  				buscfg->bus.csi2.lanecfg.data[i].pos =
> -					vep.bus.mipi_csi2.data_lanes[i];
> +					vep->bus.mipi_csi2.data_lanes[i];
>  				buscfg->bus.csi2.lanecfg.data[i].pol =
> -					vep.bus.mipi_csi2.lane_polarities[i + 1];
> +					vep->bus.mipi_csi2.lane_polarities[i + 1];
>  				dev_dbg(dev,
>  					"data lane %u polarity %u, pos %u\n", i,
>  					buscfg->bus.csi2.lanecfg.data[i].pol,
> @@ -2137,57 +2135,13 @@ static int isp_fwnode_parse(struct device *dev, struct fwnode_handle *fwnode,
>  
>  	default:
>  		dev_warn(dev, "%pOF: invalid interface %u\n",
> -			 to_of_node(fwnode), vep.base.port);
> +			 to_of_node(vep->base.local_fwnode), vep->base.port);
>  		return -EINVAL;
>  	}
>  
>  	return 0;
>  }
>  
> -static int isp_fwnodes_parse(struct device *dev,
> -			     struct v4l2_async_notifier *notifier)
> -{
> -	struct fwnode_handle *fwnode = NULL;
> -
> -	notifier->subdevs = devm_kcalloc(
> -		dev, ISP_MAX_SUBDEVS, sizeof(*notifier->subdevs), GFP_KERNEL);
> -	if (!notifier->subdevs)
> -		return -ENOMEM;
> -
> -	while (notifier->num_subdevs < ISP_MAX_SUBDEVS &&
> -	       (fwnode = fwnode_graph_get_next_endpoint(
> -			of_fwnode_handle(dev->of_node), fwnode))) {
> -		struct isp_async_subdev *isd;
> -
> -		isd = devm_kzalloc(dev, sizeof(*isd), GFP_KERNEL);
> -		if (!isd)
> -			goto error;
> -
> -		if (isp_fwnode_parse(dev, fwnode, isd)) {
> -			devm_kfree(dev, isd);
> -			continue;
> -		}
> -
> -		notifier->subdevs[notifier->num_subdevs] = &isd->asd;
> -
> -		isd->asd.match.fwnode.fwnode =
> -			fwnode_graph_get_remote_port_parent(fwnode);
> -		if (!isd->asd.match.fwnode.fwnode) {
> -			dev_warn(dev, "bad remote port parent\n");
> -			goto error;
> -		}
> -
> -		isd->asd.match_type = V4L2_ASYNC_MATCH_FWNODE;
> -		notifier->num_subdevs++;
> -	}
> -
> -	return notifier->num_subdevs;
> -
> -error:
> -	fwnode_handle_put(fwnode);
> -	return -EINVAL;
> -}
> -
>  static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
>  {
>  	struct isp_device *isp = container_of(async, struct isp_device,
> @@ -2256,15 +2210,17 @@ static int isp_probe(struct platform_device *pdev)
>  	if (ret)
>  		return ret;
>  
> -	ret = isp_fwnodes_parse(&pdev->dev, &isp->notifier);
> -	if (ret < 0)
> -		return ret;
> -
>  	isp->autoidle = autoidle;
>  
>  	mutex_init(&isp->isp_mutex);
>  	spin_lock_init(&isp->stat_lock);
>  
> +	ret = v4l2_async_notifier_parse_fwnode_endpoints(
> +		&pdev->dev, &isp->notifier, sizeof(struct isp_async_subdev),
> +		isp_fwnode_parse);
> +	if (ret < 0)
> +		goto error;
> +
>  	isp->dev = &pdev->dev;
>  	isp->ref_count = 0;
>  
> @@ -2406,6 +2362,7 @@ static int isp_probe(struct platform_device *pdev)
>  	isp_xclk_cleanup(isp);
>  	__omap3isp_put(isp, false);
>  error:
> +	v4l2_async_notifier_cleanup(&isp->notifier);
>  	mutex_destroy(&isp->isp_mutex);
>  
>  	return ret;
> diff --git a/drivers/media/platform/omap3isp/isp.h b/drivers/media/platform/omap3isp/isp.h
> index e528df6efc09..8b9043db94b3 100644
> --- a/drivers/media/platform/omap3isp/isp.h
> +++ b/drivers/media/platform/omap3isp/isp.h
> @@ -220,14 +220,11 @@ struct isp_device {
>  
>  	unsigned int sbl_resources;
>  	unsigned int subclk_resources;
> -
> -#define ISP_MAX_SUBDEVS		8
> -	struct v4l2_subdev *subdevs[ISP_MAX_SUBDEVS];
>  };
>  
>  struct isp_async_subdev {
> -	struct isp_bus_cfg bus;
>  	struct v4l2_async_subdev asd;
> +	struct isp_bus_cfg bus;
>  };
>  
>  #define v4l2_subdev_to_bus_cfg(sd) \
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 11/32] omap3isp: Fix check for our own sub-devices
  2017-10-26  7:53 ` [PATCH v16 11/32] omap3isp: Fix check for our own sub-devices Sakari Ailus
@ 2017-10-27 14:47   ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:47 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 1195 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:21AM +0300, Sakari Ailus wrote:
> We only want to link sub-devices that were bound to the async notifier the
> isp driver registered but there may be other sub-devices in the
> v4l2_device as well. Check for the correct async notifier.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/platform/omap3isp/isp.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
> index 97a5206b6ddc..4afd7ba4fad6 100644
> --- a/drivers/media/platform/omap3isp/isp.c
> +++ b/drivers/media/platform/omap3isp/isp.c
> @@ -2155,7 +2155,7 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
>  		return ret;
>  
>  	list_for_each_entry(sd, &v4l2_dev->subdevs, list) {
> -		if (!sd->asd)
> +		if (sd->notifier != &isp->notifier)
>  			continue;
>  
>  		ret = isp_link_entity(isp, &sd->entity,
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 12/32] omap3isp: Print the name of the entity where no source pads could be found
  2017-10-26  7:53 ` [PATCH v16 12/32] omap3isp: Print the name of the entity where no source pads could be found Sakari Ailus
@ 2017-10-27 14:47   ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:47 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 1084 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:22AM +0300, Sakari Ailus wrote:
> If no source pads are found in an entity, print the name of the entity.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/platform/omap3isp/isp.c | 4 ++--
>  1 file changed, 2 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
> index 4afd7ba4fad6..35687c9707e0 100644
> --- a/drivers/media/platform/omap3isp/isp.c
> +++ b/drivers/media/platform/omap3isp/isp.c
> @@ -1669,8 +1669,8 @@ static int isp_link_entity(
>  			break;
>  	}
>  	if (i == entity->num_pads) {
> -		dev_err(isp->dev, "%s: no source pad in external entity\n",
> -			__func__);
> +		dev_err(isp->dev, "%s: no source pad in external entity %s\n",
> +			__func__, entity->name);
>  		return -EINVAL;
>  	}
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 13/32] v4l: async: Move async subdev notifier operations to a separate structure
  2017-10-26  7:53 ` [PATCH v16 13/32] v4l: async: Move async subdev notifier operations to a separate structure Sakari Ailus
  2017-10-26 21:44   ` Niklas Söderlund
@ 2017-10-27 14:47   ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:47 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 26207 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:23AM +0300, Sakari Ailus wrote:
> From: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> 
> The async subdev notifier .bound(), .unbind() and .complete() operations
> are function pointers stored directly in the v4l2_async_subdev
> structure. As the structure isn't immutable, this creates a potential
> security risk as the function pointers are mutable.
> 
> To fix this, move the function pointers to a new
> v4l2_async_subdev_operations structure that can be made const in
> drivers.
> 
> Signed-off-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/platform/am437x/am437x-vpfe.c    |  8 +++++--
>  drivers/media/platform/atmel/atmel-isc.c       | 10 ++++++---
>  drivers/media/platform/atmel/atmel-isi.c       | 10 ++++++---
>  drivers/media/platform/davinci/vpif_capture.c  |  8 +++++--
>  drivers/media/platform/davinci/vpif_display.c  |  8 +++++--
>  drivers/media/platform/exynos4-is/media-dev.c  |  8 +++++--
>  drivers/media/platform/omap3isp/isp.c          |  6 +++++-
>  drivers/media/platform/pxa_camera.c            |  8 +++++--
>  drivers/media/platform/qcom/camss-8x16/camss.c |  8 +++++--
>  drivers/media/platform/rcar-vin/rcar-core.c    | 10 ++++++---
>  drivers/media/platform/rcar_drif.c             | 10 ++++++---
>  drivers/media/platform/soc_camera/soc_camera.c | 14 ++++++------
>  drivers/media/platform/stm32/stm32-dcmi.c      | 10 ++++++---
>  drivers/media/platform/ti-vpe/cal.c            |  8 +++++--
>  drivers/media/platform/xilinx/xilinx-vipp.c    |  8 +++++--
>  drivers/media/v4l2-core/v4l2-async.c           | 30 ++++++++++++--------------
>  drivers/staging/media/imx/imx-media-dev.c      |  8 +++++--
>  include/media/v4l2-async.h                     | 29 ++++++++++++++++---------
>  18 files changed, 135 insertions(+), 66 deletions(-)
> 
> diff --git a/drivers/media/platform/am437x/am437x-vpfe.c b/drivers/media/platform/am437x/am437x-vpfe.c
> index dfcc484cab89..0997c640191d 100644
> --- a/drivers/media/platform/am437x/am437x-vpfe.c
> +++ b/drivers/media/platform/am437x/am437x-vpfe.c
> @@ -2417,6 +2417,11 @@ static int vpfe_async_complete(struct v4l2_async_notifier *notifier)
>  	return vpfe_probe_complete(vpfe);
>  }
>  
> +static const struct v4l2_async_notifier_operations vpfe_async_ops = {
> +	.bound = vpfe_async_bound,
> +	.complete = vpfe_async_complete,
> +};
> +
>  static struct vpfe_config *
>  vpfe_get_pdata(struct platform_device *pdev)
>  {
> @@ -2590,8 +2595,7 @@ static int vpfe_probe(struct platform_device *pdev)
>  
>  	vpfe->notifier.subdevs = vpfe->cfg->asd;
>  	vpfe->notifier.num_subdevs = ARRAY_SIZE(vpfe->cfg->asd);
> -	vpfe->notifier.bound = vpfe_async_bound;
> -	vpfe->notifier.complete = vpfe_async_complete;
> +	vpfe->notifier.ops = &vpfe_async_ops;
>  	ret = v4l2_async_notifier_register(&vpfe->v4l2_dev,
>  						&vpfe->notifier);
>  	if (ret) {
> diff --git a/drivers/media/platform/atmel/atmel-isc.c b/drivers/media/platform/atmel/atmel-isc.c
> index 2f8e345d297e..382fe355e616 100644
> --- a/drivers/media/platform/atmel/atmel-isc.c
> +++ b/drivers/media/platform/atmel/atmel-isc.c
> @@ -1637,6 +1637,12 @@ static int isc_async_complete(struct v4l2_async_notifier *notifier)
>  	return 0;
>  }
>  
> +static const struct v4l2_async_notifier_operations isc_async_ops = {
> +	.bound = isc_async_bound,
> +	.unbind = isc_async_unbind,
> +	.complete = isc_async_complete,
> +};
> +
>  static void isc_subdev_cleanup(struct isc_device *isc)
>  {
>  	struct isc_subdev_entity *subdev_entity;
> @@ -1849,9 +1855,7 @@ static int atmel_isc_probe(struct platform_device *pdev)
>  	list_for_each_entry(subdev_entity, &isc->subdev_entities, list) {
>  		subdev_entity->notifier.subdevs = &subdev_entity->asd;
>  		subdev_entity->notifier.num_subdevs = 1;
> -		subdev_entity->notifier.bound = isc_async_bound;
> -		subdev_entity->notifier.unbind = isc_async_unbind;
> -		subdev_entity->notifier.complete = isc_async_complete;
> +		subdev_entity->notifier.ops = &isc_async_ops;
>  
>  		ret = v4l2_async_notifier_register(&isc->v4l2_dev,
>  						   &subdev_entity->notifier);
> diff --git a/drivers/media/platform/atmel/atmel-isi.c b/drivers/media/platform/atmel/atmel-isi.c
> index 463c0146915e..e900995143a3 100644
> --- a/drivers/media/platform/atmel/atmel-isi.c
> +++ b/drivers/media/platform/atmel/atmel-isi.c
> @@ -1103,6 +1103,12 @@ static int isi_graph_notify_bound(struct v4l2_async_notifier *notifier,
>  	return 0;
>  }
>  
> +static const struct v4l2_async_notifier_operations isi_graph_notify_ops = {
> +	.bound = isi_graph_notify_bound,
> +	.unbind = isi_graph_notify_unbind,
> +	.complete = isi_graph_notify_complete,
> +};
> +
>  static int isi_graph_parse(struct atmel_isi *isi, struct device_node *node)
>  {
>  	struct device_node *ep = NULL;
> @@ -1150,9 +1156,7 @@ static int isi_graph_init(struct atmel_isi *isi)
>  
>  	isi->notifier.subdevs = subdevs;
>  	isi->notifier.num_subdevs = 1;
> -	isi->notifier.bound = isi_graph_notify_bound;
> -	isi->notifier.unbind = isi_graph_notify_unbind;
> -	isi->notifier.complete = isi_graph_notify_complete;
> +	isi->notifier.ops = &isi_graph_notify_ops;
>  
>  	ret = v4l2_async_notifier_register(&isi->v4l2_dev, &isi->notifier);
>  	if (ret < 0) {
> diff --git a/drivers/media/platform/davinci/vpif_capture.c b/drivers/media/platform/davinci/vpif_capture.c
> index 0ef36cec21d1..a89367ab1e06 100644
> --- a/drivers/media/platform/davinci/vpif_capture.c
> +++ b/drivers/media/platform/davinci/vpif_capture.c
> @@ -1500,6 +1500,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)
>  	return vpif_probe_complete();
>  }
>  
> +static const struct v4l2_async_notifier_operations vpif_async_ops = {
> +	.bound = vpif_async_bound,
> +	.complete = vpif_async_complete,
> +};
> +
>  static struct vpif_capture_config *
>  vpif_capture_get_pdata(struct platform_device *pdev)
>  {
> @@ -1691,8 +1696,7 @@ static __init int vpif_probe(struct platform_device *pdev)
>  	} else {
>  		vpif_obj.notifier.subdevs = vpif_obj.config->asd;
>  		vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
> -		vpif_obj.notifier.bound = vpif_async_bound;
> -		vpif_obj.notifier.complete = vpif_async_complete;
> +		vpif_obj.notifier.ops = &vpif_async_ops;
>  		err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
>  						   &vpif_obj.notifier);
>  		if (err) {
> diff --git a/drivers/media/platform/davinci/vpif_display.c b/drivers/media/platform/davinci/vpif_display.c
> index 56fe4e5b396e..ff2f75a328c9 100644
> --- a/drivers/media/platform/davinci/vpif_display.c
> +++ b/drivers/media/platform/davinci/vpif_display.c
> @@ -1232,6 +1232,11 @@ static int vpif_async_complete(struct v4l2_async_notifier *notifier)
>  	return vpif_probe_complete();
>  }
>  
> +static const struct v4l2_async_notifier_operations vpif_async_ops = {
> +	.bound = vpif_async_bound,
> +	.complete = vpif_async_complete,
> +};
> +
>  /*
>   * vpif_probe: This function creates device entries by register itself to the
>   * V4L2 driver and initializes fields of each channel objects
> @@ -1313,8 +1318,7 @@ static __init int vpif_probe(struct platform_device *pdev)
>  	} else {
>  		vpif_obj.notifier.subdevs = vpif_obj.config->asd;
>  		vpif_obj.notifier.num_subdevs = vpif_obj.config->asd_sizes[0];
> -		vpif_obj.notifier.bound = vpif_async_bound;
> -		vpif_obj.notifier.complete = vpif_async_complete;
> +		vpif_obj.notifier.ops = &vpif_async_ops;
>  		err = v4l2_async_notifier_register(&vpif_obj.v4l2_dev,
>  						   &vpif_obj.notifier);
>  		if (err) {
> diff --git a/drivers/media/platform/exynos4-is/media-dev.c b/drivers/media/platform/exynos4-is/media-dev.c
> index d4656d5175d7..c15596b56dc9 100644
> --- a/drivers/media/platform/exynos4-is/media-dev.c
> +++ b/drivers/media/platform/exynos4-is/media-dev.c
> @@ -1405,6 +1405,11 @@ static int subdev_notifier_complete(struct v4l2_async_notifier *notifier)
>  	return media_device_register(&fmd->media_dev);
>  }
>  
> +static const struct v4l2_async_notifier_operations subdev_notifier_ops = {
> +	.bound = subdev_notifier_bound,
> +	.complete = subdev_notifier_complete,
> +};
> +
>  static int fimc_md_probe(struct platform_device *pdev)
>  {
>  	struct device *dev = &pdev->dev;
> @@ -1479,8 +1484,7 @@ static int fimc_md_probe(struct platform_device *pdev)
>  	if (fmd->num_sensors > 0) {
>  		fmd->subdev_notifier.subdevs = fmd->async_subdevs;
>  		fmd->subdev_notifier.num_subdevs = fmd->num_sensors;
> -		fmd->subdev_notifier.bound = subdev_notifier_bound;
> -		fmd->subdev_notifier.complete = subdev_notifier_complete;
> +		fmd->subdev_notifier.ops = &subdev_notifier_ops;
>  		fmd->num_sensors = 0;
>  
>  		ret = v4l2_async_notifier_register(&fmd->v4l2_dev,
> diff --git a/drivers/media/platform/omap3isp/isp.c b/drivers/media/platform/omap3isp/isp.c
> index 35687c9707e0..b7ff3842afc0 100644
> --- a/drivers/media/platform/omap3isp/isp.c
> +++ b/drivers/media/platform/omap3isp/isp.c
> @@ -2171,6 +2171,10 @@ static int isp_subdev_notifier_complete(struct v4l2_async_notifier *async)
>  	return media_device_register(&isp->media_dev);
>  }
>  
> +static const struct v4l2_async_notifier_operations isp_subdev_notifier_ops = {
> +	.complete = isp_subdev_notifier_complete,
> +};
> +
>  /*
>   * isp_probe - Probe ISP platform device
>   * @pdev: Pointer to ISP platform device
> @@ -2341,7 +2345,7 @@ static int isp_probe(struct platform_device *pdev)
>  	if (ret < 0)
>  		goto error_register_entities;
>  
> -	isp->notifier.complete = isp_subdev_notifier_complete;
> +	isp->notifier.ops = &isp_subdev_notifier_ops;
>  
>  	ret = v4l2_async_notifier_register(&isp->v4l2_dev, &isp->notifier);
>  	if (ret)
> diff --git a/drivers/media/platform/pxa_camera.c b/drivers/media/platform/pxa_camera.c
> index edca993c2b1f..9d3f0cb1d95a 100644
> --- a/drivers/media/platform/pxa_camera.c
> +++ b/drivers/media/platform/pxa_camera.c
> @@ -2221,6 +2221,11 @@ static void pxa_camera_sensor_unbind(struct v4l2_async_notifier *notifier,
>  	mutex_unlock(&pcdev->mlock);
>  }
>  
> +static const struct v4l2_async_notifier_operations pxa_camera_sensor_ops = {
> +	.bound = pxa_camera_sensor_bound,
> +	.unbind = pxa_camera_sensor_unbind,
> +};
> +
>  /*
>   * Driver probe, remove, suspend and resume operations
>   */
> @@ -2489,8 +2494,7 @@ static int pxa_camera_probe(struct platform_device *pdev)
>  	pcdev->asds[0] = &pcdev->asd;
>  	pcdev->notifier.subdevs = pcdev->asds;
>  	pcdev->notifier.num_subdevs = 1;
> -	pcdev->notifier.bound = pxa_camera_sensor_bound;
> -	pcdev->notifier.unbind = pxa_camera_sensor_unbind;
> +	pcdev->notifier.ops = &pxa_camera_sensor_ops;
>  
>  	if (!of_have_populated_dt())
>  		pcdev->asd.match_type = V4L2_ASYNC_MATCH_I2C;
> diff --git a/drivers/media/platform/qcom/camss-8x16/camss.c b/drivers/media/platform/qcom/camss-8x16/camss.c
> index a3760b5dd1d1..390a42c17b66 100644
> --- a/drivers/media/platform/qcom/camss-8x16/camss.c
> +++ b/drivers/media/platform/qcom/camss-8x16/camss.c
> @@ -601,6 +601,11 @@ static int camss_subdev_notifier_complete(struct v4l2_async_notifier *async)
>  	return media_device_register(&camss->media_dev);
>  }
>  
> +static const struct v4l2_async_notifier_operations camss_subdev_notifier_ops = {
> +	.bound = camss_subdev_notifier_bound,
> +	.complete = camss_subdev_notifier_complete,
> +};
> +
>  static const struct media_device_ops camss_media_ops = {
>  	.link_notify = v4l2_pipeline_link_notify,
>  };
> @@ -655,8 +660,7 @@ static int camss_probe(struct platform_device *pdev)
>  		goto err_register_entities;
>  
>  	if (camss->notifier.num_subdevs) {
> -		camss->notifier.bound = camss_subdev_notifier_bound;
> -		camss->notifier.complete = camss_subdev_notifier_complete;
> +		camss->notifier.ops = &camss_subdev_notifier_ops;
>  
>  		ret = v4l2_async_notifier_register(&camss->v4l2_dev,
>  						   &camss->notifier);
> diff --git a/drivers/media/platform/rcar-vin/rcar-core.c b/drivers/media/platform/rcar-vin/rcar-core.c
> index 380288658601..108d776f3265 100644
> --- a/drivers/media/platform/rcar-vin/rcar-core.c
> +++ b/drivers/media/platform/rcar-vin/rcar-core.c
> @@ -134,6 +134,12 @@ static int rvin_digital_notify_bound(struct v4l2_async_notifier *notifier,
>  
>  	return 0;
>  }
> +static const struct v4l2_async_notifier_operations rvin_digital_notify_ops = {
> +	.bound = rvin_digital_notify_bound,
> +	.unbind = rvin_digital_notify_unbind,
> +	.complete = rvin_digital_notify_complete,
> +};
> +
>  
>  static int rvin_digital_parse_v4l2(struct device *dev,
>  				   struct v4l2_fwnode_endpoint *vep,
> @@ -183,9 +189,7 @@ static int rvin_digital_graph_init(struct rvin_dev *vin)
>  	vin_dbg(vin, "Found digital subdevice %pOF\n",
>  		to_of_node(vin->digital->asd.match.fwnode.fwnode));
>  
> -	vin->notifier.bound = rvin_digital_notify_bound;
> -	vin->notifier.unbind = rvin_digital_notify_unbind;
> -	vin->notifier.complete = rvin_digital_notify_complete;
> +	vin->notifier.ops = &rvin_digital_notify_ops;
>  	ret = v4l2_async_notifier_register(&vin->v4l2_dev, &vin->notifier);
>  	if (ret < 0) {
>  		vin_err(vin, "Notifier registration failed\n");
> diff --git a/drivers/media/platform/rcar_drif.c b/drivers/media/platform/rcar_drif.c
> index 2c6afd38b78a..63c94f4028a7 100644
> --- a/drivers/media/platform/rcar_drif.c
> +++ b/drivers/media/platform/rcar_drif.c
> @@ -1185,6 +1185,12 @@ static int rcar_drif_notify_complete(struct v4l2_async_notifier *notifier)
>  	return ret;
>  }
>  
> +static const struct v4l2_async_notifier_operations rcar_drif_notify_ops = {
> +	.bound = rcar_drif_notify_bound,
> +	.unbind = rcar_drif_notify_unbind,
> +	.complete = rcar_drif_notify_complete,
> +};
> +
>  /* Read endpoint properties */
>  static void rcar_drif_get_ep_properties(struct rcar_drif_sdr *sdr,
>  					struct fwnode_handle *fwnode)
> @@ -1347,9 +1353,7 @@ static int rcar_drif_sdr_probe(struct rcar_drif_sdr *sdr)
>  	if (ret)
>  		goto error;
>  
> -	sdr->notifier.bound = rcar_drif_notify_bound;
> -	sdr->notifier.unbind = rcar_drif_notify_unbind;
> -	sdr->notifier.complete = rcar_drif_notify_complete;
> +	sdr->notifier.ops = &rcar_drif_notify_ops;
>  
>  	/* Register notifier */
>  	ret = v4l2_async_notifier_register(&sdr->v4l2_dev, &sdr->notifier);
> diff --git a/drivers/media/platform/soc_camera/soc_camera.c b/drivers/media/platform/soc_camera/soc_camera.c
> index 1f3c450c7a69..916ff68b73d4 100644
> --- a/drivers/media/platform/soc_camera/soc_camera.c
> +++ b/drivers/media/platform/soc_camera/soc_camera.c
> @@ -1391,6 +1391,12 @@ static int soc_camera_async_complete(struct v4l2_async_notifier *notifier)
>  	return 0;
>  }
>  
> +static const struct v4l2_async_notifier_operations soc_camera_async_ops = {
> +	.bound = soc_camera_async_bound,
> +	.unbind = soc_camera_async_unbind,
> +	.complete = soc_camera_async_complete,
> +};
> +
>  static int scan_async_group(struct soc_camera_host *ici,
>  			    struct v4l2_async_subdev **asd, unsigned int size)
>  {
> @@ -1437,9 +1443,7 @@ static int scan_async_group(struct soc_camera_host *ici,
>  
>  	sasc->notifier.subdevs = asd;
>  	sasc->notifier.num_subdevs = size;
> -	sasc->notifier.bound = soc_camera_async_bound;
> -	sasc->notifier.unbind = soc_camera_async_unbind;
> -	sasc->notifier.complete = soc_camera_async_complete;
> +	sasc->notifier.ops = &soc_camera_async_ops;
>  
>  	icd->sasc = sasc;
>  	icd->parent = ici->v4l2_dev.dev;
> @@ -1537,9 +1541,7 @@ static int soc_of_bind(struct soc_camera_host *ici,
>  
>  	sasc->notifier.subdevs = &info->subdev;
>  	sasc->notifier.num_subdevs = 1;
> -	sasc->notifier.bound = soc_camera_async_bound;
> -	sasc->notifier.unbind = soc_camera_async_unbind;
> -	sasc->notifier.complete = soc_camera_async_complete;
> +	sasc->notifier.ops = &soc_camera_async_ops;
>  
>  	icd->sasc = sasc;
>  	icd->parent = ici->v4l2_dev.dev;
> diff --git a/drivers/media/platform/stm32/stm32-dcmi.c b/drivers/media/platform/stm32/stm32-dcmi.c
> index 35ba6f211b79..ac4c450a6c7d 100644
> --- a/drivers/media/platform/stm32/stm32-dcmi.c
> +++ b/drivers/media/platform/stm32/stm32-dcmi.c
> @@ -1495,6 +1495,12 @@ static int dcmi_graph_notify_bound(struct v4l2_async_notifier *notifier,
>  	return 0;
>  }
>  
> +static const struct v4l2_async_notifier_operations dcmi_graph_notify_ops = {
> +	.bound = dcmi_graph_notify_bound,
> +	.unbind = dcmi_graph_notify_unbind,
> +	.complete = dcmi_graph_notify_complete,
> +};
> +
>  static int dcmi_graph_parse(struct stm32_dcmi *dcmi, struct device_node *node)
>  {
>  	struct device_node *ep = NULL;
> @@ -1542,9 +1548,7 @@ static int dcmi_graph_init(struct stm32_dcmi *dcmi)
>  
>  	dcmi->notifier.subdevs = subdevs;
>  	dcmi->notifier.num_subdevs = 1;
> -	dcmi->notifier.bound = dcmi_graph_notify_bound;
> -	dcmi->notifier.unbind = dcmi_graph_notify_unbind;
> -	dcmi->notifier.complete = dcmi_graph_notify_complete;
> +	dcmi->notifier.ops = &dcmi_graph_notify_ops;
>  
>  	ret = v4l2_async_notifier_register(&dcmi->v4l2_dev, &dcmi->notifier);
>  	if (ret < 0) {
> diff --git a/drivers/media/platform/ti-vpe/cal.c b/drivers/media/platform/ti-vpe/cal.c
> index 42e383a48ffe..8b586c864524 100644
> --- a/drivers/media/platform/ti-vpe/cal.c
> +++ b/drivers/media/platform/ti-vpe/cal.c
> @@ -1522,6 +1522,11 @@ static int cal_async_complete(struct v4l2_async_notifier *notifier)
>  	return 0;
>  }
>  
> +static const struct v4l2_async_notifier_operations cal_async_ops = {
> +	.bound = cal_async_bound,
> +	.complete = cal_async_complete,
> +};
> +
>  static int cal_complete_ctx(struct cal_ctx *ctx)
>  {
>  	struct video_device *vfd;
> @@ -1736,8 +1741,7 @@ static int of_cal_create_instance(struct cal_ctx *ctx, int inst)
>  	ctx->asd_list[0] = asd;
>  	ctx->notifier.subdevs = ctx->asd_list;
>  	ctx->notifier.num_subdevs = 1;
> -	ctx->notifier.bound = cal_async_bound;
> -	ctx->notifier.complete = cal_async_complete;
> +	ctx->notifier.ops = &cal_async_ops;
>  	ret = v4l2_async_notifier_register(&ctx->v4l2_dev,
>  					   &ctx->notifier);
>  	if (ret) {
> diff --git a/drivers/media/platform/xilinx/xilinx-vipp.c b/drivers/media/platform/xilinx/xilinx-vipp.c
> index ebfdf334d99c..d881cf09876d 100644
> --- a/drivers/media/platform/xilinx/xilinx-vipp.c
> +++ b/drivers/media/platform/xilinx/xilinx-vipp.c
> @@ -351,6 +351,11 @@ static int xvip_graph_notify_bound(struct v4l2_async_notifier *notifier,
>  	return -EINVAL;
>  }
>  
> +static const struct v4l2_async_notifier_operations xvip_graph_notify_ops = {
> +	.bound = xvip_graph_notify_bound,
> +	.complete = xvip_graph_notify_complete,
> +};
> +
>  static int xvip_graph_parse_one(struct xvip_composite_device *xdev,
>  				struct device_node *node)
>  {
> @@ -548,8 +553,7 @@ static int xvip_graph_init(struct xvip_composite_device *xdev)
>  
>  	xdev->notifier.subdevs = subdevs;
>  	xdev->notifier.num_subdevs = num_subdevs;
> -	xdev->notifier.bound = xvip_graph_notify_bound;
> -	xdev->notifier.complete = xvip_graph_notify_complete;
> +	xdev->notifier.ops = &xvip_graph_notify_ops;
>  
>  	ret = v4l2_async_notifier_register(&xdev->v4l2_dev, &xdev->notifier);
>  	if (ret < 0) {
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 46aebfc75e43..9d6fc5f25619 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -102,16 +102,16 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  {
>  	int ret;
>  
> -	if (notifier->bound) {
> -		ret = notifier->bound(notifier, sd, asd);
> +	if (notifier->ops->bound) {
> +		ret = notifier->ops->bound(notifier, sd, asd);
>  		if (ret < 0)
>  			return ret;
>  	}
>  
>  	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
>  	if (ret < 0) {
> -		if (notifier->unbind)
> -			notifier->unbind(notifier, sd, asd);
> +		if (notifier->ops->unbind)
> +			notifier->ops->unbind(notifier, sd, asd);
>  		return ret;
>  	}
>  
> @@ -140,9 +140,8 @@ static void v4l2_async_notifier_unbind_all_subdevs(
>  	struct v4l2_subdev *sd, *tmp;
>  
>  	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> -		if (notifier->unbind)
> -			notifier->unbind(notifier, sd, sd->asd);
> -
> +		if (notifier->ops->unbind)
> +			notifier->ops->unbind(notifier, sd, sd->asd);
>  		v4l2_async_cleanup(sd);
>  
>  		list_move(&sd->async_list, &subdev_list);
> @@ -199,8 +198,8 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  		}
>  	}
>  
> -	if (list_empty(&notifier->waiting) && notifier->complete) {
> -		ret = notifier->complete(notifier);
> +	if (list_empty(&notifier->waiting) && notifier->ops->complete) {
> +		ret = notifier->ops->complete(notifier);
>  		if (ret)
>  			goto err_complete;
>  	}
> @@ -297,10 +296,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  		if (ret)
>  			goto err_unlock;
>  
> -		if (!list_empty(&notifier->waiting) || !notifier->complete)
> +		if (!list_empty(&notifier->waiting) || !notifier->ops->complete)
>  			goto out_unlock;
>  
> -		ret = notifier->complete(notifier);
> +		ret = notifier->ops->complete(notifier);
>  		if (ret)
>  			goto err_cleanup;
>  
> @@ -316,9 +315,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	return 0;
>  
>  err_cleanup:
> -	if (notifier->unbind)
> -		notifier->unbind(notifier, sd, sd->asd);
> -
> +	if (notifier->ops->unbind)
> +		notifier->ops->unbind(notifier, sd, sd->asd);
>  	v4l2_async_cleanup(sd);
>  
>  err_unlock:
> @@ -337,8 +335,8 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  
>  		list_add(&sd->asd->list, &notifier->waiting);
>  
> -		if (notifier->unbind)
> -			notifier->unbind(notifier, sd, sd->asd);
> +		if (notifier->ops->unbind)
> +			notifier->ops->unbind(notifier, sd, sd->asd);
>  	}
>  
>  	v4l2_async_cleanup(sd);
> diff --git a/drivers/staging/media/imx/imx-media-dev.c b/drivers/staging/media/imx/imx-media-dev.c
> index b55e5ebba8b4..47c4c954fed5 100644
> --- a/drivers/staging/media/imx/imx-media-dev.c
> +++ b/drivers/staging/media/imx/imx-media-dev.c
> @@ -440,6 +440,11 @@ static int imx_media_probe_complete(struct v4l2_async_notifier *notifier)
>  	return media_device_register(&imxmd->md);
>  }
>  
> +static const struct v4l2_async_notifier_operations imx_media_subdev_ops = {
> +	.bound = imx_media_subdev_bound,
> +	.complete = imx_media_probe_complete,
> +};
> +
>  /*
>   * adds controls to a video device from an entity subdevice.
>   * Continues upstream from the entity's sink pads.
> @@ -608,8 +613,7 @@ static int imx_media_probe(struct platform_device *pdev)
>  
>  	/* prepare the async subdev notifier and register it */
>  	imxmd->subdev_notifier.subdevs = imxmd->async_ptrs;
> -	imxmd->subdev_notifier.bound = imx_media_subdev_bound;
> -	imxmd->subdev_notifier.complete = imx_media_probe_complete;
> +	imxmd->subdev_notifier.ops = &imx_media_subdev_ops;
>  	ret = v4l2_async_notifier_register(&imxmd->v4l2_dev,
>  					   &imxmd->subdev_notifier);
>  	if (ret) {
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 329aeebd1a80..68606afb5ef9 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -18,6 +18,7 @@ struct device;
>  struct device_node;
>  struct v4l2_device;
>  struct v4l2_subdev;
> +struct v4l2_async_notifier;
>  
>  /* A random max subdevice number, used to allocate an array on stack */
>  #define V4L2_MAX_SUBDEVS 128U
> @@ -79,8 +80,25 @@ struct v4l2_async_subdev {
>  };
>  
>  /**
> + * struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations
> + * @bound:	a subdevice driver has successfully probed one of the subdevices
> + * @complete:	all subdevices have been probed successfully
> + * @unbind:	a subdevice is leaving
> + */
> +struct v4l2_async_notifier_operations {
> +	int (*bound)(struct v4l2_async_notifier *notifier,
> +		     struct v4l2_subdev *subdev,
> +		     struct v4l2_async_subdev *asd);
> +	int (*complete)(struct v4l2_async_notifier *notifier);
> +	void (*unbind)(struct v4l2_async_notifier *notifier,
> +		       struct v4l2_subdev *subdev,
> +		       struct v4l2_async_subdev *asd);
> +};
> +
> +/**
>   * struct v4l2_async_notifier - v4l2_device notifier data
>   *
> + * @ops:	notifier operations
>   * @num_subdevs: number of subdevices used in the subdevs array
>   * @max_subdevs: number of subdevices allocated in the subdevs array
>   * @subdevs:	array of pointers to subdevice descriptors
> @@ -88,11 +106,9 @@ struct v4l2_async_subdev {
>   * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
>   * @done:	list of struct v4l2_subdev, already probed
>   * @list:	member in a global list of notifiers
> - * @bound:	a subdevice driver has successfully probed one of subdevices
> - * @complete:	all subdevices have been probed successfully
> - * @unbind:	a subdevice is leaving
>   */
>  struct v4l2_async_notifier {
> +	const struct v4l2_async_notifier_operations *ops;
>  	unsigned int num_subdevs;
>  	unsigned int max_subdevs;
>  	struct v4l2_async_subdev **subdevs;
> @@ -100,13 +116,6 @@ struct v4l2_async_notifier {
>  	struct list_head waiting;
>  	struct list_head done;
>  	struct list_head list;
> -	int (*bound)(struct v4l2_async_notifier *notifier,
> -		     struct v4l2_subdev *subdev,
> -		     struct v4l2_async_subdev *asd);
> -	int (*complete)(struct v4l2_async_notifier *notifier);
> -	void (*unbind)(struct v4l2_async_notifier *notifier,
> -		       struct v4l2_subdev *subdev,
> -		       struct v4l2_async_subdev *asd);
>  };
>  
>  /**
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 14/32] v4l: async: Introduce helpers for calling async ops callbacks
  2017-10-26  7:53 ` [PATCH v16 14/32] v4l: async: Introduce helpers for calling async ops callbacks Sakari Ailus
  2017-10-26 21:46   ` Niklas Söderlund
@ 2017-10-27 14:48   ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:48 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 4299 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:24AM +0300, Sakari Ailus wrote:
> Add three helper functions to call async operations callbacks. Besides
> simplifying callbacks, this allows async notifiers to have no ops set,
> i.e. it can be left NULL.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/v4l2-core/v4l2-async.c | 56 +++++++++++++++++++++++++-----------
>  1 file changed, 39 insertions(+), 17 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 9d6fc5f25619..e170682dae78 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -25,6 +25,34 @@
>  #include <media/v4l2-fwnode.h>
>  #include <media/v4l2-subdev.h>
>  
> +static int v4l2_async_notifier_call_bound(struct v4l2_async_notifier *n,
> +					  struct v4l2_subdev *subdev,
> +					  struct v4l2_async_subdev *asd)
> +{
> +	if (!n->ops || !n->ops->bound)
> +		return 0;
> +
> +	return n->ops->bound(n, subdev, asd);
> +}
> +
> +static void v4l2_async_notifier_call_unbind(struct v4l2_async_notifier *n,
> +					    struct v4l2_subdev *subdev,
> +					    struct v4l2_async_subdev *asd)
> +{
> +	if (!n->ops || !n->ops->unbind)
> +		return;
> +
> +	n->ops->unbind(n, subdev, asd);
> +}
> +
> +static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
> +{
> +	if (!n->ops || !n->ops->complete)
> +		return 0;
> +
> +	return n->ops->complete(n);
> +}
> +
>  static bool match_i2c(struct v4l2_subdev *sd, struct v4l2_async_subdev *asd)
>  {
>  #if IS_ENABLED(CONFIG_I2C)
> @@ -102,16 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  {
>  	int ret;
>  
> -	if (notifier->ops->bound) {
> -		ret = notifier->ops->bound(notifier, sd, asd);
> -		if (ret < 0)
> -			return ret;
> -	}
> +	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
> +	if (ret < 0)
> +		return ret;
>  
>  	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
>  	if (ret < 0) {
> -		if (notifier->ops->unbind)
> -			notifier->ops->unbind(notifier, sd, asd);
> +		v4l2_async_notifier_call_unbind(notifier, sd, asd);
>  		return ret;
>  	}
>  
> @@ -140,8 +165,7 @@ static void v4l2_async_notifier_unbind_all_subdevs(
>  	struct v4l2_subdev *sd, *tmp;
>  
>  	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> -		if (notifier->ops->unbind)
> -			notifier->ops->unbind(notifier, sd, sd->asd);
> +		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>  		v4l2_async_cleanup(sd);
>  
>  		list_move(&sd->async_list, &subdev_list);
> @@ -198,8 +222,8 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  		}
>  	}
>  
> -	if (list_empty(&notifier->waiting) && notifier->ops->complete) {
> -		ret = notifier->ops->complete(notifier);
> +	if (list_empty(&notifier->waiting)) {
> +		ret = v4l2_async_notifier_call_complete(notifier);
>  		if (ret)
>  			goto err_complete;
>  	}
> @@ -296,10 +320,10 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  		if (ret)
>  			goto err_unlock;
>  
> -		if (!list_empty(&notifier->waiting) || !notifier->ops->complete)
> +		if (!list_empty(&notifier->waiting))
>  			goto out_unlock;
>  
> -		ret = notifier->ops->complete(notifier);
> +		ret = v4l2_async_notifier_call_complete(notifier);
>  		if (ret)
>  			goto err_cleanup;
>  
> @@ -315,8 +339,7 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	return 0;
>  
>  err_cleanup:
> -	if (notifier->ops->unbind)
> -		notifier->ops->unbind(notifier, sd, sd->asd);
> +	v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>  	v4l2_async_cleanup(sd);
>  
>  err_unlock:
> @@ -335,8 +358,7 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  
>  		list_add(&sd->asd->list, &notifier->waiting);
>  
> -		if (notifier->ops->unbind)
> -			notifier->ops->unbind(notifier, sd, sd->asd);
> +		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>  	}
>  
>  	v4l2_async_cleanup(sd);
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 15/32] v4l: async: Register sub-devices before calling bound callback
  2017-10-26  7:53 ` [PATCH v16 15/32] v4l: async: Register sub-devices before calling bound callback Sakari Ailus
       [not found]   ` <20171026075342.5760-16-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
@ 2017-10-27 14:49   ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:49 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 1482 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:25AM +0300, Sakari Ailus wrote:
> Register the sub-device before calling the notifier's bound callback.
> Doing this the other way around is problematic as the struct v4l2_device
> has not assigned for the sub-device yet and may be required by the bound
> callback.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/v4l2-core/v4l2-async.c | 6 +++---
>  1 file changed, 3 insertions(+), 3 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index e170682dae78..46db85685894 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -130,13 +130,13 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  {
>  	int ret;
>  
> -	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
> +	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
>  	if (ret < 0)
>  		return ret;
>  
> -	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> +	ret = v4l2_async_notifier_call_bound(notifier, sd, asd);
>  	if (ret < 0) {
> -		v4l2_async_notifier_call_unbind(notifier, sd, asd);
> +		v4l2_device_unregister_subdev(sd);
>  		return ret;
>  	}
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 16/32] v4l: async: Allow async notifier register call succeed with no subdevs
  2017-10-26  7:53 ` [PATCH v16 16/32] v4l: async: Allow async notifier register call succeed with no subdevs Sakari Ailus
@ 2017-10-27 14:49       ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:49 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 2055 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:26AM +0300, Sakari Ailus wrote:
> The information on how many async sub-devices would be bindable to a
> notifier is typically dependent on information from platform firmware and
> it's not driver's business to be aware of that.
> 
> Many V4L2 main drivers are perfectly usable (and useful) without async
> sub-devices and so if there aren't any around, just proceed call the
> notifier's complete callback immediately without registering the notifier
> itself.
> 
> If a driver needs to check whether there are async sub-devices available,
> it can be done by inspecting the notifier's num_subdevs field which tells
> the number of async sub-devices.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>

-- Sebastian

>  drivers/media/v4l2-core/v4l2-async.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 46db85685894..1b536d68cedf 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -180,14 +180,22 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  	int ret;
>  	int i;
>  
> -	if (!v4l2_dev || !notifier->num_subdevs ||
> -	    notifier->num_subdevs > V4L2_MAX_SUBDEVS)
> +	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
>  		return -EINVAL;
>  
>  	notifier->v4l2_dev = v4l2_dev;
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> +	if (!notifier->num_subdevs) {
> +		int ret;
> +
> +		ret = v4l2_async_notifier_call_complete(notifier);
> +		notifier->v4l2_dev = NULL;
> +
> +		return ret;
> +	}
> +
>  	for (i = 0; i < notifier->num_subdevs; i++) {
>  		asd = notifier->subdevs[i];
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 16/32] v4l: async: Allow async notifier register call succeed with no subdevs
@ 2017-10-27 14:49       ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:49 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 1977 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:26AM +0300, Sakari Ailus wrote:
> The information on how many async sub-devices would be bindable to a
> notifier is typically dependent on information from platform firmware and
> it's not driver's business to be aware of that.
> 
> Many V4L2 main drivers are perfectly usable (and useful) without async
> sub-devices and so if there aren't any around, just proceed call the
> notifier's complete callback immediately without registering the notifier
> itself.
> 
> If a driver needs to check whether there are async sub-devices available,
> it can be done by inspecting the notifier's num_subdevs field which tells
> the number of async sub-devices.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/v4l2-core/v4l2-async.c | 12 ++++++++++--
>  1 file changed, 10 insertions(+), 2 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 46db85685894..1b536d68cedf 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -180,14 +180,22 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  	int ret;
>  	int i;
>  
> -	if (!v4l2_dev || !notifier->num_subdevs ||
> -	    notifier->num_subdevs > V4L2_MAX_SUBDEVS)
> +	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
>  		return -EINVAL;
>  
>  	notifier->v4l2_dev = v4l2_dev;
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> +	if (!notifier->num_subdevs) {
> +		int ret;
> +
> +		ret = v4l2_async_notifier_call_complete(notifier);
> +		notifier->v4l2_dev = NULL;
> +
> +		return ret;
> +	}
> +
>  	for (i = 0; i < notifier->num_subdevs; i++) {
>  		asd = notifier->subdevs[i];
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16.1 17/32] v4l: async: Prepare for async sub-device notifiers
  2017-10-27  8:26   ` [PATCH v16.1 " Sakari Ailus
  2017-10-27  8:36     ` Niklas Söderlund
@ 2017-10-27 14:50     ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-27 14:50 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel

[-- Attachment #1: Type: text/plain, Size: 4425 bytes --]

Hi,

On Fri, Oct 27, 2017 at 11:26:29AM +0300, Sakari Ailus wrote:
> Refactor the V4L2 async framework a little in preparation for async
> sub-device notifiers. This avoids making some structural changes in the
> patch actually implementing sub-device notifiers, making that patch easier
> to review.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/v4l2-core/v4l2-async.c | 69 ++++++++++++++++++++++++++----------
>  1 file changed, 50 insertions(+), 19 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 1b536d68cedf..6265717769d2 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -125,12 +125,13 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
>  }
>  
>  static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
> +				   struct v4l2_device *v4l2_dev,
>  				   struct v4l2_subdev *sd,
>  				   struct v4l2_async_subdev *asd)
>  {
>  	int ret;
>  
> -	ret = v4l2_device_register_subdev(notifier->v4l2_dev, sd);
> +	ret = v4l2_device_register_subdev(v4l2_dev, sd);
>  	if (ret < 0)
>  		return ret;
>  
> @@ -151,6 +152,29 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  	return 0;
>  }
>  
> +/* Test all async sub-devices in a notifier for a match. */
> +static int v4l2_async_notifier_try_all_subdevs(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
> +	struct v4l2_subdev *sd, *tmp;
> +
> +	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> +		struct v4l2_async_subdev *asd;
> +		int ret;
> +
> +		asd = v4l2_async_find_match(notifier, sd);
> +		if (!asd)
> +			continue;
> +
> +		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
> +		if (ret < 0)
> +			return ret;
> +	}
> +
> +	return 0;
> +}
> +
>  static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  {
>  	v4l2_device_unregister_subdev(sd);
> @@ -172,18 +196,15 @@ static void v4l2_async_notifier_unbind_all_subdevs(
>  	}
>  }
>  
> -int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> -				 struct v4l2_async_notifier *notifier)
> +static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  {
> -	struct v4l2_subdev *sd, *tmp;
>  	struct v4l2_async_subdev *asd;
>  	int ret;
>  	int i;
>  
> -	if (!v4l2_dev || notifier->num_subdevs > V4L2_MAX_SUBDEVS)
> +	if (notifier->num_subdevs > V4L2_MAX_SUBDEVS)
>  		return -EINVAL;
>  
> -	notifier->v4l2_dev = v4l2_dev;
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> @@ -216,18 +237,10 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  
>  	mutex_lock(&list_lock);
>  
> -	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> -		int ret;
> -
> -		asd = v4l2_async_find_match(notifier, sd);
> -		if (!asd)
> -			continue;
> -
> -		ret = v4l2_async_match_notify(notifier, sd, asd);
> -		if (ret < 0) {
> -			mutex_unlock(&list_lock);
> -			return ret;
> -		}
> +	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> +	if (ret) {
> +		mutex_unlock(&list_lock);
> +		return ret;
>  	}
>  
>  	if (list_empty(&notifier->waiting)) {
> @@ -250,6 +263,23 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  
>  	return ret;
>  }
> +
> +int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
> +				 struct v4l2_async_notifier *notifier)
> +{
> +	int ret;
> +
> +	if (WARN_ON(!v4l2_dev))
> +		return -EINVAL;
> +
> +	notifier->v4l2_dev = v4l2_dev;
> +
> +	ret = __v4l2_async_notifier_register(notifier);
> +	if (ret)
> +		notifier->v4l2_dev = NULL;
> +
> +	return ret;
> +}
>  EXPORT_SYMBOL(v4l2_async_notifier_register);
>  
>  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> @@ -324,7 +354,8 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  		if (!asd)
>  			continue;
>  
> -		ret = v4l2_async_match_notify(notifier, sd, asd);
> +		ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd,
> +					      asd);
>  		if (ret)
>  			goto err_unlock;
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16.1 18/32] v4l: async: Allow binding notifiers to sub-devices
  2017-10-27  8:27   ` [PATCH v16.1 " Sakari Ailus
  2017-10-27  8:44     ` Niklas Söderlund
@ 2017-10-29 22:19     ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 22:19 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel

[-- Attachment #1: Type: text/plain, Size: 14012 bytes --]

Hi,

On Fri, Oct 27, 2017 at 11:27:09AM +0300, Sakari Ailus wrote:
> Registering a notifier has required the knowledge of struct v4l2_device
> for the reason that sub-devices generally are registered to the
> v4l2_device (as well as the media device, also available through
> v4l2_device).
> 
> This information is not available for sub-device drivers at probe time.
> 
> What this patch does is that it allows registering notifiers without
> having v4l2_device around. Instead the sub-device pointer is stored in the
> notifier. Once the sub-device of the driver that registered the notifier
> is registered, the notifier will gain the knowledge of the v4l2_device,
> and the binding of async sub-devices from the sub-device driver's notifier
> may proceed.
> 
> The complete callback of the root notifier will be called only when the
> v4l2_device is available and no notifier has pending sub-devices to bind.
> No complete callbacks are supported for sub-device notifiers.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/v4l2-core/v4l2-async.c | 212 ++++++++++++++++++++++++++++-------
>  include/media/v4l2-async.h           |  19 +++-
>  2 files changed, 189 insertions(+), 42 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index 6265717769d2..ed539c4fd5dc 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -124,11 +124,87 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
>  	return NULL;
>  }
>  
> +/* Find the sub-device notifier registered by a sub-device driver. */
> +static struct v4l2_async_notifier *v4l2_async_find_subdev_notifier(
> +	struct v4l2_subdev *sd)
> +{
> +	struct v4l2_async_notifier *n;
> +
> +	list_for_each_entry(n, &notifier_list, list)
> +		if (n->sd == sd)
> +			return n;
> +
> +	return NULL;
> +}
> +
> +/* Get v4l2_device related to the notifier if one can be found. */
> +static struct v4l2_device *v4l2_async_notifier_find_v4l2_dev(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	while (notifier->parent)
> +		notifier = notifier->parent;
> +
> +	return notifier->v4l2_dev;
> +}
> +
> +/*
> + * Return true if all child sub-device notifiers are complete, false otherwise.
> + */
> +static bool v4l2_async_notifier_can_complete(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	struct v4l2_subdev *sd;
> +
> +	if (!list_empty(&notifier->waiting))
> +		return false;
> +
> +	list_for_each_entry(sd, &notifier->done, async_list) {
> +		struct v4l2_async_notifier *subdev_notifier =
> +			v4l2_async_find_subdev_notifier(sd);
> +
> +		if (subdev_notifier &&
> +		    !v4l2_async_notifier_can_complete(subdev_notifier))
> +			return false;
> +	}
> +
> +	return true;
> +}
> +
> +/*
> + * Complete the master notifier if possible. This is done when all async
> + * sub-devices have been bound; v4l2_device is also available then.
> + */
> +static int v4l2_async_notifier_try_complete(
> +	struct v4l2_async_notifier *notifier)
> +{
> +	/* Quick check whether there are still more sub-devices here. */
> +	if (!list_empty(&notifier->waiting))
> +		return 0;
> +
> +	/* Check the entire notifier tree; find the root notifier first. */
> +	while (notifier->parent)
> +		notifier = notifier->parent;
> +
> +	/* This is root if it has v4l2_dev. */
> +	if (!notifier->v4l2_dev)
> +		return 0;
> +
> +	/* Is everything ready? */
> +	if (!v4l2_async_notifier_can_complete(notifier))
> +		return 0;
> +
> +	return v4l2_async_notifier_call_complete(notifier);
> +}
> +
> +static int v4l2_async_notifier_try_all_subdevs(
> +	struct v4l2_async_notifier *notifier);
> +
>  static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  				   struct v4l2_device *v4l2_dev,
>  				   struct v4l2_subdev *sd,
>  				   struct v4l2_async_subdev *asd)
>  {
> +	struct v4l2_async_notifier *subdev_notifier;
>  	int ret;
>  
>  	ret = v4l2_device_register_subdev(v4l2_dev, sd);
> @@ -149,17 +225,36 @@ static int v4l2_async_match_notify(struct v4l2_async_notifier *notifier,
>  	/* Move from the global subdevice list to notifier's done */
>  	list_move(&sd->async_list, &notifier->done);
>  
> -	return 0;
> +	/*
> +	 * See if the sub-device has a notifier. If not, return here.
> +	 */
> +	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
> +	if (!subdev_notifier || subdev_notifier->parent)
> +		return 0;
> +
> +	/*
> +	 * Proceed with checking for the sub-device notifier's async
> +	 * sub-devices, and return the result. The error will be handled by the
> +	 * caller.
> +	 */
> +	subdev_notifier->parent = notifier;
> +
> +	return v4l2_async_notifier_try_all_subdevs(subdev_notifier);
>  }
>  
>  /* Test all async sub-devices in a notifier for a match. */
>  static int v4l2_async_notifier_try_all_subdevs(
>  	struct v4l2_async_notifier *notifier)
>  {
> -	struct v4l2_device *v4l2_dev = notifier->v4l2_dev;
> -	struct v4l2_subdev *sd, *tmp;
> +	struct v4l2_device *v4l2_dev =
> +		v4l2_async_notifier_find_v4l2_dev(notifier);
> +	struct v4l2_subdev *sd;
> +
> +	if (!v4l2_dev)
> +		return 0;
>  
> -	list_for_each_entry_safe(sd, tmp, &subdev_list, async_list) {
> +again:
> +	list_for_each_entry(sd, &subdev_list, async_list) {
>  		struct v4l2_async_subdev *asd;
>  		int ret;
>  
> @@ -170,6 +265,14 @@ static int v4l2_async_notifier_try_all_subdevs(
>  		ret = v4l2_async_match_notify(notifier, v4l2_dev, sd, asd);
>  		if (ret < 0)
>  			return ret;
> +
> +		/*
> +		 * v4l2_async_match_notify() may lead to registering a
> +		 * new notifier and thus changing the async subdevs
> +		 * list. In order to proceed safely from here, restart
> +		 * parsing the list from the beginning.
> +		 */
> +		goto again;
>  	}
>  
>  	return 0;
> @@ -183,17 +286,26 @@ static void v4l2_async_cleanup(struct v4l2_subdev *sd)
>  	sd->asd = NULL;
>  }
>  
> +/* Unbind all sub-devices in the notifier tree. */
>  static void v4l2_async_notifier_unbind_all_subdevs(
>  	struct v4l2_async_notifier *notifier)
>  {
>  	struct v4l2_subdev *sd, *tmp;
>  
>  	list_for_each_entry_safe(sd, tmp, &notifier->done, async_list) {
> +		struct v4l2_async_notifier *subdev_notifier =
> +			v4l2_async_find_subdev_notifier(sd);
> +
> +		if (subdev_notifier)
> +			v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
> +
>  		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>  		v4l2_async_cleanup(sd);
>  
>  		list_move(&sd->async_list, &subdev_list);
>  	}
> +
> +	notifier->parent = NULL;
>  }
>  
>  static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> @@ -208,15 +320,6 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> -	if (!notifier->num_subdevs) {
> -		int ret;
> -
> -		ret = v4l2_async_notifier_call_complete(notifier);
> -		notifier->v4l2_dev = NULL;
> -
> -		return ret;
> -	}
> -
>  	for (i = 0; i < notifier->num_subdevs; i++) {
>  		asd = notifier->subdevs[i];
>  
> @@ -238,16 +341,12 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  	mutex_lock(&list_lock);
>  
>  	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> -	if (ret) {
> -		mutex_unlock(&list_lock);
> -		return ret;
> -	}
> +	if (ret)
> +		goto err_unbind;
>  
> -	if (list_empty(&notifier->waiting)) {
> -		ret = v4l2_async_notifier_call_complete(notifier);
> -		if (ret)
> -			goto err_complete;
> -	}
> +	ret = v4l2_async_notifier_try_complete(notifier);
> +	if (ret)
> +		goto err_unbind;
>  
>  	/* Keep also completed notifiers on the list */
>  	list_add(&notifier->list, &notifier_list);
> @@ -256,7 +355,10 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  
>  	return 0;
>  
> -err_complete:
> +err_unbind:
> +	/*
> +	 * On failure, unbind all sub-devices registered through this notifier.
> +	 */
>  	v4l2_async_notifier_unbind_all_subdevs(notifier);
>  
>  	mutex_unlock(&list_lock);
> @@ -269,7 +371,7 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  {
>  	int ret;
>  
> -	if (WARN_ON(!v4l2_dev))
> +	if (WARN_ON(!v4l2_dev || notifier->sd))
>  		return -EINVAL;
>  
>  	notifier->v4l2_dev = v4l2_dev;
> @@ -282,20 +384,39 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  }
>  EXPORT_SYMBOL(v4l2_async_notifier_register);
>  
> +int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
> +					struct v4l2_async_notifier *notifier)
> +{
> +	int ret;
> +
> +	if (WARN_ON(!sd || notifier->v4l2_dev))
> +		return -EINVAL;
> +
> +	notifier->sd = sd;
> +
> +	ret = __v4l2_async_notifier_register(notifier);
> +	if (ret)
> +		notifier->sd = NULL;
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
> +
>  void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
>  {
> -	if (!notifier->v4l2_dev)
> +	if (!notifier->v4l2_dev && !notifier->sd)
>  		return;
>  
>  	mutex_lock(&list_lock);
>  
> -	list_del(&notifier->list);
> -
>  	v4l2_async_notifier_unbind_all_subdevs(notifier);
>  
> -	mutex_unlock(&list_lock);
> -
> +	notifier->sd = NULL;
>  	notifier->v4l2_dev = NULL;
> +
> +	list_del(&notifier->list);
> +
> +	mutex_unlock(&list_lock);
>  }
>  EXPORT_SYMBOL(v4l2_async_notifier_unregister);
>  
> @@ -331,6 +452,7 @@ EXPORT_SYMBOL_GPL(v4l2_async_notifier_cleanup);
>  
>  int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  {
> +	struct v4l2_async_notifier *subdev_notifier;
>  	struct v4l2_async_notifier *notifier;
>  	int ret;
>  
> @@ -347,24 +469,26 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  	INIT_LIST_HEAD(&sd->async_list);
>  
>  	list_for_each_entry(notifier, &notifier_list, list) {
> -		struct v4l2_async_subdev *asd = v4l2_async_find_match(notifier,
> -								      sd);
> +		struct v4l2_device *v4l2_dev =
> +			v4l2_async_notifier_find_v4l2_dev(notifier);
> +		struct v4l2_async_subdev *asd;
>  		int ret;
>  
> +		if (!v4l2_dev)
> +			continue;
> +
> +		asd = v4l2_async_find_match(notifier, sd);
>  		if (!asd)
>  			continue;
>  
>  		ret = v4l2_async_match_notify(notifier, notifier->v4l2_dev, sd,
>  					      asd);
>  		if (ret)
> -			goto err_unlock;
> -
> -		if (!list_empty(&notifier->waiting))
> -			goto out_unlock;
> +			goto err_unbind;
>  
> -		ret = v4l2_async_notifier_call_complete(notifier);
> +		ret = v4l2_async_notifier_try_complete(notifier);
>  		if (ret)
> -			goto err_cleanup;
> +			goto err_unbind;
>  
>  		goto out_unlock;
>  	}
> @@ -377,11 +501,19 @@ int v4l2_async_register_subdev(struct v4l2_subdev *sd)
>  
>  	return 0;
>  
> -err_cleanup:
> -	v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
> +err_unbind:
> +	/*
> +	 * Complete failed. Unbind the sub-devices bound through registering
> +	 * this async sub-device.
> +	 */
> +	subdev_notifier = v4l2_async_find_subdev_notifier(sd);
> +	if (subdev_notifier)
> +		v4l2_async_notifier_unbind_all_subdevs(subdev_notifier);
> +
> +	if (sd->asd)
> +		v4l2_async_notifier_call_unbind(notifier, sd, sd->asd);
>  	v4l2_async_cleanup(sd);
>  
> -err_unlock:
>  	mutex_unlock(&list_lock);
>  
>  	return ret;
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 68606afb5ef9..17c4ac7c73e8 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -82,7 +82,8 @@ struct v4l2_async_subdev {
>  /**
>   * struct v4l2_async_notifier_operations - Asynchronous V4L2 notifier operations
>   * @bound:	a subdevice driver has successfully probed one of the subdevices
> - * @complete:	all subdevices have been probed successfully
> + * @complete:	All subdevices have been probed successfully. The complete
> + *		callback is only executed for the root notifier.
>   * @unbind:	a subdevice is leaving
>   */
>  struct v4l2_async_notifier_operations {
> @@ -102,7 +103,9 @@ struct v4l2_async_notifier_operations {
>   * @num_subdevs: number of subdevices used in the subdevs array
>   * @max_subdevs: number of subdevices allocated in the subdevs array
>   * @subdevs:	array of pointers to subdevice descriptors
> - * @v4l2_dev:	pointer to struct v4l2_device
> + * @v4l2_dev:	v4l2_device of the root notifier, NULL otherwise
> + * @sd:		sub-device that registered the notifier, NULL otherwise
> + * @parent:	parent notifier
>   * @waiting:	list of struct v4l2_async_subdev, waiting for their drivers
>   * @done:	list of struct v4l2_subdev, already probed
>   * @list:	member in a global list of notifiers
> @@ -113,6 +116,8 @@ struct v4l2_async_notifier {
>  	unsigned int max_subdevs;
>  	struct v4l2_async_subdev **subdevs;
>  	struct v4l2_device *v4l2_dev;
> +	struct v4l2_subdev *sd;
> +	struct v4l2_async_notifier *parent;
>  	struct list_head waiting;
>  	struct list_head done;
>  	struct list_head list;
> @@ -128,6 +133,16 @@ int v4l2_async_notifier_register(struct v4l2_device *v4l2_dev,
>  				 struct v4l2_async_notifier *notifier);
>  
>  /**
> + * v4l2_async_subdev_notifier_register - registers a subdevice asynchronous
> + *					 notifier for a sub-device
> + *
> + * @sd: pointer to &struct v4l2_subdev
> + * @notifier: pointer to &struct v4l2_async_notifier
> + */
> +int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
> +					struct v4l2_async_notifier *notifier);
> +
> +/**
>   * v4l2_async_notifier_unregister - unregisters a subdevice asynchronous notifier
>   *
>   * @notifier: pointer to &struct v4l2_async_notifier
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16.1 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers
  2017-10-27 10:53   ` [PATCH v16.1 " Sakari Ailus
@ 2017-10-29 22:25     ` Sebastian Reichel
  2017-10-30 13:05       ` Sakari Ailus
  2017-10-30 13:09     ` [PATCH v16.2 " Sakari Ailus
  1 sibling, 1 reply; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 22:25 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel

[-- Attachment #1: Type: text/plain, Size: 4900 bytes --]

Hi,

On Fri, Oct 27, 2017 at 01:53:09PM +0300, Sakari Ailus wrote:
> 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>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> ---
>  drivers/media/v4l2-core/v4l2-async.c | 89 ++++++++++++++++++++++++++++++++----
>  1 file changed, 81 insertions(+), 8 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index ed539c4fd5dc..a33a68e5417b 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -308,8 +308,71 @@ static void v4l2_async_notifier_unbind_all_subdevs(
>  	notifier->parent = NULL;
>  }
>  
> +/* See if an fwnode can be found in a notifier's lists. */
> +static bool __v4l2_async_notifier_fwnode_has_async_subdev(
> +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
> +{
> +	struct v4l2_async_subdev *asd;
> +	struct v4l2_subdev *sd;
> +
> +	list_for_each_entry(asd, &notifier->waiting, list) {
> +		if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> +			continue;
> +
> +		if (asd->match.fwnode.fwnode == fwnode)
> +			return true;
> +	}
> +
> +	list_for_each_entry(sd, &notifier->done, async_list) {
> +		if (WARN_ON(!sd->asd))
> +			continue;
> +
> +		if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> +			continue;
> +
> +		if (sd->asd->match.fwnode.fwnode == fwnode)
> +			return true;
> +	}
> +
> +	return false;
> +}
> +
> +/*
> + * Find out whether an async sub-device was set up for an fwnode already or
> + * whether it exists in a given notifier before @this_index.
> + */
> +static bool v4l2_async_notifier_fwnode_has_async_subdev(
> +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
> +	unsigned int this_index)
> +{
> +	unsigned int j;
> +
> +	lockdep_assert_held(&list_lock);
> +
> +	/* Check that an fwnode is not being added more than once. */
> +	for (j = 0; j < this_index; j++) {
> +		struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
> +		struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
> +
> +		if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
> +		    asd->match.fwnode.fwnode ==
> +		    other_asd->match.fwnode.fwnode)
> +			return true;
> +	}
> +
> +	/* Check than an fwnode did not exist in other notifiers. */
> +	list_for_each_entry(notifier, &notifier_list, list)
> +		if (__v4l2_async_notifier_fwnode_has_async_subdev(
> +			    notifier, fwnode))
> +			return true;
> +
> +	return false;
> +}
> +
>  static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  {
> +	struct device *dev =
> +		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
>  	struct v4l2_async_subdev *asd;
>  	int ret;
>  	int i;
> @@ -320,6 +383,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  	INIT_LIST_HEAD(&notifier->waiting);
>  	INIT_LIST_HEAD(&notifier->done);
>  
> +	mutex_lock(&list_lock);
> +
>  	for (i = 0; i < notifier->num_subdevs; i++) {
>  		asd = notifier->subdevs[i];
>  
> @@ -327,33 +392,41 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
>  		case V4L2_ASYNC_MATCH_CUSTOM:
>  		case V4L2_ASYNC_MATCH_DEVNAME:
>  		case V4L2_ASYNC_MATCH_I2C:
> +			break;
>  		case V4L2_ASYNC_MATCH_FWNODE:
> +			if (v4l2_async_notifier_fwnode_has_async_subdev(
> +				    notifier, asd->match.fwnode.fwnode, i)) {
> +				dev_err(dev,
> +					"fwnode has already been registered or in notifier's subdev list\n");
> +				ret = -EEXIST;
> +				goto out_unlock;
> +			}
>  			break;
>  		default:
> -			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
> -				"Invalid match type %u on %p\n",
> +			dev_err(dev, "Invalid match type %u on %p\n",
>  				asd->match_type, asd);
> -			return -EINVAL;
> +			ret = -EINVAL;
> +			goto out_unlock;
>  		}
>  		list_add_tail(&asd->list, &notifier->waiting);
>  	}
>  
> -	mutex_lock(&list_lock);
> -
>  	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> -	if (ret)
> +	if (ret < 0)
>  		goto err_unbind;

the error path does no unlock?

>  	ret = v4l2_async_notifier_try_complete(notifier);
> -	if (ret)
> +	if (ret < 0)
>  		goto err_unbind;

dito

> +	ret = 0;
>  
>  	/* Keep also completed notifiers on the list */
>  	list_add(&notifier->list, &notifier_list);
>  
> +out_unlock:
>  	mutex_unlock(&list_lock);
>  
> -	return 0;
> +	return ret;
>  
>  err_unbind:
>  	/*

Otherwise:

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 20/32] dt: bindings: Add a binding for flash LED devices associated to a sensor
  2017-10-26  7:53 ` [PATCH v16 20/32] dt: bindings: Add a binding for flash LED devices associated to a sensor Sakari Ailus
@ 2017-10-29 22:26       ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 22:26 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA, Rob Herring

[-- Attachment #1: Type: text/plain, Size: 1668 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:30AM +0300, Sakari Ailus wrote:
> Camera flash drivers (and LEDs) are separate from the sensor devices in
> DT. In order to make an association between the two, provide the
> association information to the software.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Cc: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> Cc: devicetree-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>
> Acked-by: Rob Herring <robh-DgEjT+Ai2ygdnm+yROfE0A@public.gmane.org>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>

-- Sebastian

>  Documentation/devicetree/bindings/media/video-interfaces.txt | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt
> index bd6474920510..dc66e3224692 100644
> --- a/Documentation/devicetree/bindings/media/video-interfaces.txt
> +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt
> @@ -76,6 +76,14 @@ are required in a relevant parent node:
>  		    identifier, should be 1.
>   - #size-cells    : should be zero.
>  
> +
> +Optional properties
> +-------------------
> +
> +- flash-leds: An array of phandles, each referring to a flash LED, a sub-node
> +  of the LED driver device node.
> +
> +
>  Optional endpoint properties
>  ----------------------------
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 20/32] dt: bindings: Add a binding for flash LED devices associated to a sensor
@ 2017-10-29 22:26       ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 22:26 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree, Rob Herring

[-- Attachment #1: Type: text/plain, Size: 1486 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:30AM +0300, Sakari Ailus wrote:
> Camera flash drivers (and LEDs) are separate from the sensor devices in
> DT. In order to make an association between the two, provide the
> association information to the software.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Cc: Rob Herring <robh@kernel.org>
> Cc: devicetree@vger.kernel.org
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> Acked-by: Rob Herring <robh@kernel.org>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  Documentation/devicetree/bindings/media/video-interfaces.txt | 8 ++++++++
>  1 file changed, 8 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/media/video-interfaces.txt b/Documentation/devicetree/bindings/media/video-interfaces.txt
> index bd6474920510..dc66e3224692 100644
> --- a/Documentation/devicetree/bindings/media/video-interfaces.txt
> +++ b/Documentation/devicetree/bindings/media/video-interfaces.txt
> @@ -76,6 +76,14 @@ are required in a relevant parent node:
>  		    identifier, should be 1.
>   - #size-cells    : should be zero.
>  
> +
> +Optional properties
> +-------------------
> +
> +- flash-leds: An array of phandles, each referring to a flash LED, a sub-node
> +  of the LED driver device node.
> +
> +
>  Optional endpoint properties
>  ----------------------------
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 22/32] v4l: fwnode: Move KernelDoc documentation to the header
  2017-10-26  7:53 ` [PATCH v16 22/32] v4l: fwnode: Move KernelDoc documentation to the header Sakari Ailus
@ 2017-10-29 22:28   ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 22:28 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 10632 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:32AM +0300, Sakari Ailus wrote:
> In V4L2 the practice is to have the KernelDoc documentation in the header
> and not in .c source code files. This consequently makes the V4L2 fwnode
> function documentation part of the Media documentation build.
> 
> Also correct the link related function and argument naming in
> documentation and add an asterisk to v4l2_fwnode_endpoint_free()
> documentation to make it proper KernelDoc documentation.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Reviewed-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/v4l2-core/v4l2-fwnode.c | 75 --------------------------------
>  include/media/v4l2-fwnode.h           | 81 ++++++++++++++++++++++++++++++++++-
>  2 files changed, 80 insertions(+), 76 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index df0695b7bbcc..65bdcd59744a 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -183,25 +183,6 @@ v4l2_fwnode_endpoint_parse_csi1_bus(struct fwnode_handle *fwnode,
>  		vep->bus_type = V4L2_MBUS_CSI1;
>  }
>  
> -/**
> - * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
> - * @fwnode: pointer to the endpoint's fwnode handle
> - * @vep: pointer to the V4L2 fwnode data structure
> - *
> - * All properties are optional. If none are found, we don't set any flags. This
> - * means the port has a static configuration and no properties have to be
> - * specified explicitly. If any properties that identify the bus as parallel
> - * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
> - * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
> - * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
> - * reference to @fwnode.
> - *
> - * NOTE: This function does not parse properties the size of which is variable
> - * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in
> - * new drivers instead.
> - *
> - * Return: 0 on success or a negative error code on failure.
> - */
>  int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
>  			       struct v4l2_fwnode_endpoint *vep)
>  {
> @@ -241,14 +222,6 @@ int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
>  }
>  EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_parse);
>  
> -/*
> - * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by
> - * v4l2_fwnode_endpoint_alloc_parse()
> - * @vep - the V4L2 fwnode the resources of which are to be released
> - *
> - * It is safe to call this function with NULL argument or on a V4L2 fwnode the
> - * parsing of which failed.
> - */
>  void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
>  {
>  	if (IS_ERR_OR_NULL(vep))
> @@ -259,29 +232,6 @@ void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep)
>  }
>  EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_free);
>  
> -/**
> - * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
> - * @fwnode: pointer to the endpoint's fwnode handle
> - *
> - * All properties are optional. If none are found, we don't set any flags. This
> - * means the port has a static configuration and no properties have to be
> - * specified explicitly. If any properties that identify the bus as parallel
> - * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
> - * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
> - * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
> - * reference to @fwnode.
> - *
> - * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
> - * v4l2_fwnode_endpoint_parse():
> - *
> - * 1. It also parses variable size data.
> - *
> - * 2. The memory it has allocated to store the variable size data must be freed
> - *    using v4l2_fwnode_endpoint_free() when no longer needed.
> - *
> - * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer
> - * on error.
> - */
>  struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
>  	struct fwnode_handle *fwnode)
>  {
> @@ -324,24 +274,6 @@ struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
>  }
>  EXPORT_SYMBOL_GPL(v4l2_fwnode_endpoint_alloc_parse);
>  
> -/**
> - * v4l2_fwnode_endpoint_parse_link() - parse a link between two endpoints
> - * @__fwnode: pointer to the endpoint's fwnode at the local end of the link
> - * @link: pointer to the V4L2 fwnode link data structure
> - *
> - * Fill the link structure with the local and remote nodes and port numbers.
> - * The local_node and remote_node fields are set to point to the local and
> - * remote port's parent nodes respectively (the port parent node being the
> - * parent node of the port node if that node isn't a 'ports' node, or the
> - * grand-parent node of the port node otherwise).
> - *
> - * A reference is taken to both the local and remote nodes, the caller must use
> - * v4l2_fwnode_endpoint_put_link() to drop the references when done with the
> - * link.
> - *
> - * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be
> - * found.
> - */
>  int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
>  			   struct v4l2_fwnode_link *link)
>  {
> @@ -376,13 +308,6 @@ int v4l2_fwnode_parse_link(struct fwnode_handle *__fwnode,
>  }
>  EXPORT_SYMBOL_GPL(v4l2_fwnode_parse_link);
>  
> -/**
> - * v4l2_fwnode_put_link() - drop references to nodes in a link
> - * @link: pointer to the V4L2 fwnode link data structure
> - *
> - * Drop references to the local and remote nodes in the link. This function
> - * must be called on every link parsed with v4l2_fwnode_parse_link().
> - */
>  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link)
>  {
>  	fwnode_handle_put(link->local_node);
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index ac605af9b877..105cfeee44ef 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -115,13 +115,92 @@ struct v4l2_fwnode_link {
>  	unsigned int remote_port;
>  };
>  
> +/**
> + * v4l2_fwnode_endpoint_parse() - parse all fwnode node properties
> + * @fwnode: pointer to the endpoint's fwnode handle
> + * @vep: pointer to the V4L2 fwnode data structure
> + *
> + * All properties are optional. If none are found, we don't set any flags. This
> + * means the port has a static configuration and no properties have to be
> + * specified explicitly. If any properties that identify the bus as parallel
> + * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
> + * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
> + * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
> + * reference to @fwnode.
> + *
> + * NOTE: This function does not parse properties the size of which is variable
> + * without a low fixed limit. Please use v4l2_fwnode_endpoint_alloc_parse() in
> + * new drivers instead.
> + *
> + * Return: 0 on success or a negative error code on failure.
> + */
>  int v4l2_fwnode_endpoint_parse(struct fwnode_handle *fwnode,
>  			       struct v4l2_fwnode_endpoint *vep);
> +
> +/**
> + * v4l2_fwnode_endpoint_free() - free the V4L2 fwnode acquired by
> + * v4l2_fwnode_endpoint_alloc_parse()
> + * @vep: the V4L2 fwnode the resources of which are to be released
> + *
> + * It is safe to call this function with NULL argument or on a V4L2 fwnode the
> + * parsing of which failed.
> + */
> +void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
> +
> +/**
> + * v4l2_fwnode_endpoint_alloc_parse() - parse all fwnode node properties
> + * @fwnode: pointer to the endpoint's fwnode handle
> + *
> + * All properties are optional. If none are found, we don't set any flags. This
> + * means the port has a static configuration and no properties have to be
> + * specified explicitly. If any properties that identify the bus as parallel
> + * are found and slave-mode isn't set, we set V4L2_MBUS_MASTER. Similarly, if
> + * we recognise the bus as serial CSI-2 and clock-noncontinuous isn't set, we
> + * set the V4L2_MBUS_CSI2_CONTINUOUS_CLOCK flag. The caller should hold a
> + * reference to @fwnode.
> + *
> + * v4l2_fwnode_endpoint_alloc_parse() has two important differences to
> + * v4l2_fwnode_endpoint_parse():
> + *
> + * 1. It also parses variable size data.
> + *
> + * 2. The memory it has allocated to store the variable size data must be freed
> + *    using v4l2_fwnode_endpoint_free() when no longer needed.
> + *
> + * Return: Pointer to v4l2_fwnode_endpoint if successful, on an error pointer
> + * on error.
> + */
>  struct v4l2_fwnode_endpoint *v4l2_fwnode_endpoint_alloc_parse(
>  	struct fwnode_handle *fwnode);
> -void v4l2_fwnode_endpoint_free(struct v4l2_fwnode_endpoint *vep);
> +
> +/**
> + * v4l2_fwnode_parse_link() - parse a link between two endpoints
> + * @fwnode: pointer to the endpoint's fwnode at the local end of the link
> + * @link: pointer to the V4L2 fwnode link data structure
> + *
> + * Fill the link structure with the local and remote nodes and port numbers.
> + * The local_node and remote_node fields are set to point to the local and
> + * remote port's parent nodes respectively (the port parent node being the
> + * parent node of the port node if that node isn't a 'ports' node, or the
> + * grand-parent node of the port node otherwise).
> + *
> + * A reference is taken to both the local and remote nodes, the caller must use
> + * v4l2_fwnode_put_link() to drop the references when done with the
> + * link.
> + *
> + * Return: 0 on success, or -ENOLINK if the remote endpoint fwnode can't be
> + * found.
> + */
>  int v4l2_fwnode_parse_link(struct fwnode_handle *fwnode,
>  			   struct v4l2_fwnode_link *link);
> +
> +/**
> + * v4l2_fwnode_put_link() - drop references to nodes in a link
> + * @link: pointer to the V4L2 fwnode link data structure
> + *
> + * Drop references to the local and remote nodes in the link. This function
> + * must be called on every link parsed with v4l2_fwnode_parse_link().
> + */
>  void v4l2_fwnode_put_link(struct v4l2_fwnode_link *link);
>  
>  /**
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 23/32] v4l: fwnode: Add a helper function for parsing generic references
  2017-10-26  7:53 ` [PATCH v16 23/32] v4l: fwnode: Add a helper function for parsing generic references Sakari Ailus
  2017-10-27 10:30   ` Niklas Söderlund
@ 2017-10-29 22:53   ` Sebastian Reichel
  1 sibling, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 22:53 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 3161 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:33AM +0300, Sakari Ailus wrote:
> Add function v4l2_fwnode_reference_parse() for parsing them as async
> sub-devices. This can be done on e.g. flash or lens async sub-devices that
> are not part of but are associated with a sensor.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/v4l2-core/v4l2-fwnode.c | 69 +++++++++++++++++++++++++++++++++++
>  1 file changed, 69 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 65bdcd59744a..edd2e8d983a1 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -509,6 +509,75 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
>  }
>  EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_endpoints_by_port);
>  
> +/*
> + * v4l2_fwnode_reference_parse - parse references for async sub-devices
> + * @dev: the device node the properties of which are parsed for references
> + * @notifier: the async notifier where the async subdevs will be added
> + * @prop: the name of the property
> + *
> + * Return: 0 on success
> + *	   -ENOENT if no entries were found
> + *	   -ENOMEM if memory allocation failed
> + *	   -EINVAL if property parsing failed
> + */
> +static int v4l2_fwnode_reference_parse(
> +	struct device *dev, struct v4l2_async_notifier *notifier,
> +	const char *prop)
> +{
> +	struct fwnode_reference_args args;
> +	unsigned int index;
> +	int ret;
> +
> +	for (index = 0;
> +	     !(ret = fwnode_property_get_reference_args(
> +		       dev_fwnode(dev), prop, NULL, 0, index, &args));
> +	     index++)
> +		fwnode_handle_put(args.fwnode);
> +
> +	if (!index)
> +		return -ENOENT;
> +
> +	/*
> +	 * Note that right now both -ENODATA and -ENOENT may signal
> +	 * out-of-bounds access. Return the error in cases other than that.
> +	 */
> +	if (ret != -ENOENT && ret != -ENODATA)
> +		return ret;
> +
> +	ret = v4l2_async_notifier_realloc(notifier,
> +					  notifier->num_subdevs + index);
> +	if (ret)
> +		return ret;
> +
> +	for (index = 0; !fwnode_property_get_reference_args(
> +		     dev_fwnode(dev), prop, NULL, 0, index, &args);
> +	     index++) {
> +		struct v4l2_async_subdev *asd;
> +
> +		if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
> +			ret = -EINVAL;
> +			goto error;
> +		}
> +
> +		asd = kzalloc(sizeof(*asd), GFP_KERNEL);
> +		if (!asd) {
> +			ret = -ENOMEM;
> +			goto error;
> +		}
> +
> +		notifier->subdevs[notifier->num_subdevs] = asd;
> +		asd->match.fwnode.fwnode = args.fwnode;
> +		asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> +		notifier->num_subdevs++;
> +	}
> +
> +	return 0;
> +
> +error:
> +	fwnode_handle_put(args.fwnode);
> +	return ret;
> +}
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
>  MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16.1 24/32] v4l: fwnode: Add a helper function to obtain device / integer references
  2017-10-26 15:01   ` [PATCH v16.1 " Sakari Ailus
@ 2017-10-29 22:58     ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 22:58 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel

[-- Attachment #1: Type: text/plain, Size: 10239 bytes --]

Hi,

On Thu, Oct 26, 2017 at 06:01:58PM +0300, Sakari Ailus wrote:
> v4l2_fwnode_reference_parse_int_prop() will find an fwnode such that under
> the device's own fwnode, it will follow child fwnodes with the given
> property-value pair and return the resulting fwnode.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

> since v16:
> 
> - use const char * const *props for string arrays with property names.
> 
>  drivers/media/v4l2-core/v4l2-fwnode.c | 287 ++++++++++++++++++++++++++++++++++
>  1 file changed, 287 insertions(+)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index edd2e8d983a1..f8cd88f791c4 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -578,6 +578,293 @@ static int v4l2_fwnode_reference_parse(
>  	return ret;
>  }
>  
> +/*
> + * v4l2_fwnode_reference_get_int_prop - parse a reference with integer
> + *					arguments
> + * @fwnode: fwnode to read @prop from
> + * @notifier: notifier for @dev
> + * @prop: the name of the property
> + * @index: the index of the reference to get
> + * @props: the array of integer property names
> + * @nprops: the number of integer property names in @nprops
> + *
> + * First find an fwnode referred to by the reference at @index in @prop.
> + *
> + * Then under that fwnode, @nprops times, for each property in @props,
> + * iteratively follow child nodes starting from fwnode such that they have the
> + * property in @props array at the index of the child node distance from the
> + * root node and the value of that property matching with the integer argument
> + * of the reference, at the same index.
> + *
> + * The child fwnode reched at the end of the iteration is then returned to the
> + * caller.
> + *
> + * The core reason for this is that you cannot refer to just any node in ACPI.
> + * So to refer to an endpoint (easy in DT) you need to refer to a device, then
> + * provide a list of (property name, property value) tuples where each tuple
> + * uniquely identifies a child node. The first tuple identifies a child directly
> + * underneath the device fwnode, the next tuple identifies a child node
> + * underneath the fwnode identified by the previous tuple, etc. until you
> + * reached the fwnode you need.
> + *
> + * An example with a graph, as defined in Documentation/acpi/dsd/graph.txt:
> + *
> + *	Scope (\_SB.PCI0.I2C2)
> + *	{
> + *		Device (CAM0)
> + *		{
> + *			Name (_DSD, Package () {
> + *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> + *				Package () {
> + *					Package () {
> + *						"compatible",
> + *						Package () { "nokia,smia" }
> + *					},
> + *				},
> + *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
> + *				Package () {
> + *					Package () { "port0", "PRT0" },
> + *				}
> + *			})
> + *			Name (PRT0, Package() {
> + *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> + *				Package () {
> + *					Package () { "port", 0 },
> + *				},
> + *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
> + *				Package () {
> + *					Package () { "endpoint0", "EP00" },
> + *				}
> + *			})
> + *			Name (EP00, Package() {
> + *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> + *				Package () {
> + *					Package () { "endpoint", 0 },
> + *					Package () {
> + *						"remote-endpoint",
> + *						Package() {
> + *							\_SB.PCI0.ISP, 4, 0
> + *						}
> + *					},
> + *				}
> + *			})
> + *		}
> + *	}
> + *
> + *	Scope (\_SB.PCI0)
> + *	{
> + *		Device (ISP)
> + *		{
> + *			Name (_DSD, Package () {
> + *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
> + *				Package () {
> + *					Package () { "port4", "PRT4" },
> + *				}
> + *			})
> + *
> + *			Name (PRT4, Package() {
> + *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> + *				Package () {
> + *					Package () { "port", 4 },
> + *				},
> + *				ToUUID("dbb8e3e6-5886-4ba6-8795-1319f52a966b"),
> + *				Package () {
> + *					Package () { "endpoint0", "EP40" },
> + *				}
> + *			})
> + *
> + *			Name (EP40, Package() {
> + *				ToUUID("daffd814-6eba-4d8c-8a91-bc9bbf4aa301"),
> + *				Package () {
> + *					Package () { "endpoint", 0 },
> + *					Package () {
> + *						"remote-endpoint",
> + *						Package () {
> + *							\_SB.PCI0.I2C2.CAM0,
> + *							0, 0
> + *						}
> + *					},
> + *				}
> + *			})
> + *		}
> + *	}
> + *
> + * From the EP40 node under ISP device, you could parse the graph remote
> + * endpoint using v4l2_fwnode_reference_get_int_prop with these arguments:
> + *
> + *  @fwnode: fwnode referring to EP40 under ISP.
> + *  @prop: "remote-endpoint"
> + *  @index: 0
> + *  @props: "port", "endpoint"
> + *  @nprops: 2
> + *
> + * And you'd get back fwnode referring to EP00 under CAM0.
> + *
> + * The same works the other way around: if you use EP00 under CAM0 as the
> + * fwnode, you'll get fwnode referring to EP40 under ISP.
> + *
> + * The same example in DT syntax would look like this:
> + *
> + * cam: cam0 {
> + *	compatible = "nokia,smia";
> + *
> + *	port {
> + *		port = <0>;
> + *		endpoint {
> + *			endpoint = <0>;
> + *			remote-endpoint = <&isp 4 0>;
> + *		};
> + *	};
> + * };
> + *
> + * isp: isp {
> + *	ports {
> + *		port@4 {
> + *			port = <4>;
> + *			endpoint {
> + *				endpoint = <0>;
> + *				remote-endpoint = <&cam 0 0>;
> + *			};
> + *		};
> + *	};
> + * };
> + *
> + * Return: 0 on success
> + *	   -ENOENT if no entries (or the property itself) were found
> + *	   -EINVAL if property parsing otherwise failed
> + *	   -ENOMEM if memory allocation failed
> + */
> +static struct fwnode_handle *v4l2_fwnode_reference_get_int_prop(
> +	struct fwnode_handle *fwnode, const char *prop, unsigned int index,
> +	const char * const *props, unsigned int nprops)
> +{
> +	struct fwnode_reference_args fwnode_args;
> +	unsigned int *args = fwnode_args.args;
> +	struct fwnode_handle *child;
> +	int ret;
> +
> +	/*
> +	 * Obtain remote fwnode as well as the integer arguments.
> +	 *
> +	 * Note that right now both -ENODATA and -ENOENT may signal
> +	 * out-of-bounds access. Return -ENOENT in that case.
> +	 */
> +	ret = fwnode_property_get_reference_args(fwnode, prop, NULL, nprops,
> +						 index, &fwnode_args);
> +	if (ret)
> +		return ERR_PTR(ret == -ENODATA ? -ENOENT : ret);
> +
> +	/*
> +	 * Find a node in the tree under the referred fwnode corresponding to
> +	 * the integer arguments.
> +	 */
> +	fwnode = fwnode_args.fwnode;
> +	while (nprops--) {
> +		u32 val;
> +
> +		/* Loop over all child nodes under fwnode. */
> +		fwnode_for_each_child_node(fwnode, child) {
> +			if (fwnode_property_read_u32(child, *props, &val))
> +				continue;
> +
> +			/* Found property, see if its value matches. */
> +			if (val == *args)
> +				break;
> +		}
> +
> +		fwnode_handle_put(fwnode);
> +
> +		/* No property found; return an error here. */
> +		if (!child) {
> +			fwnode = ERR_PTR(-ENOENT);
> +			break;
> +		}
> +
> +		props++;
> +		args++;
> +		fwnode = child;
> +	}
> +
> +	return fwnode;
> +}
> +
> +/*
> + * v4l2_fwnode_reference_parse_int_props - parse references for async
> + *					   sub-devices
> + * @dev: struct device pointer
> + * @notifier: notifier for @dev
> + * @prop: the name of the property
> + * @props: the array of integer property names
> + * @nprops: the number of integer properties
> + *
> + * Use v4l2_fwnode_reference_get_int_prop to find fwnodes through reference in
> + * property @prop with integer arguments with child nodes matching in properties
> + * @props. Then, set up V4L2 async sub-devices for those fwnodes in the notifier
> + * accordingly.
> + *
> + * While it is technically possible to use this function on DT, it is only
> + * meaningful on ACPI. On Device tree you can refer to any node in the tree but
> + * on ACPI the references are limited to devices.
> + *
> + * Return: 0 on success
> + *	   -ENOENT if no entries (or the property itself) were found
> + *	   -EINVAL if property parsing otherwisefailed
> + *	   -ENOMEM if memory allocation failed
> + */
> +static int v4l2_fwnode_reference_parse_int_props(
> +	struct device *dev, struct v4l2_async_notifier *notifier,
> +	const char *prop, const char * const *props, unsigned int nprops)
> +{
> +	struct fwnode_handle *fwnode;
> +	unsigned int index;
> +	int ret;
> +
> +	for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
> +					 dev_fwnode(dev), prop, index, props,
> +					 nprops))); index++)
> +		fwnode_handle_put(fwnode);
> +
> +	/*
> +	 * Note that right now both -ENODATA and -ENOENT may signal
> +	 * out-of-bounds access. Return the error in cases other than that.
> +	 */
> +	if (PTR_ERR(fwnode) != -ENOENT && PTR_ERR(fwnode) != -ENODATA)
> +		return PTR_ERR(fwnode);
> +
> +	ret = v4l2_async_notifier_realloc(notifier,
> +					  notifier->num_subdevs + index);
> +	if (ret)
> +		return -ENOMEM;
> +
> +	for (index = 0; !IS_ERR((fwnode = v4l2_fwnode_reference_get_int_prop(
> +					 dev_fwnode(dev), prop, index, props,
> +					 nprops))); index++) {
> +		struct v4l2_async_subdev *asd;
> +
> +		if (WARN_ON(notifier->num_subdevs >= notifier->max_subdevs)) {
> +			ret = -EINVAL;
> +			goto error;
> +		}
> +
> +		asd = kzalloc(sizeof(struct v4l2_async_subdev), GFP_KERNEL);
> +		if (!asd) {
> +			ret = -ENOMEM;
> +			goto error;
> +		}
> +
> +		notifier->subdevs[notifier->num_subdevs] = asd;
> +		asd->match.fwnode.fwnode = fwnode;
> +		asd->match_type = V4L2_ASYNC_MATCH_FWNODE;
> +		notifier->num_subdevs++;
> +	}
> +
> +	return PTR_ERR(fwnode) == -ENOENT ? 0 : PTR_ERR(fwnode);
> +
> +error:
> +	fwnode_handle_put(fwnode);
> +	return ret;
> +}
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
>  MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16.1 25/32] v4l: fwnode: Add convenience function for parsing common external refs
  2017-10-26 15:03   ` [PATCH v16.1 " Sakari Ailus
@ 2017-10-29 23:00     ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 23:00 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel

[-- Attachment #1: Type: text/plain, Size: 4741 bytes --]

Hi,

On Thu, Oct 26, 2017 at 06:03:27PM +0300, Sakari Ailus wrote:
> Add v4l2_fwnode_parse_reference_sensor_common for parsing common
> sensor properties that refer to adjacent devices such as flash or lens
> driver chips.
> 
> As this is an association only, there's little a regular driver needs to
> know about these devices as such.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>

Reviewd-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

> ---
> since v16:
> 
> - use const char * const *props for string arrays with property names.
> 
>  drivers/media/v4l2-core/v4l2-fwnode.c | 35 +++++++++++++++++++++++++++++++++++
>  include/media/v4l2-async.h            |  3 ++-
>  include/media/v4l2-fwnode.h           | 21 +++++++++++++++++++++
>  3 files changed, 58 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index f8cd88f791c4..39387dc6cadd 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -865,6 +865,41 @@ static int v4l2_fwnode_reference_parse_int_props(
>  	return ret;
>  }
>  
> +int v4l2_async_notifier_parse_fwnode_sensor_common(
> +	struct device *dev, struct v4l2_async_notifier *notifier)
> +{
> +	static const char * const led_props[] = { "led" };
> +	static const struct {
> +		const char *name;
> +		const char * const *props;
> +		unsigned int nprops;
> +	} props[] = {
> +		{ "flash-leds", led_props, ARRAY_SIZE(led_props) },
> +		{ "lens-focus", NULL, 0 },
> +	};
> +	unsigned int i;
> +
> +	for (i = 0; i < ARRAY_SIZE(props); i++) {
> +		int ret;
> +
> +		if (props[i].props && is_acpi_node(dev_fwnode(dev)))
> +			ret = v4l2_fwnode_reference_parse_int_props(
> +				dev, notifier, props[i].name,
> +				props[i].props, props[i].nprops);
> +		else
> +			ret = v4l2_fwnode_reference_parse(
> +				dev, notifier, props[i].name);
> +		if (ret && ret != -ENOENT) {
> +			dev_warn(dev, "parsing property \"%s\" failed (%d)\n",
> +				 props[i].name, ret);
> +			return ret;
> +		}
> +	}
> +
> +	return 0;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
>  MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 17c4ac7c73e8..8d8cfc3f3100 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -156,7 +156,8 @@ void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier);
>   * Release memory resources related to a notifier, including the async
>   * sub-devices allocated for the purposes of the notifier but not the notifier
>   * itself. The user is responsible for calling this function to clean up the
> - * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints.
> + * notifier after calling @v4l2_async_notifier_parse_fwnode_endpoints or
> + * @v4l2_fwnode_reference_parse_sensor_common.
>   *
>   * There is no harm from calling v4l2_async_notifier_cleanup in other
>   * cases as long as its memory has been zeroed after it has been
> diff --git a/include/media/v4l2-fwnode.h b/include/media/v4l2-fwnode.h
> index 105cfeee44ef..ca50108dfd8f 100644
> --- a/include/media/v4l2-fwnode.h
> +++ b/include/media/v4l2-fwnode.h
> @@ -319,4 +319,25 @@ int v4l2_async_notifier_parse_fwnode_endpoints_by_port(
>  			      struct v4l2_fwnode_endpoint *vep,
>  			      struct v4l2_async_subdev *asd));
>  
> +/**
> + * v4l2_fwnode_reference_parse_sensor_common - parse common references on
> + *					       sensors for async sub-devices
> + * @dev: the device node the properties of which are parsed for references
> + * @notifier: the async notifier where the async subdevs will be added
> + *
> + * Parse common sensor properties for remote devices related to the
> + * sensor and set up async sub-devices for them.
> + *
> + * Any notifier populated using this function must be released with a call to
> + * v4l2_async_notifier_release() after it has been unregistered and the async
> + * sub-devices are no longer in use, even in the case the function returned an
> + * error.
> + *
> + * Return: 0 on success
> + *	   -ENOMEM if memory allocation failed
> + *	   -EINVAL if property parsing failed
> + */
> +int v4l2_async_notifier_parse_fwnode_sensor_common(
> +	struct device *dev, struct v4l2_async_notifier *notifier);
> +
>  #endif /* _V4L2_FWNODE_H */
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 26/32] v4l: fwnode: Add a convenience function for registering sensors
  2017-10-26  7:53     ` Sakari Ailus
  (?)
  (?)
@ 2017-10-29 23:02     ` Sebastian Reichel
  -1 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 23:02 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 6526 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:36AM +0300, Sakari Ailus wrote:
> Add a convenience function for parsing firmware for information on related
> devices using v4l2_async_notifier_parse_fwnode_sensor_common() registering
> the notifier and finally the async sub-device itself.
> 
> This should be useful for sensor drivers that do not have device specific
> requirements related to firmware information parsing or the async
> framework.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/v4l2-core/v4l2-async.c  | 19 ++++++++++++----
>  drivers/media/v4l2-core/v4l2-fwnode.c | 41 +++++++++++++++++++++++++++++++++++
>  include/media/v4l2-async.h            | 22 +++++++++++++++++++
>  include/media/v4l2-subdev.h           |  3 +++
>  4 files changed, 81 insertions(+), 4 deletions(-)
> 
> diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> index b4e88eef195f..e81a72b8d46e 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -474,19 +474,25 @@ int v4l2_async_subdev_notifier_register(struct v4l2_subdev *sd,
>  }
>  EXPORT_SYMBOL(v4l2_async_subdev_notifier_register);
>  
> -void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> +static void __v4l2_async_notifier_unregister(
> +	struct v4l2_async_notifier *notifier)
>  {
> -	if (!notifier->v4l2_dev && !notifier->sd)
> +	if (!notifier || (!notifier->v4l2_dev && !notifier->sd))
>  		return;
>  
> -	mutex_lock(&list_lock);
> -
>  	v4l2_async_notifier_unbind_all_subdevs(notifier);
>  
>  	notifier->sd = NULL;
>  	notifier->v4l2_dev = NULL;
>  
>  	list_del(&notifier->list);
> +}
> +
> +void v4l2_async_notifier_unregister(struct v4l2_async_notifier *notifier)
> +{
> +	mutex_lock(&list_lock);
> +
> +	__v4l2_async_notifier_unregister(notifier);
>  
>  	mutex_unlock(&list_lock);
>  }
> @@ -596,6 +602,11 @@ void v4l2_async_unregister_subdev(struct v4l2_subdev *sd)
>  {
>  	mutex_lock(&list_lock);
>  
> +	__v4l2_async_notifier_unregister(sd->subdev_notifier);
> +	v4l2_async_notifier_cleanup(sd->subdev_notifier);
> +	kfree(sd->subdev_notifier);
> +	sd->subdev_notifier = NULL;
> +
>  	if (sd->asd) {
>  		struct v4l2_async_notifier *notifier = sd->notifier;
>  
> diff --git a/drivers/media/v4l2-core/v4l2-fwnode.c b/drivers/media/v4l2-core/v4l2-fwnode.c
> index 1234bd1a2f49..82af608fd626 100644
> --- a/drivers/media/v4l2-core/v4l2-fwnode.c
> +++ b/drivers/media/v4l2-core/v4l2-fwnode.c
> @@ -29,6 +29,7 @@
>  
>  #include <media/v4l2-async.h>
>  #include <media/v4l2-fwnode.h>
> +#include <media/v4l2-subdev.h>
>  
>  enum v4l2_fwnode_bus_type {
>  	V4L2_FWNODE_BUS_TYPE_GUESS = 0,
> @@ -900,6 +901,46 @@ int v4l2_async_notifier_parse_fwnode_sensor_common(
>  }
>  EXPORT_SYMBOL_GPL(v4l2_async_notifier_parse_fwnode_sensor_common);
>  
> +int v4l2_async_register_subdev_sensor_common(struct v4l2_subdev *sd)
> +{
> +	struct v4l2_async_notifier *notifier;
> +	int ret;
> +
> +	if (WARN_ON(!sd->dev))
> +		return -ENODEV;
> +
> +	notifier = kzalloc(sizeof(*notifier), GFP_KERNEL);
> +	if (!notifier)
> +		return -ENOMEM;
> +
> +	ret = v4l2_async_notifier_parse_fwnode_sensor_common(sd->dev,
> +							     notifier);
> +	if (ret < 0)
> +		goto out_cleanup;
> +
> +	ret = v4l2_async_subdev_notifier_register(sd, notifier);
> +	if (ret < 0)
> +		goto out_cleanup;
> +
> +	ret = v4l2_async_register_subdev(sd);
> +	if (ret < 0)
> +		goto out_unregister;
> +
> +	sd->subdev_notifier = notifier;
> +
> +	return 0;
> +
> +out_unregister:
> +	v4l2_async_notifier_unregister(notifier);
> +
> +out_cleanup:
> +	v4l2_async_notifier_cleanup(notifier);
> +	kfree(notifier);
> +
> +	return ret;
> +}
> +EXPORT_SYMBOL_GPL(v4l2_async_register_subdev_sensor_common);
> +
>  MODULE_LICENSE("GPL");
>  MODULE_AUTHOR("Sakari Ailus <sakari.ailus@linux.intel.com>");
>  MODULE_AUTHOR("Sylwester Nawrocki <s.nawrocki@samsung.com>");
> diff --git a/include/media/v4l2-async.h b/include/media/v4l2-async.h
> index 8d8cfc3f3100..6152434cbe82 100644
> --- a/include/media/v4l2-async.h
> +++ b/include/media/v4l2-async.h
> @@ -174,6 +174,28 @@ void v4l2_async_notifier_cleanup(struct v4l2_async_notifier *notifier);
>  int v4l2_async_register_subdev(struct v4l2_subdev *sd);
>  
>  /**
> + * v4l2_async_register_subdev_sensor_common - registers a sensor sub-device to
> + *					      the asynchronous sub-device
> + *					      framework and parse set up common
> + *					      sensor related devices
> + *
> + * @sd: pointer to struct &v4l2_subdev
> + *
> + * This function is just like v4l2_async_register_subdev() with the exception
> + * that calling it will also parse firmware interfaces for remote references
> + * using v4l2_async_notifier_parse_fwnode_sensor_common() and registers the
> + * async sub-devices. The sub-device is similarly unregistered by calling
> + * v4l2_async_unregister_subdev().
> + *
> + * While registered, the subdev module is marked as in-use.
> + *
> + * An error is returned if the module is no longer loaded on any attempts
> + * to register it.
> + */
> +int __must_check v4l2_async_register_subdev_sensor_common(
> +	struct v4l2_subdev *sd);
> +
> +/**
>   * v4l2_async_unregister_subdev - unregisters a sub-device to the asynchronous
>   * 	subdevice framework
>   *
> diff --git a/include/media/v4l2-subdev.h b/include/media/v4l2-subdev.h
> index e83872078376..ec399c770301 100644
> --- a/include/media/v4l2-subdev.h
> +++ b/include/media/v4l2-subdev.h
> @@ -793,6 +793,8 @@ struct v4l2_subdev_platform_data {
>   *	list.
>   * @asd: Pointer to respective &struct v4l2_async_subdev.
>   * @notifier: Pointer to the managing notifier.
> + * @subdev_notifier: A sub-device notifier implicitly registered for the sub-
> + *		     device using v4l2_device_register_sensor_subdev().
>   * @pdata: common part of subdevice platform data
>   *
>   * Each instance of a subdev driver should create this struct, either
> @@ -823,6 +825,7 @@ struct v4l2_subdev {
>  	struct list_head async_list;
>  	struct v4l2_async_subdev *asd;
>  	struct v4l2_async_notifier *notifier;
> +	struct v4l2_async_notifier *subdev_notifier;
>  	struct v4l2_subdev_platform_data *pdata;
>  };
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 27/32] dt: bindings: smiapp: Document lens-focus and flash-leds properties
  2017-10-26  7:53     ` Sakari Ailus
@ 2017-10-29 23:03         ` Sebastian Reichel
  -1 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 23:03 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 1289 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:37AM +0300, Sakari Ailus wrote:
> Document optional lens-focus and flash-leds properties for the smiapp
> driver.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> Acked-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>

Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>

-- Sebastian

> ---
>  Documentation/devicetree/bindings/media/i2c/nokia,smia.txt | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
> index 855e1faf73e2..33f10a94c381 100644
> --- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
> +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
> @@ -27,6 +27,8 @@ Optional properties
>  - nokia,nvm-size: The size of the NVM, in bytes. If the size is not given,
>    the NVM contents will not be read.
>  - reset-gpios: XSHUTDOWN GPIO
> +- flash-leds: See ../video-interfaces.txt
> +- lens-focus: See ../video-interfaces.txt
>  
>  
>  Endpoint node mandatory properties
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 27/32] dt: bindings: smiapp: Document lens-focus and flash-leds properties
@ 2017-10-29 23:03         ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 23:03 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 1189 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:37AM +0300, Sakari Ailus wrote:
> Document optional lens-focus and flash-leds properties for the smiapp
> driver.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

> ---
>  Documentation/devicetree/bindings/media/i2c/nokia,smia.txt | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
> index 855e1faf73e2..33f10a94c381 100644
> --- a/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
> +++ b/Documentation/devicetree/bindings/media/i2c/nokia,smia.txt
> @@ -27,6 +27,8 @@ Optional properties
>  - nokia,nvm-size: The size of the NVM, in bytes. If the size is not given,
>    the NVM contents will not be read.
>  - reset-gpios: XSHUTDOWN GPIO
> +- flash-leds: See ../video-interfaces.txt
> +- lens-focus: See ../video-interfaces.txt
>  
>  
>  Endpoint node mandatory properties
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 28/32] smiapp: Add support for flash and lens devices
  2017-10-26  7:53     ` Sakari Ailus
  (?)
@ 2017-10-29 23:04     ` Sebastian Reichel
  -1 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 23:04 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 1528 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:38AM +0300, Sakari Ailus wrote:
> Parse async sub-devices related to the sensor by switching the async
> sub-device registration function.
> 
> These types devices aren't directly related to the sensor, but are
> nevertheless handled by the smiapp driver due to the relationship of these
> component to the main part of the camera module --- the sensor.
> 
> This does not yet address providing the user space with information on how
> to associate the sensor or lens devices but the kernel now has the
> necessary information to do that.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/i2c/smiapp/smiapp-core.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/i2c/smiapp/smiapp-core.c b/drivers/media/i2c/smiapp/smiapp-core.c
> index fbd851be51d2..a87c50373813 100644
> --- a/drivers/media/i2c/smiapp/smiapp-core.c
> +++ b/drivers/media/i2c/smiapp/smiapp-core.c
> @@ -3118,7 +3118,7 @@ static int smiapp_probe(struct i2c_client *client,
>  	if (rval < 0)
>  		goto out_media_entity_cleanup;
>  
> -	rval = v4l2_async_register_subdev(&sensor->src->sd);
> +	rval = v4l2_async_register_subdev_sensor_common(&sensor->src->sd);
>  	if (rval < 0)
>  		goto out_media_entity_cleanup;
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 29/32] et8ek8: Add support for flash and lens devices
  2017-10-26  7:53 ` [PATCH v16 29/32] et8ek8: " Sakari Ailus
@ 2017-10-29 23:05   ` Sebastian Reichel
  2017-11-12 11:27   ` et8ek8: Document " Pavel Machek
  1 sibling, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 23:05 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 1084 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:39AM +0300, Sakari Ailus wrote:
> Parse async sub-devices related to the sensor by switching the async
> sub-device registration function.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/i2c/et8ek8/et8ek8_driver.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/i2c/et8ek8/et8ek8_driver.c b/drivers/media/i2c/et8ek8/et8ek8_driver.c
> index c14f0fd6ded3..e9eff9039ef5 100644
> --- a/drivers/media/i2c/et8ek8/et8ek8_driver.c
> +++ b/drivers/media/i2c/et8ek8/et8ek8_driver.c
> @@ -1453,7 +1453,7 @@ static int et8ek8_probe(struct i2c_client *client,
>  		goto err_mutex;
>  	}
>  
> -	ret = v4l2_async_register_subdev(&sensor->subdev);
> +	ret = v4l2_async_register_subdev_sensor_common(&sensor->subdev);
>  	if (ret < 0)
>  		goto err_entity;
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 30/32] ov5670: Add support for flash and lens devices
  2017-10-26  7:53     ` Sakari Ailus
  (?)
@ 2017-10-29 23:05     ` Sebastian Reichel
  -1 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 23:05 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 1041 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:40AM +0300, Sakari Ailus wrote:
> Parse async sub-devices related to the sensor by switching the async
> sub-device registration function.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/i2c/ov5670.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/i2c/ov5670.c b/drivers/media/i2c/ov5670.c
> index a65469f88e36..9f9196568eb8 100644
> --- a/drivers/media/i2c/ov5670.c
> +++ b/drivers/media/i2c/ov5670.c
> @@ -2529,7 +2529,7 @@ static int ov5670_probe(struct i2c_client *client)
>  	}
>  
>  	/* Async register for subdev */
> -	ret = v4l2_async_register_subdev(&ov5670->sd);
> +	ret = v4l2_async_register_subdev_sensor_common(&ov5670->sd);
>  	if (ret < 0) {
>  		err_msg = "v4l2_async_register_subdev() error";
>  		goto error_entity_cleanup;
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 31/32] ov13858: Add support for flash and lens devices
  2017-10-26  7:53 ` [PATCH v16 31/32] ov13858: Add " Sakari Ailus
@ 2017-10-29 23:06       ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 23:06 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media-u79uwXL29TY76Z2rM5mHXA,
	niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw, pavel-+ZI9xUNit7I,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 1068 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:41AM +0300, Sakari Ailus wrote:
> Parse async sub-devices related to the sensor by switching the async
> sub-device registration function.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
> Acked-by: Hans Verkuil <hans.verkuil-FYB4Gu1CFyUAvxtiuMwx3w@public.gmane.org>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>

-- Sebastian

>  drivers/media/i2c/ov13858.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
> index fdce2befed02..bf7d06f3f21a 100644
> --- a/drivers/media/i2c/ov13858.c
> +++ b/drivers/media/i2c/ov13858.c
> @@ -1761,7 +1761,7 @@ static int ov13858_probe(struct i2c_client *client,
>  		goto error_handler_free;
>  	}
>  
> -	ret = v4l2_async_register_subdev(&ov13858->sd);
> +	ret = v4l2_async_register_subdev_sensor_common(&ov13858->sd);
>  	if (ret < 0)
>  		goto error_media_entity;
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 31/32] ov13858: Add support for flash and lens devices
@ 2017-10-29 23:06       ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 23:06 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 990 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:41AM +0300, Sakari Ailus wrote:
> Parse async sub-devices related to the sensor by switching the async
> sub-device registration function.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  drivers/media/i2c/ov13858.c | 2 +-
>  1 file changed, 1 insertion(+), 1 deletion(-)
> 
> diff --git a/drivers/media/i2c/ov13858.c b/drivers/media/i2c/ov13858.c
> index fdce2befed02..bf7d06f3f21a 100644
> --- a/drivers/media/i2c/ov13858.c
> +++ b/drivers/media/i2c/ov13858.c
> @@ -1761,7 +1761,7 @@ static int ov13858_probe(struct i2c_client *client,
>  		goto error_handler_free;
>  	}
>  
> -	ret = v4l2_async_register_subdev(&ov13858->sd);
> +	ret = v4l2_async_register_subdev_sensor_common(&ov13858->sd);
>  	if (ret < 0)
>  		goto error_media_entity;
>  
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16 32/32] arm: dts: omap3: N9/N950: Add flash references to the camera
  2017-10-26  7:53 ` [PATCH v16 32/32] arm: dts: omap3: N9/N950: Add flash references to the camera Sakari Ailus
@ 2017-10-29 23:08   ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-10-29 23:08 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, pavel, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 2269 bytes --]

Hi,

On Thu, Oct 26, 2017 at 10:53:42AM +0300, Sakari Ailus wrote:
> Add flash and indicator LED phandles to the sensor node.
> 
> Signed-off-by: Sakari Ailus <sakari.ailus@linux.intel.com>
> Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> Acked-by: Pavel Machek <pavel@ucw.cz>
> ---

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

>  arch/arm/boot/dts/omap3-n9.dts       | 1 +
>  arch/arm/boot/dts/omap3-n950-n9.dtsi | 4 ++--
>  arch/arm/boot/dts/omap3-n950.dts     | 1 +
>  3 files changed, 4 insertions(+), 2 deletions(-)
> 
> diff --git a/arch/arm/boot/dts/omap3-n9.dts b/arch/arm/boot/dts/omap3-n9.dts
> index b9e58c536afd..39e35f8b8206 100644
> --- a/arch/arm/boot/dts/omap3-n9.dts
> +++ b/arch/arm/boot/dts/omap3-n9.dts
> @@ -26,6 +26,7 @@
>  		clocks = <&isp 0>;
>  		clock-frequency = <9600000>;
>  		nokia,nvm-size = <(16 * 64)>;
> +		flash-leds = <&as3645a_flash &as3645a_indicator>;
>  		port {
>  			smia_1_1: endpoint {
>  				link-frequencies = /bits/ 64 <199200000 210000000 499200000>;
> diff --git a/arch/arm/boot/dts/omap3-n950-n9.dtsi b/arch/arm/boot/dts/omap3-n950-n9.dtsi
> index 1b0bd72945f2..12fbb3da5fce 100644
> --- a/arch/arm/boot/dts/omap3-n950-n9.dtsi
> +++ b/arch/arm/boot/dts/omap3-n950-n9.dtsi
> @@ -271,14 +271,14 @@
>  		#size-cells = <0>;
>  		reg = <0x30>;
>  		compatible = "ams,as3645a";
> -		flash@0 {
> +		as3645a_flash: flash@0 {
>  			reg = <0x0>;
>  			flash-timeout-us = <150000>;
>  			flash-max-microamp = <320000>;
>  			led-max-microamp = <60000>;
>  			ams,input-max-microamp = <1750000>;
>  		};
> -		indicator@1 {
> +		as3645a_indicator: indicator@1 {
>  			reg = <0x1>;
>  			led-max-microamp = <10000>;
>  		};
> diff --git a/arch/arm/boot/dts/omap3-n950.dts b/arch/arm/boot/dts/omap3-n950.dts
> index 646601a3ebd8..c354a1ed1e70 100644
> --- a/arch/arm/boot/dts/omap3-n950.dts
> +++ b/arch/arm/boot/dts/omap3-n950.dts
> @@ -60,6 +60,7 @@
>  		clocks = <&isp 0>;
>  		clock-frequency = <9600000>;
>  		nokia,nvm-size = <(16 * 64)>;
> +		flash-leds = <&as3645a_flash &as3645a_indicator>;
>  		port {
>  			smia_1_1: endpoint {
>  				link-frequencies = /bits/ 64 <210000000 333600000 398400000>;
> -- 
> 2.11.0
> 

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: [PATCH v16.1 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers
  2017-10-29 22:25     ` Sebastian Reichel
@ 2017-10-30 13:05       ` Sakari Ailus
  0 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-30 13:05 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Sakari Ailus, linux-media, niklas.soderlund, maxime.ripard,
	hverkuil, laurent.pinchart, pavel

Hi Sebastian,

On Sun, Oct 29, 2017 at 11:25:55PM +0100, Sebastian Reichel wrote:
> Hi,
> 
> On Fri, Oct 27, 2017 at 01:53:09PM +0300, Sakari Ailus wrote:
> > 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>
> > Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
> > Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
> > ---
> >  drivers/media/v4l2-core/v4l2-async.c | 89 ++++++++++++++++++++++++++++++++----
> >  1 file changed, 81 insertions(+), 8 deletions(-)
> > 
> > diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
> > index ed539c4fd5dc..a33a68e5417b 100644
> > --- a/drivers/media/v4l2-core/v4l2-async.c
> > +++ b/drivers/media/v4l2-core/v4l2-async.c
> > @@ -308,8 +308,71 @@ static void v4l2_async_notifier_unbind_all_subdevs(
> >  	notifier->parent = NULL;
> >  }
> >  
> > +/* See if an fwnode can be found in a notifier's lists. */
> > +static bool __v4l2_async_notifier_fwnode_has_async_subdev(
> > +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
> > +{
> > +	struct v4l2_async_subdev *asd;
> > +	struct v4l2_subdev *sd;
> > +
> > +	list_for_each_entry(asd, &notifier->waiting, list) {
> > +		if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> > +			continue;
> > +
> > +		if (asd->match.fwnode.fwnode == fwnode)
> > +			return true;
> > +	}
> > +
> > +	list_for_each_entry(sd, &notifier->done, async_list) {
> > +		if (WARN_ON(!sd->asd))
> > +			continue;
> > +
> > +		if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
> > +			continue;
> > +
> > +		if (sd->asd->match.fwnode.fwnode == fwnode)
> > +			return true;
> > +	}
> > +
> > +	return false;
> > +}
> > +
> > +/*
> > + * Find out whether an async sub-device was set up for an fwnode already or
> > + * whether it exists in a given notifier before @this_index.
> > + */
> > +static bool v4l2_async_notifier_fwnode_has_async_subdev(
> > +	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
> > +	unsigned int this_index)
> > +{
> > +	unsigned int j;
> > +
> > +	lockdep_assert_held(&list_lock);
> > +
> > +	/* Check that an fwnode is not being added more than once. */
> > +	for (j = 0; j < this_index; j++) {
> > +		struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
> > +		struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
> > +
> > +		if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
> > +		    asd->match.fwnode.fwnode ==
> > +		    other_asd->match.fwnode.fwnode)
> > +			return true;
> > +	}
> > +
> > +	/* Check than an fwnode did not exist in other notifiers. */
> > +	list_for_each_entry(notifier, &notifier_list, list)
> > +		if (__v4l2_async_notifier_fwnode_has_async_subdev(
> > +			    notifier, fwnode))
> > +			return true;
> > +
> > +	return false;
> > +}
> > +
> >  static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  {
> > +	struct device *dev =
> > +		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
> >  	struct v4l2_async_subdev *asd;
> >  	int ret;
> >  	int i;
> > @@ -320,6 +383,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  	INIT_LIST_HEAD(&notifier->waiting);
> >  	INIT_LIST_HEAD(&notifier->done);
> >  
> > +	mutex_lock(&list_lock);
> > +
> >  	for (i = 0; i < notifier->num_subdevs; i++) {
> >  		asd = notifier->subdevs[i];
> >  
> > @@ -327,33 +392,41 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
> >  		case V4L2_ASYNC_MATCH_CUSTOM:
> >  		case V4L2_ASYNC_MATCH_DEVNAME:
> >  		case V4L2_ASYNC_MATCH_I2C:
> > +			break;
> >  		case V4L2_ASYNC_MATCH_FWNODE:
> > +			if (v4l2_async_notifier_fwnode_has_async_subdev(
> > +				    notifier, asd->match.fwnode.fwnode, i)) {
> > +				dev_err(dev,
> > +					"fwnode has already been registered or in notifier's subdev list\n");
> > +				ret = -EEXIST;
> > +				goto out_unlock;
> > +			}
> >  			break;
> >  		default:
> > -			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
> > -				"Invalid match type %u on %p\n",
> > +			dev_err(dev, "Invalid match type %u on %p\n",
> >  				asd->match_type, asd);
> > -			return -EINVAL;
> > +			ret = -EINVAL;
> > +			goto out_unlock;
> >  		}
> >  		list_add_tail(&asd->list, &notifier->waiting);
> >  	}
> >  
> > -	mutex_lock(&list_lock);
> > -
> >  	ret = v4l2_async_notifier_try_all_subdevs(notifier);
> > -	if (ret)
> > +	if (ret < 0)
> >  		goto err_unbind;
> 
> the error path does no unlock?

It does; however the two paths were introduced as the other always returned
zero. So the result is rather less clean after fixing the bug, let me clean
this up...

> 
> >  	ret = v4l2_async_notifier_try_complete(notifier);
> > -	if (ret)
> > +	if (ret < 0)
> >  		goto err_unbind;
> 
> dito
> 
> > +	ret = 0;
> >  
> >  	/* Keep also completed notifiers on the list */
> >  	list_add(&notifier->list, &notifier_list);
> >  
> > +out_unlock:
> >  	mutex_unlock(&list_lock);
> >  
> > -	return 0;
> > +	return ret;
> >  
> >  err_unbind:
> >  	/*
> 
> Otherwise:
> 
> Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

Thanks!

-- 
Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 107+ messages in thread

* [PATCH v16.2 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers
  2017-10-27 10:53   ` [PATCH v16.1 " Sakari Ailus
  2017-10-29 22:25     ` Sebastian Reichel
@ 2017-10-30 13:09     ` Sakari Ailus
  1 sibling, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-10-30 13:09 UTC (permalink / raw)
  To: linux-media
  Cc: niklas.soderlund, maxime.ripard, hverkuil, laurent.pinchart, pavel, sre

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>
Acked-by: Hans Verkuil <hans.verkuil@cisco.com>
Acked-by: Niklas Söderlund <niklas.soderlund+renesas@ragnatech.se>
Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>
---
since v16.1:

- Clean up error handling; there's now only a single error path, not two.

 drivers/media/v4l2-core/v4l2-async.c | 86 +++++++++++++++++++++++++++++++++---
 1 file changed, 79 insertions(+), 7 deletions(-)

diff --git a/drivers/media/v4l2-core/v4l2-async.c b/drivers/media/v4l2-core/v4l2-async.c
index ed539c4fd5dc..57bd54016064 100644
--- a/drivers/media/v4l2-core/v4l2-async.c
+++ b/drivers/media/v4l2-core/v4l2-async.c
@@ -308,8 +308,71 @@ static void v4l2_async_notifier_unbind_all_subdevs(
 	notifier->parent = NULL;
 }
 
+/* See if an fwnode can be found in a notifier's lists. */
+static bool __v4l2_async_notifier_fwnode_has_async_subdev(
+	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode)
+{
+	struct v4l2_async_subdev *asd;
+	struct v4l2_subdev *sd;
+
+	list_for_each_entry(asd, &notifier->waiting, list) {
+		if (asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
+			continue;
+
+		if (asd->match.fwnode.fwnode == fwnode)
+			return true;
+	}
+
+	list_for_each_entry(sd, &notifier->done, async_list) {
+		if (WARN_ON(!sd->asd))
+			continue;
+
+		if (sd->asd->match_type != V4L2_ASYNC_MATCH_FWNODE)
+			continue;
+
+		if (sd->asd->match.fwnode.fwnode == fwnode)
+			return true;
+	}
+
+	return false;
+}
+
+/*
+ * Find out whether an async sub-device was set up for an fwnode already or
+ * whether it exists in a given notifier before @this_index.
+ */
+static bool v4l2_async_notifier_fwnode_has_async_subdev(
+	struct v4l2_async_notifier *notifier, struct fwnode_handle *fwnode,
+	unsigned int this_index)
+{
+	unsigned int j;
+
+	lockdep_assert_held(&list_lock);
+
+	/* Check that an fwnode is not being added more than once. */
+	for (j = 0; j < this_index; j++) {
+		struct v4l2_async_subdev *asd = notifier->subdevs[this_index];
+		struct v4l2_async_subdev *other_asd = notifier->subdevs[j];
+
+		if (other_asd->match_type == V4L2_ASYNC_MATCH_FWNODE &&
+		    asd->match.fwnode.fwnode ==
+		    other_asd->match.fwnode.fwnode)
+			return true;
+	}
+
+	/* Check than an fwnode did not exist in other notifiers. */
+	list_for_each_entry(notifier, &notifier_list, list)
+		if (__v4l2_async_notifier_fwnode_has_async_subdev(
+			    notifier, fwnode))
+			return true;
+
+	return false;
+}
+
 static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 {
+	struct device *dev =
+		notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL;
 	struct v4l2_async_subdev *asd;
 	int ret;
 	int i;
@@ -320,6 +383,8 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	INIT_LIST_HEAD(&notifier->waiting);
 	INIT_LIST_HEAD(&notifier->done);
 
+	mutex_lock(&list_lock);
+
 	for (i = 0; i < notifier->num_subdevs; i++) {
 		asd = notifier->subdevs[i];
 
@@ -327,25 +392,31 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 		case V4L2_ASYNC_MATCH_CUSTOM:
 		case V4L2_ASYNC_MATCH_DEVNAME:
 		case V4L2_ASYNC_MATCH_I2C:
+			break;
 		case V4L2_ASYNC_MATCH_FWNODE:
+			if (v4l2_async_notifier_fwnode_has_async_subdev(
+				    notifier, asd->match.fwnode.fwnode, i)) {
+				dev_err(dev,
+					"fwnode has already been registered or in notifier's subdev list\n");
+				ret = -EEXIST;
+				goto err_unlock;
+			}
 			break;
 		default:
-			dev_err(notifier->v4l2_dev ? notifier->v4l2_dev->dev : NULL,
-				"Invalid match type %u on %p\n",
+			dev_err(dev, "Invalid match type %u on %p\n",
 				asd->match_type, asd);
-			return -EINVAL;
+			ret = -EINVAL;
+			goto err_unlock;
 		}
 		list_add_tail(&asd->list, &notifier->waiting);
 	}
 
-	mutex_lock(&list_lock);
-
 	ret = v4l2_async_notifier_try_all_subdevs(notifier);
-	if (ret)
+	if (ret < 0)
 		goto err_unbind;
 
 	ret = v4l2_async_notifier_try_complete(notifier);
-	if (ret)
+	if (ret < 0)
 		goto err_unbind;
 
 	/* Keep also completed notifiers on the list */
@@ -361,6 +432,7 @@ static int __v4l2_async_notifier_register(struct v4l2_async_notifier *notifier)
 	 */
 	v4l2_async_notifier_unbind_all_subdevs(notifier);
 
+err_unlock:
 	mutex_unlock(&list_lock);
 
 	return ret;
-- 
2.11.0

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* et8ek8: Document support for flash and lens devices
  2017-10-26  7:53 ` [PATCH v16 29/32] et8ek8: " Sakari Ailus
  2017-10-29 23:05   ` Sebastian Reichel
@ 2017-11-12 11:27   ` Pavel Machek
  2017-11-12 14:25       ` Sebastian Reichel
  1 sibling, 1 reply; 107+ messages in thread
From: Pavel Machek @ 2017-11-12 11:27 UTC (permalink / raw)
  To: Sakari Ailus
  Cc: linux-media, niklas.soderlund, maxime.ripard, hverkuil,
	laurent.pinchart, sre, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 872 bytes --]


Document dts support of LED/focus.

Signed-off-by: Pavel Machek <pavel@ucw.cz>

diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
index 0b7b6a4..e80d589 100644
--- a/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
+++ b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
@@ -20,6 +20,13 @@ Mandatory properties
   is in hardware standby mode when the signal is in the low state.
 
 
+Optional properties
+-------------------
+
+- flash-leds: See ../video-interfaces.txt
+- lens-focus: See ../video-interfaces.txt
+
+
 Endpoint node mandatory properties
 ----------------------------------
 
-- 
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html

[-- Attachment #2: Digital signature --]
[-- Type: application/pgp-signature, Size: 181 bytes --]

^ permalink raw reply related	[flat|nested] 107+ messages in thread

* Re: et8ek8: Document support for flash and lens devices
  2017-11-12 11:27   ` et8ek8: Document " Pavel Machek
@ 2017-11-12 14:25       ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-11-12 14:25 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Sakari Ailus, linux-media-u79uwXL29TY76Z2rM5mHXA,
	niklas.soderlund-1zkq55x86MTxsAP9Fp7wbw,
	maxime.ripard-wi1+55ScJUtKEb57/3fJTNBPR1lH4CV8,
	hverkuil-qWit8jRvyhVmR6Xm/wNWPw,
	laurent.pinchart-ryLnwIuWjnjg/C1BVhZhaw,
	linux-acpi-u79uwXL29TY76Z2rM5mHXA,
	devicetree-u79uwXL29TY76Z2rM5mHXA

[-- Attachment #1: Type: text/plain, Size: 1128 bytes --]

Hi,

On Sun, Nov 12, 2017 at 12:27:29PM +0100, Pavel Machek wrote:
> 
> Document dts support of LED/focus.
> 
> Signed-off-by: Pavel Machek <pavel-+ZI9xUNit7I@public.gmane.org>

Reviewed-by: Sebastian Reichel <sebastian.reichel-ZGY8ohtN/8pPYcu2f3hruQ@public.gmane.org>

-- Sebastian

> diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
> index 0b7b6a4..e80d589 100644
> --- a/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
> +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
> @@ -20,6 +20,13 @@ Mandatory properties
>    is in hardware standby mode when the signal is in the low state.
>  
>  
> +Optional properties
> +-------------------
> +
> +- flash-leds: See ../video-interfaces.txt
> +- lens-focus: See ../video-interfaces.txt
> +
> +
>  Endpoint node mandatory properties
>  ----------------------------------
>  
> -- 
> (english) http://www.livejournal.com/~pavelmachek
> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html



[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: et8ek8: Document support for flash and lens devices
@ 2017-11-12 14:25       ` Sebastian Reichel
  0 siblings, 0 replies; 107+ messages in thread
From: Sebastian Reichel @ 2017-11-12 14:25 UTC (permalink / raw)
  To: Pavel Machek
  Cc: Sakari Ailus, linux-media, niklas.soderlund, maxime.ripard,
	hverkuil, laurent.pinchart, linux-acpi, devicetree

[-- Attachment #1: Type: text/plain, Size: 1082 bytes --]

Hi,

On Sun, Nov 12, 2017 at 12:27:29PM +0100, Pavel Machek wrote:
> 
> Document dts support of LED/focus.
> 
> Signed-off-by: Pavel Machek <pavel@ucw.cz>

Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

-- Sebastian

> diff --git a/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
> index 0b7b6a4..e80d589 100644
> --- a/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
> +++ b/Documentation/devicetree/bindings/media/i2c/toshiba,et8ek8.txt
> @@ -20,6 +20,13 @@ Mandatory properties
>    is in hardware standby mode when the signal is in the low state.
>  
>  
> +Optional properties
> +-------------------
> +
> +- flash-leds: See ../video-interfaces.txt
> +- lens-focus: See ../video-interfaces.txt
> +
> +
>  Endpoint node mandatory properties
>  ----------------------------------
>  
> -- 
> (english) http://www.livejournal.com/~pavelmachek
> (cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html



[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 833 bytes --]

^ permalink raw reply	[flat|nested] 107+ messages in thread

* Re: et8ek8: Document support for flash and lens devices
  2017-11-12 14:25       ` Sebastian Reichel
  (?)
@ 2017-11-13 17:05       ` Sakari Ailus
  -1 siblings, 0 replies; 107+ messages in thread
From: Sakari Ailus @ 2017-11-13 17:05 UTC (permalink / raw)
  To: Sebastian Reichel
  Cc: Pavel Machek, Sakari Ailus, linux-media, niklas.soderlund,
	maxime.ripard, hverkuil, laurent.pinchart, linux-acpi,
	devicetree

On Sun, Nov 12, 2017 at 03:25:47PM +0100, Sebastian Reichel wrote:
> Hi,
> 
> On Sun, Nov 12, 2017 at 12:27:29PM +0100, Pavel Machek wrote:
> > 
> > Document dts support of LED/focus.
> > 
> > Signed-off-by: Pavel Machek <pavel@ucw.cz>
> 
> Reviewed-by: Sebastian Reichel <sebastian.reichel@collabora.co.uk>

Thanks, guys!

Applied, with "dt-bindings: " prefix added to the subject.

-- 
Sakari Ailus
e-mail: sakari.ailus@iki.fi

^ permalink raw reply	[flat|nested] 107+ messages in thread

end of thread, other threads:[~2017-11-13 17:05 UTC | newest]

Thread overview: 107+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-10-26  7:53 [PATCH v16 00/32] Unified fwnode endpoint parser, async sub-device notifier support, N9 flash DTS Sakari Ailus
2017-10-26  7:53 ` Sakari Ailus
2017-10-26  7:53 ` [PATCH v16 01/32] v4l: async: Remove re-probing support Sakari Ailus
2017-10-26 15:20   ` Niklas Söderlund
2017-10-26  7:53 ` [PATCH v16 02/32] v4l: async: Don't set sd->dev NULL in v4l2_async_cleanup Sakari Ailus
     [not found]   ` <20171026075342.5760-3-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-26 15:23     ` Niklas Söderlund
2017-10-26 15:23       ` Niklas Söderlund
2017-10-26  7:53 ` [PATCH v16 03/32] v4l: async: fix unbind error in v4l2_async_notifier_unregister() Sakari Ailus
2017-10-26  7:53 ` [PATCH v16 05/32] v4l: async: Correctly serialise async sub-device unregistration Sakari Ailus
     [not found]   ` <20171026075342.5760-6-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-26 15:38     ` Niklas Söderlund
2017-10-26 15:38       ` Niklas Söderlund
2017-10-26  7:53 ` [PATCH v16 07/32] v4l: async: Add V4L2 async documentation to the documentation build Sakari Ailus
2017-10-26  7:53 ` [PATCH v16 08/32] v4l: fwnode: Support generic parsing of graph endpoints in a device Sakari Ailus
2017-10-26 21:35   ` Niklas Söderlund
2017-10-26  7:53 ` [PATCH v16 09/32] omap3isp: Use generic parser for parsing fwnode endpoints Sakari Ailus
     [not found]   ` <20171026075342.5760-10-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-27 14:46     ` Sebastian Reichel
2017-10-27 14:46       ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 10/32] rcar-vin: " Sakari Ailus
2017-10-26  7:53 ` [PATCH v16 11/32] omap3isp: Fix check for our own sub-devices Sakari Ailus
2017-10-27 14:47   ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 12/32] omap3isp: Print the name of the entity where no source pads could be found Sakari Ailus
2017-10-27 14:47   ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 13/32] v4l: async: Move async subdev notifier operations to a separate structure Sakari Ailus
2017-10-26 21:44   ` Niklas Söderlund
2017-10-27 14:47   ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 14/32] v4l: async: Introduce helpers for calling async ops callbacks Sakari Ailus
2017-10-26 21:46   ` Niklas Söderlund
2017-10-27 14:48   ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 15/32] v4l: async: Register sub-devices before calling bound callback Sakari Ailus
     [not found]   ` <20171026075342.5760-16-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-26 21:52     ` Niklas Söderlund
2017-10-26 21:52       ` Niklas Söderlund
2017-10-27 14:49   ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 16/32] v4l: async: Allow async notifier register call succeed with no subdevs Sakari Ailus
     [not found]   ` <20171026075342.5760-17-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-26 22:00     ` Niklas Söderlund
2017-10-26 22:00       ` Niklas Söderlund
2017-10-27 14:49     ` Sebastian Reichel
2017-10-27 14:49       ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 17/32] v4l: async: Prepare for async sub-device notifiers Sakari Ailus
2017-10-26 22:10   ` Niklas Söderlund
2017-10-27  8:10     ` Niklas Söderlund
2017-10-27  8:30       ` Sakari Ailus
2017-10-27  8:26   ` [PATCH v16.1 " Sakari Ailus
2017-10-27  8:36     ` Niklas Söderlund
2017-10-27 14:50     ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 18/32] v4l: async: Allow binding notifiers to sub-devices Sakari Ailus
2017-10-27  8:27   ` [PATCH v16.1 " Sakari Ailus
2017-10-27  8:44     ` Niklas Söderlund
2017-10-29 22:19     ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 19/32] v4l: async: Ensure only unique fwnodes are registered to notifiers Sakari Ailus
2017-10-27  9:52   ` Niklas Söderlund
     [not found]     ` <20171027095227.GA8854-ofJ5d6taAgIKcZgyrm77+z0dHWC0CY5B@public.gmane.org>
2017-10-27 10:06       ` Sakari Ailus
2017-10-27 10:06         ` Sakari Ailus
2017-10-27 10:26         ` Niklas Söderlund
2017-10-27 10:53   ` [PATCH v16.1 " Sakari Ailus
2017-10-29 22:25     ` Sebastian Reichel
2017-10-30 13:05       ` Sakari Ailus
2017-10-30 13:09     ` [PATCH v16.2 " Sakari Ailus
2017-10-26  7:53 ` [PATCH v16 20/32] dt: bindings: Add a binding for flash LED devices associated to a sensor Sakari Ailus
     [not found]   ` <20171026075342.5760-21-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-29 22:26     ` Sebastian Reichel
2017-10-29 22:26       ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 21/32] dt: bindings: Add lens-focus binding for image sensors Sakari Ailus
2017-10-26  7:53 ` [PATCH v16 22/32] v4l: fwnode: Move KernelDoc documentation to the header Sakari Ailus
2017-10-29 22:28   ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 23/32] v4l: fwnode: Add a helper function for parsing generic references Sakari Ailus
2017-10-27 10:30   ` Niklas Söderlund
2017-10-29 22:53   ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 24/32] v4l: fwnode: Add a helper function to obtain device / integer references Sakari Ailus
2017-10-26 15:01   ` [PATCH v16.1 " Sakari Ailus
2017-10-29 22:58     ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 25/32] v4l: fwnode: Add convenience function for parsing common external refs Sakari Ailus
2017-10-26 15:03   ` [PATCH v16.1 " Sakari Ailus
2017-10-29 23:00     ` Sebastian Reichel
     [not found] ` <20171026075342.5760-1-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-26  7:53   ` [PATCH v16 04/32] v4l: async: Fix notifier complete callback error handling Sakari Ailus
2017-10-26  7:53     ` Sakari Ailus
     [not found]     ` <20171026075342.5760-5-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-26 15:34       ` Niklas Söderlund
2017-10-26 15:34         ` Niklas Söderlund
2017-10-27 14:46     ` Sebastian Reichel
2017-10-26  7:53   ` [PATCH v16 06/32] v4l: async: Use more intuitive names for internal functions Sakari Ailus
2017-10-26  7:53     ` Sakari Ailus
     [not found]     ` <20171026075342.5760-7-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-26 15:39       ` Niklas Söderlund
2017-10-26 15:39         ` Niklas Söderlund
2017-10-26  7:53   ` [PATCH v16 26/32] v4l: fwnode: Add a convenience function for registering sensors Sakari Ailus
2017-10-26  7:53     ` Sakari Ailus
2017-10-27 13:06     ` Niklas Söderlund
2017-10-29 23:02     ` Sebastian Reichel
2017-10-26  7:53   ` [PATCH v16 27/32] dt: bindings: smiapp: Document lens-focus and flash-leds properties Sakari Ailus
2017-10-26  7:53     ` Sakari Ailus
2017-10-27 14:38     ` Rob Herring
     [not found]     ` <20171026075342.5760-28-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-29 23:03       ` Sebastian Reichel
2017-10-29 23:03         ` Sebastian Reichel
2017-10-26  7:53   ` [PATCH v16 28/32] smiapp: Add support for flash and lens devices Sakari Ailus
2017-10-26  7:53     ` Sakari Ailus
2017-10-29 23:04     ` Sebastian Reichel
2017-10-26  7:53   ` [PATCH v16 30/32] ov5670: " Sakari Ailus
2017-10-26  7:53     ` Sakari Ailus
2017-10-29 23:05     ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 29/32] et8ek8: " Sakari Ailus
2017-10-29 23:05   ` Sebastian Reichel
2017-11-12 11:27   ` et8ek8: Document " Pavel Machek
2017-11-12 14:25     ` Sebastian Reichel
2017-11-12 14:25       ` Sebastian Reichel
2017-11-13 17:05       ` Sakari Ailus
2017-10-26  7:53 ` [PATCH v16 31/32] ov13858: Add " Sakari Ailus
     [not found]   ` <20171026075342.5760-32-sakari.ailus-VuQAYsv1563Yd54FQh9/CA@public.gmane.org>
2017-10-29 23:06     ` Sebastian Reichel
2017-10-29 23:06       ` Sebastian Reichel
2017-10-26  7:53 ` [PATCH v16 32/32] arm: dts: omap3: N9/N950: Add flash references to the camera Sakari Ailus
2017-10-29 23:08   ` Sebastian Reichel

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.