Re: [PATCH v3 2/8] of: property: fw_devlink: Follow GPIO nexus maps

From: Saravana Kannan

Date: Mon Oct 26 2026 - 00:47:25 EST


On Tue, Oct 20, 2026 at 6:00 AM Ernest Van Hoecke
<ernestvanhoecke@xxxxxxxxx> wrote:
>
> From: Ernest Van Hoecke <ernest.vanhoecke@xxxxxxxxxxx>
>
> GPIO consumers use of_parse_phandle_with_args_map() to resolve
> specifiers through gpio-map properties. fw_devlink instead parses GPIO
> properties as direct phandle references, so it records the nexus node as
> the supplier rather than the mapped GPIO provider.
>
> A nexus is a translation node, not the GPIO provider, and need not be
> populated as a device. The resulting fwnode link can therefore remain
> unresolved and indefinitely defer the consumer while
> device_links_check_suppliers() waits for the nexus.
>
> Use the map-aware parser for all supported GPIO property spellings. This
> makes fw_devlink resolve the same provider as the GPIO consumer API.
> Direct GPIO references continue to work because the map-aware parser
> returns the original provider when no gpio-map property is present.
>
> Fixes: 7f00be96f125 ("of: property: Add device link support for interrupt-parent, dmas and -gpio(s)")
> Reported-by: Leonardo Costa <leonardo.costa@xxxxxxxxxxx>
> Link: https://lore.kernel.org/all/juuc4af7ndbajcl7gzf4tg5qz2q2j5tt3rvql4jbauradujrre@gc5nbdhhixaf/
> Tested-by: Leonardo Costa <leonardo.costa@xxxxxxxxxxx>
> Cc: stable@xxxxxxxxxxxxxxx
> Reviewed-by: Linus Walleij <linusw@xxxxxxxxxx>
> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxxxxxxxx>
> Reviewed-by: Herve Codina <herve.codina@xxxxxxxxxxx>
> Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@xxxxxxxxxxx>
> ---
> drivers/of/property.c | 38 ++++++++++++++++++++++++++++----------
> 1 file changed, 28 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/of/property.c b/drivers/of/property.c
> index 45e55f618488..aa65976739e1 100644
> --- a/drivers/of/property.c
> +++ b/drivers/of/property.c
> @@ -1311,6 +1311,19 @@ static struct device_node *parse_prop_cells(struct device_node *np,
> return sup_args.np;
> }
>
> +static struct device_node *parse_nexus_prop(struct device_node *np,
> + const char *prop_name, int index,
> + const char *stem_name)
> +{
> + struct of_phandle_args sup_args;
> +
> + if (of_parse_phandle_with_args_map(np, prop_name, stem_name, index,
> + &sup_args))
> + return NULL;
> +
> + return sup_args.np;
> +}
> +
> #define DEFINE_SIMPLE_PROP(fname, name, cells) \
> static struct device_node *parse_##fname(struct device_node *np, \
> const char *prop_name, int index) \
> @@ -1361,6 +1374,15 @@ static struct device_node *parse_##fname(struct device_node *np, \
> return parse_suffix_prop_cells(np, prop_name, index, suffix, cells); \
> }
>
> +#define DEFINE_SUFFIX_NEXUS_PROP(fname, suffix, stem) \

It's the node that's called the nexus node. The properties themselves
all have a "map" in their name.

I'd prefer calling these DEFINE_SUFFIX_MAP_PROP() and the simple one
as DEFINE_SIMPLE_MAP_PROP(). Similar fixes for the function names too.

I know it's a nit pick, but I think it makes sense.

-Saravana

> +static struct device_node *parse_##fname(struct device_node *np, \
> + const char *prop_name, int index) \
> +{ \
> + if (!strends(prop_name, suffix)) \
> + return NULL; \
> + return parse_nexus_prop(np, prop_name, index, stem); \
> +}
> +
> /**
> * struct supplier_bindings - Property parsing functions for suppliers
> *
> @@ -1416,7 +1438,7 @@ DEFINE_SIMPLE_PROP(pses, "pses", "#pse-cells")
> DEFINE_SIMPLE_PROP(power_supplies, "power-supplies", NULL)
> DEFINE_SIMPLE_PROP(mmc_pwrseq, "mmc-pwrseq", NULL)
> DEFINE_SUFFIX_PROP(regulators, "-supply", NULL)
> -DEFINE_SUFFIX_PROP(gpio, "-gpio", "#gpio-cells")
> +DEFINE_SUFFIX_NEXUS_PROP(gpio, "-gpio", "gpio")
>
> static struct device_node *parse_pinctrl_n(struct device_node *np,
> const char *prop_name, int index)
> @@ -1436,8 +1458,10 @@ static struct device_node *parse_gpios(struct device_node *np,
> if (strends(prop_name, ",nr-gpios"))
> return NULL;
>
> - return parse_suffix_prop_cells(np, prop_name, index, "-gpios",
> - "#gpio-cells");
> + if (!strends(prop_name, "-gpios"))
> + return NULL;
> +
> + return parse_nexus_prop(np, prop_name, index, "gpio");
> }
>
> static struct device_node *parse_iommu_maps(struct device_node *np,
> @@ -1452,8 +1476,6 @@ static struct device_node *parse_iommu_maps(struct device_node *np,
> static struct device_node *parse_gpio_compat(struct device_node *np,
> const char *prop_name, int index)
> {
> - struct of_phandle_args sup_args;
> -
> if (strcmp(prop_name, "gpio") && strcmp(prop_name, "gpios"))
> return NULL;
>
> @@ -1464,11 +1486,7 @@ static struct device_node *parse_gpio_compat(struct device_node *np,
> if (of_property_read_bool(np, "gpio-hog"))
> return NULL;
>
> - if (of_parse_phandle_with_args(np, prop_name, "#gpio-cells", index,
> - &sup_args))
> - return NULL;
> -
> - return sup_args.np;
> + return parse_nexus_prop(np, prop_name, index, "gpio");
> }
>
> static struct device_node *parse_i2c_parent(struct device_node *np,
>
> --
> 2.43.0
>