Hi Jacopo,
On Wed, Dec 13, 2017 at 07:26:20PM +0100, Jacopo Mondi wrote:
> The v4l2-async module operations are quite complex to follow, due to the
> asynchronous nature of subdevices and notifiers registration and
> matching procedures. In order to help with debugging of failed or
> erroneous matching between a subdevice and the notifier collected
> async_subdevice it gets matched against, introduce a few dev_dbg() calls
> in v4l2_async core operations.
>
> Protect the debug operations with a Kconfig defined symbol, to make sure
> when debugging is disabled, no additional code or data is added to the
> module.
>
> Notifiers are identified by the name of the subdevice or v4l2_dev they are
> registered by, while subdevice matching which now happens on endpoints,
> need a longer description built walking the fwnode graph backwards
> collecting parent nodes names (otherwise we would have had printouts
> like: "Matching "endpoint" with "endpoint"" which are not that useful).
>
> Signed-off-by: Jacopo Mondi <[email protected]>
>
> ---
> For fwnodes backed by OF, I may have used the "%pOF" format modifier to
> get the full node name instead of parsing the fwnode graph by myself with
> "v4l2_async_fwnode_full_name()". Unfortunately I'm not aware of anything
> like "%pOF" for ACPI backed fwnodes. Also, walking the fwnode graph by
> myself allows me to reduce the depth, to reduce the debug messages output
> length which is anyway long enough to result disturbing on a 80columns
> terminal window.
ACPI doesn't have such at the moment. I think printing the full path would
still be better. There isn't that much more to print after all.
> ---
>
> drivers/media/v4l2-core/Kconfig | 8 ++++
> drivers/media/v4l2-core/v4l2-async.c | 81
> ++++++++++++++++++++++++++++++++++++
> 2 files changed, 89 insertions(+)
>
> diff --git a/drivers/media/v4l2-core/Kconfig b/drivers/media/v4l2-core/Kconfig
> index a35c336..8331736 100644
> --- a/drivers/media/v4l2-core/Kconfig
> +++ b/drivers/media/v4l2-core/Kconfig
> @@ -17,6 +17,14 @@ config VIDEO_ADV_DEBUG
> V4L devices.
> In doubt, say N.
>
> +config VIDEO_V4L2_ASYNC_DEBUG
> + bool "Enable debug functionalities for V4L2 async module"
> + depends on VIDEO_V4L2
I'm not sure I'd add a Kconfig option. This is adding a fairly simple
function only to the kernel.
> + default n
> + ---help---
> + Say Y here to enable debug output in V4L2 async module.
> + In doubt, say N.
> +
> config VIDEO_FIXED_MINOR_RANGES
> bool "Enable old-style fixed minor ranges on drivers/video devices"
> default n
> diff --git a/drivers/media/v4l2-core/v4l2-async.c
> b/drivers/media/v4l2-core/v4l2-async.c
> index c13a781..307e1a5 100644
> --- a/drivers/media/v4l2-core/v4l2-async.c
> +++ b/drivers/media/v4l2-core/v4l2-async.c
> @@ -8,6 +8,10 @@
> * published by the Free Software Foundation.
> */
>
> +#if defined(CONFIG_VIDEO_V4L2_ASYNC_DEBUG)
> +#define DEBUG
Do you need this?
> +#endif
> +
> #include <linux/device.h>
> #include <linux/err.h>
> #include <linux/i2c.h>
> @@ -25,6 +29,52 @@
> #include <media/v4l2-fwnode.h>
> #include <media/v4l2-subdev.h>
>
> +#if defined(CONFIG_VIDEO_V4L2_ASYNC_DEBUG)
> +#define V4L2_ASYNC_FWNODE_NAME_LEN 512
> +
> +static void __v4l2_async_fwnode_full_name(char *name,
> + unsigned int len,
> + unsigned int max_depth,
> + struct fwnode_handle *fwnode)
> +{
> + unsigned int buf_len = len < V4L2_ASYNC_FWNODE_NAME_LEN ?
> + len : V4L2_ASYNC_FWNODE_NAME_LEN;
> + char __tmp[V4L2_ASYNC_FWNODE_NAME_LEN];
That's a bit too much to allocate from the stack I think.
> + struct fwnode_handle *parent;
> +
> + memset(name, 0, buf_len);
> + buf_len -= snprintf(__tmp, buf_len, "%s", fwnode_get_name(fwnode));
> +
> + parent = fwnode;
> + while ((parent = fwnode_get_parent(parent)) && buf_len &&
> + --max_depth) {
> + buf_len -= snprintf(name, buf_len, "%s/%s",
> + fwnode_get_name(parent), __tmp);
> + strcpy(__tmp, name);
> + }
> +}
> +
> +static void v4l2_async_fwnode_full_name(char *name,
> + unsigned int len,
> + struct fwnode_handle *fwnode)
> +{
> + /*
> + * Usually 4 as nesting level is sufficient to identify an
> + * endpoint firmware node uniquely.
> + */
> + __v4l2_async_fwnode_full_name(name, len, 4, fwnode);
> +}
> +
> +#else /* CONFIG_VIDEO_V4L2_ASYNC_DEBUG */
> +#define V4L2_ASYNC_FWNODE_NAME_LEN 0
> +
> +static void v4l2_async_fwnode_full_name(char *name,
> + unsigned int len,
> + struct fwnode_handle *fwnode)
> +{
> +}
> +#endif /* CONFIG_VIDEO_V4L2_ASYNC_DEBUG */
> +
> static struct device *v4l2_async_notifier_dev(
> struct v4l2_async_notifier *notifier)
> {
> @@ -54,9 +104,12 @@ static void v4l2_async_notifier_call_unbind(struct
> v4l2_async_notifier *n,
>
> static int v4l2_async_notifier_call_complete(struct v4l2_async_notifier *n)
> {
> + struct device *dev = v4l2_async_notifier_dev(n);
> if (!n->ops || !n->ops->complete)
> return 0;
>
> + dev_dbg(dev, "Complete notifier \"%s\"\n", fwnode_get_name(n->owner));
> +
> return n->ops->complete(n);
> }
>
> @@ -100,8 +153,17 @@ 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 device *dev = v4l2_async_notifier_dev(notifier);
> + char asd_full_name[V4L2_ASYNC_FWNODE_NAME_LEN];
> + char sd_full_name[V4L2_ASYNC_FWNODE_NAME_LEN];
> struct v4l2_async_subdev *asd;
>
> + v4l2_async_fwnode_full_name(sd_full_name, V4L2_ASYNC_FWNODE_NAME_LEN,
> + sd->fwnode);
> +
> + dev_dbg(dev, "Match notifier \"%s\" with subdevice \"%s\"\n",
> + fwnode_get_name(notifier->owner), sd_full_name);
> +
> list_for_each_entry(asd, ¬ifier->waiting, list) {
> /* bus_type has been verified valid before */
> switch (asd->match_type) {
> @@ -115,6 +177,11 @@ static struct v4l2_async_subdev *v4l2_async_find_match(
> match = match_i2c;
> break;
> case V4L2_ASYNC_MATCH_FWNODE:
> + v4l2_async_fwnode_full_name(asd_full_name,
> + V4L2_ASYNC_FWNODE_NAME_LEN,
> + asd->match.fwnode.fwnode);
> + dev_dbg(dev, "Test sd \"%s\" with async_sd \"%s\"\n",
> + sd_full_name, asd_full_name);
> match = match_fwnode;
> break;
> default:
> @@ -198,9 +265,16 @@ static int v4l2_async_match_notify(struct
> v4l2_async_notifier *notifier,
> struct v4l2_subdev *sd,
> struct v4l2_async_subdev *asd)
> {
> + struct device *dev = v4l2_async_notifier_dev(notifier);
> struct v4l2_async_notifier *subdev_notifier;
> + char sd_full_name[V4L2_ASYNC_FWNODE_NAME_LEN];
> int ret;
>
> + v4l2_async_fwnode_full_name(sd_full_name, V4L2_ASYNC_FWNODE_NAME_LEN,
> + sd->fwnode);
> + dev_dbg(dev, "Matched sd: \"%s\" with notifier \"%s\"\n",
> + sd_full_name, fwnode_get_name(notifier->owner));
> +
> ret = v4l2_device_register_subdev(v4l2_dev, sd);
> if (ret < 0)
> return ret;
> @@ -240,6 +314,7 @@ static int v4l2_async_match_notify(struct
> v4l2_async_notifier *notifier,
> static int v4l2_async_notifier_try_all_subdevs(
> struct v4l2_async_notifier *notifier)
> {
> + struct device *dev = v4l2_async_notifier_dev(notifier);
> struct v4l2_device *v4l2_dev =
> v4l2_async_notifier_find_v4l2_dev(notifier);
> struct v4l2_subdev *sd;
> @@ -247,6 +322,9 @@ static int v4l2_async_notifier_try_all_subdevs(
> if (!v4l2_dev)
> return 0;
>
> + dev_dbg(dev, "Testing notifier \"%s\" against all subdevices\n",
> + fwnode_get_name(notifier->owner));
> +
> again:
> list_for_each_entry(sd, &subdev_list, async_list) {
> struct v4l2_async_subdev *asd;
> @@ -378,6 +456,9 @@ static int __v4l2_async_notifier_register(struct
> v4l2_async_notifier *notifier)
>
> notifier->owner = dev_fwnode(dev);
>
> + dev_dbg(dev, "Registering notifier \"%s\"\n",
> + fwnode_get_name(notifier->owner));
> +
> mutex_lock(&list_lock);
>
> for (i = 0; i < notifier->num_subdevs; i++) {
> --
> 2.7.4
>
--
Sakari Ailus
[email protected]