Re: [PATCH v3 4/8] of: unittest: Test fw_devlink with GPIO nexus maps
From: Saravana Kannan
Date: Mon Oct 26 2026 - 00:54:51 EST
On Tue, Oct 20, 2026 at 6:00 AM Ernest Van Hoecke
<ernestvanhoecke@xxxxxxxxx> wrote:
>
> From: Ernest Van Hoecke <ernest.vanhoecke@xxxxxxxxxxx>
>
> Add OF unit tests that call the fw_devlink add_links operation for GPIOs
> routed through nexus maps. Verify that each mapped consumer has exactly
> one link to the final GPIO provider rather than to the nexus.
>
> Also cover direct references and all GPIO property spellings recognized
> by fw_devlink, including the deprecated singular and unprefixed forms.
>
> The gpio-map routes its entries to different providers so that selecting
> the wrong entry is caught as well.
>
> Reviewed-by: Bartosz Golaszewski <bartosz.golaszewski@xxxxxxxxxxxxxxxx>
> Reviewed-by: Linus Walleij <linusw@xxxxxxxxxx>
> Signed-off-by: Ernest Van Hoecke <ernest.vanhoecke@xxxxxxxxxxx>
> ---
> v3: Route gpio-map entries to two providers, use a middle entry (Herve)
> v2: https://lore.kernel.org/r/20260910-fw-devlink-nexus-ready-v2-3-17ac82dbe226@xxxxxxxxxxx
> ---
> drivers/of/unittest-data/tests-phandle.dtsi | 39 +++++++++++++++
> drivers/of/unittest.c | 75 +++++++++++++++++++++++++++++
> 2 files changed, 114 insertions(+)
>
> diff --git a/drivers/of/unittest-data/tests-phandle.dtsi b/drivers/of/unittest-data/tests-phandle.dtsi
> index 554a996b2ef1..f5d7ee072c90 100644
> --- a/drivers/of/unittest-data/tests-phandle.dtsi
> +++ b/drivers/of/unittest-data/tests-phandle.dtsi
> @@ -79,6 +79,45 @@ consumer-b {
> phandle-list-bad-args = <&provider2 1 0>,
> <&provider4 0>;
> };
> +
> + fw-devlink-tests {
> + gpio_provider_a: gpio-controller-a {
> + #gpio-cells = <2>;
> + };
> +
> + gpio_provider_b: gpio-controller-b {
> + #gpio-cells = <2>;
> + };
> +
> + fwdevlink_nexus: nexus {
> + #gpio-cells = <2>;
> + gpio-map = <1 0 &gpio_provider_a 3 0>,
> + <2 0 &gpio_provider_b 5 0>,
> + <3 0 &gpio_provider_a 7 0>;
> + gpio-map-mask = <0xffffffff 0>;
> + gpio-map-pass-thru = <0 0xffffffff>;
> + };
> +
> + gpio-compat-consumer {
> + gpios = <&fwdevlink_nexus 2 1>;
> + };
> +
> + gpio-compat-singular-consumer {
> + gpio = <&fwdevlink_nexus 2 1>;
> + };
> +
> + gpio-consumer {
> + test-gpios = <&fwdevlink_nexus 2 1>;
> + };
> +
> + gpio-direct-consumer {
> + test-gpios = <&gpio_provider_a 1 0>;
> + };
> +
> + gpio-singular-consumer {
> + test-gpio = <&fwdevlink_nexus 2 1>;
> + };
> + };
> };
> };
> };
> diff --git a/drivers/of/unittest.c b/drivers/of/unittest.c
> index e255f54f4d76..f15c110dbf4d 100644
> --- a/drivers/of/unittest.c
> +++ b/drivers/of/unittest.c
> @@ -10,6 +10,7 @@
> #include <linux/dma-direct.h> /* to test phys_to_dma/dma_to_phys */
> #include <linux/err.h>
> #include <linux/errno.h>
> +#include <linux/fwnode.h>
> #include <linux/hashtable.h>
> #include <linux/libfdt.h>
> #include <linux/of.h>
> @@ -710,6 +711,79 @@ static void __init of_unittest_parse_phandle_with_args_map(void)
> }
> }
>
> +static void __init of_unittest_fw_devlink_supplier(struct device_node *tests,
> + const char *consumer_name,
> + const char *supplier_name)
> +{
> + struct device_node *consumer, *supplier;
> + struct fwnode_handle *consumer_fwnode;
> + struct fwnode_link *link;
> + unsigned int link_count = 0;
> + bool found = false;
> + int rc;
> +
> + consumer = of_get_child_by_name(tests, consumer_name);
> + supplier = of_get_child_by_name(tests, supplier_name);
> + if (unittest(consumer && supplier, "missing consumer %s or supplier %s\n",
> + consumer_name, supplier_name))
> + goto put_nodes;
> +
> + consumer_fwnode = of_fwnode_handle(consumer);
> + fwnode_links_purge(consumer_fwnode);
Why this line? Aren't you controlling the exact set of properties in
the test nodes?
-Saravana
> + rc = fwnode_call_int_op(consumer_fwnode, add_links);
> + if (rc == -EOPNOTSUPP) {
> + pr_info_once("fw_devlink tests skipped: OF supplier links are not supported\n");
> + goto purge_links;
> + }
> + if (unittest(!rc, "failed to add links for %pOF: %d\n", consumer, rc))
> + goto purge_links;
> +
> + /*
> + * The suppliers list should normally be accessed with fwnode_link_lock
> + * held, but that lock is private to the driver core. These test nodes
> + * are isolated and have no concurrent link updates.
> + */
> + list_for_each_entry(link, &consumer_fwnode->suppliers, c_hook) {
> + link_count++;
> + if (link->supplier == of_fwnode_handle(supplier))
> + found = true;
> + }
> +
> + unittest(link_count == 1, "%pOF has %u suppliers, expected 1\n", consumer, link_count);
> + unittest(found, "%pOF is not linked to supplier %pOF\n", consumer, supplier);
> +
> +purge_links:
> + fwnode_links_purge(consumer_fwnode);
> +put_nodes:
> + of_node_put(consumer);
> + of_node_put(supplier);
> +}
> +
> +static void __init of_unittest_fw_devlink(void)
> +{
> + static const struct {
> + const char *consumer;
> + const char *supplier;
> + } cases[] = {
> + { "gpio-compat-consumer", "gpio-controller-b" },
> + { "gpio-compat-singular-consumer", "gpio-controller-b" },
> + { "gpio-consumer", "gpio-controller-b" },
> + { "gpio-direct-consumer", "gpio-controller-a" },
> + { "gpio-singular-consumer", "gpio-controller-b" },
> + };
> + struct device_node *tests;
> + int i;
> +
> + tests = of_find_node_by_path("/testcase-data/phandle-tests/fw-devlink-tests");
> + if (unittest(tests, "missing fw_devlink test data\n"))
> + return;
> +
> + for (i = 0; i < ARRAY_SIZE(cases); i++)
> + of_unittest_fw_devlink_supplier(tests, cases[i].consumer, cases[i].supplier);
> +
> + of_node_put(tests);
> +}
> +
> static void __init of_unittest_property_string(void)
> {
> const char *strings[4];
> @@ -4533,6 +4607,7 @@ static int __init of_unittest(void)
> of_unittest_dynamic();
> of_unittest_parse_phandle_with_args();
> of_unittest_parse_phandle_with_args_map();
> + of_unittest_fw_devlink();
> of_unittest_printf();
> of_unittest_property_string();
> of_unittest_property_copy();
>
> --
> 2.43.0
>