[PATCH v2 03/15] iio: inkern: only return error codes in iio_channel_get_*() APIs
Andy Shevchenko
andy.shevchenko at gmail.com
Mon Jul 11 06:29:53 PDT 2022
On Mon, Jul 11, 2022 at 2:38 PM Nuno Sá <nuno.sa at analog.com> wrote:
>
> APIs like of_iio_channel_get_by_name() and of_iio_channel_get_all() were
> returning a mix of NULL and pointers with NULL being the way to
> "notify" that we should do a "system" lookup for channels. This make
> it very confusing and prone to errors as commit 9f63cc0921ec
> ("iio: inkern: fix return value in devm_of_iio_channel_get_by_name()")
> proves. On top of this, patterns like 'if (channel != NULL) return
> channel' were being used where channel could actually be an error code
> which makes the code hard to read.
>
> This change also makes some functional changes on how errors were being
> handled. In the original behavior, even if we get an error like '-ENOMEM',
> we still continue with the search. We should only continue to lookup for
> the channel when it makes sense to do so. Hence, the main error handling
> in 'of_iio_channel_get_by_name()' is changed to the following logic:
>
> * If a channel 'name' is provided and we do find it via
> 'io-channel-names', we should be able to get it. If we get any error,
> we should not proceed with the lookup. Moreover, we should return an error
> so that callers won't proceed with a system lookup.
> * If a channel 'name' is provided and we cannot find it ('index < 0'),
> 'of_parse_phandle_with_args()' is expected to fail with '-EINVAL'. Hence,
> we should only continue if we get that error.
> * If a channel 'name' is not provided we should only carry on with the
> search if 'of_parse_phandle_with_args()' returns '-ENOENT'.
>
> Also note that a system channel lookup is only done if the returned
> error code (from 'of_iio_channel_get_by_name()' or
> 'of_iio_channel_get_all()' is -ENODEV.
LGTM (but I might miss something, it's a bit too many conditionals),
Reviewed-by: Andy Shevchenko <andy.shevchenko at gmail.com>
> Signed-off-by: Nuno Sá <nuno.sa at analog.com>
> ---
> drivers/iio/inkern.c | 54 +++++++++++++++++++++++++++++++-------------
> 1 file changed, 38 insertions(+), 16 deletions(-)
>
> diff --git a/drivers/iio/inkern.c b/drivers/iio/inkern.c
> index 87fd2a0d44f2..c6f1cfe09bd3 100644
> --- a/drivers/iio/inkern.c
> +++ b/drivers/iio/inkern.c
> @@ -214,7 +214,7 @@ static struct iio_channel *of_iio_channel_get(struct device_node *np, int index)
> struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
> const char *name)
> {
> - struct iio_channel *chan = NULL;
> + struct iio_channel *chan;
>
> /* Walk up the tree of devices looking for a matching iio channel */
> while (np) {
> @@ -231,13 +231,33 @@ struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
> name);
> chan = of_iio_channel_get(np, index);
> if (!IS_ERR(chan) || PTR_ERR(chan) == -EPROBE_DEFER)
> - break;
> - else if (name && index >= 0) {
> - pr_err("ERROR: could not get IIO channel %pOF:%s(%i)\n",
> - np, name ? name : "", index);
> - return NULL;
> + return chan;
> + if (name) {
> + if (index >= 0) {
> + pr_err("ERROR: could not get IIO channel %pOF:%s(%i)\n",
> + np, name, index);
> + /*
> + * In this case, we found 'name' in 'io-channel-names'
> + * but somehow we still fail so that we should not proceed
> + * with any other lookup. Hence, explicitly return -EINVAL
> + * (maybe not the better error code) so that the caller
> + * won't do a system lookup.
> + */
> + return ERR_PTR(-EINVAL);
> + }
> + /* If index < 0, then of_parse_phandle_with_args() fails
> + * with -EINVAL which is expected. We should not proceed
> + * if we get any other error.
> + */
> + if (PTR_ERR(chan) != -EINVAL)
> + return chan;
> + } else if (PTR_ERR(chan) != -ENOENT) {
> + /*
> + * if !name, then we should only proceed the lookup if
> + * of_parse_phandle_with_args() returns -ENOENT.
> + */
> + return chan;
> }
> -
> /*
> * No matching IIO channel found on this node.
> * If the parent node has a "io-channel-ranges" property,
> @@ -245,10 +265,10 @@ struct iio_channel *of_iio_channel_get_by_name(struct device_node *np,
> */
> np = np->parent;
> if (np && !of_get_property(np, "io-channel-ranges", NULL))
> - return NULL;
> + return ERR_PTR(-ENODEV);
> }
>
> - return chan;
> + return ERR_PTR(-ENODEV);
> }
> EXPORT_SYMBOL_GPL(of_iio_channel_get_by_name);
>
> @@ -267,8 +287,8 @@ static struct iio_channel *of_iio_channel_get_all(struct device *dev)
> break;
> } while (++nummaps);
>
> - if (nummaps == 0) /* no error, return NULL to search map table */
> - return NULL;
> + if (nummaps == 0)
> + return ERR_PTR(-ENODEV);
>
> /* NULL terminated array to save passing size */
> chans = kcalloc(nummaps + 1, sizeof(*chans), GFP_KERNEL);
> @@ -295,7 +315,7 @@ static struct iio_channel *of_iio_channel_get_all(struct device *dev)
>
> static inline struct iio_channel *of_iio_channel_get_all(struct device *dev)
> {
> - return NULL;
> + return ERR_PTR(-ENODEV);
> }
>
> #endif /* CONFIG_OF */
> @@ -362,7 +382,7 @@ struct iio_channel *iio_channel_get(struct device *dev,
> if (dev) {
> channel = of_iio_channel_get_by_name(dev->of_node,
> channel_name);
> - if (channel != NULL)
> + if (!IS_ERR(channel) || PTR_ERR(channel) != -ENODEV)
> return channel;
> }
>
> @@ -412,8 +432,6 @@ struct iio_channel *devm_of_iio_channel_get_by_name(struct device *dev,
> channel = of_iio_channel_get_by_name(np, channel_name);
> if (IS_ERR(channel))
> return channel;
> - if (!channel)
> - return ERR_PTR(-ENODEV);
>
> ret = devm_add_action_or_reset(dev, devm_iio_channel_free, channel);
> if (ret)
> @@ -436,7 +454,11 @@ struct iio_channel *iio_channel_get_all(struct device *dev)
> return ERR_PTR(-EINVAL);
>
> chans = of_iio_channel_get_all(dev);
> - if (chans)
> + /*
> + * We only want to carry on if the error is -ENODEV. Anything else
> + * should be reported up the stack.
> + */
> + if (!IS_ERR(chans) || PTR_ERR(chans) != -ENODEV)
> return chans;
>
> name = dev_name(dev);
> --
> 2.37.0
>
--
With Best Regards,
Andy Shevchenko
More information about the Linux-mediatek
mailing list