On Mon, Jun 29, 2026 at 12:52:08PM +0200, Bartosz Golaszewski wrote:
> Add a kunit test suite for fw_devlink support for software nodes.
>
> Most cases call add_links() directly and inspect the resulting fwnode
> supplier/consumer lists: a single reference, multiple references, a
> reference to an unregistered node, a "remote-endpoint" reference and a
> reference array. The last case is end-to-end - it registers real consumer
> and supplier platform devices together with their drivers, adds the
> consumer first and checks that fw_devlink defers its probe until the
> supplier has been bound.
...
> ---
> drivers/base/test/Kconfig | 5 +
> drivers/base/test/Makefile | 3 +
> drivers/base/test/swnode-devlink-test.c | 336
> ++++++++++++++++++++++++++++++++
+ MAINTAINERS.
...
> CFLAGS_property-entry-test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
> +
> +obj-$(CONFIG_DRIVER_SWNODE_KUNIT_TEST) += swnode-devlink-test.o
> +CFLAGS_swnode-devlink-test.o += $(DISABLE_STRUCTLEAK_PLUGIN)
Is it the case for this?
...
> +#include <linux/device.h>
> +#include <linux/fwnode.h>
+ list.h
> +#include <linux/platform_device.h>
> +#include <linux/property.h>
> +#include <linux/types.h>
> +#include <linux/wait.h>
...
> +static int swnode_count_suppliers(struct fwnode_handle *fwnode)
> +{
> + struct fwnode_link *link;
> + int ret = 0;
Why signed? Also it's not 'ret' semantically it's 'count'.
> + /*
> + * The suppliers and consumers lists should typically only be accessed
> + * with the fwnode_link_lock taken but it's private to the driver core.
> + *
> + * These are tests and at this point nobody should be modifying them so
> + * let's just access the list.
> + */
> + list_for_each_entry(link, &fwnode->suppliers, c_hook)
> + ret++;
> +
> + return ret;
> +}
...
> +/* A single reference creates exactly one supplier link, on both list ends.
> */
> +static void swnode_devlink_test_single_ref(struct kunit *test)
> +{
> + static const struct software_node supp_swnode = {
> + .name = "swnode-devlink-test-supplier"
Keep trailing comma.
> + };
> +
Redundant blank line.
> + struct fwnode_handle *cons_fwnode, *supp_fwnode;
> + int ret;
> +
> + const struct property_entry props[] = {
> + PROPERTY_ENTRY_REF("supplier", &supp_swnode),
> + { }
> + };
> +
> + supp_fwnode = kunit_software_node_register(test, &supp_swnode);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, supp_fwnode);
> +
> + cons_fwnode = kunit_fwnode_create_software_node(test, props, NULL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, cons_fwnode);
> +
> + ret = fwnode_call_int_op(cons_fwnode, add_links);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + KUNIT_EXPECT_EQ(test, swnode_count_suppliers(cons_fwnode), 1);
> + KUNIT_EXPECT_TRUE(test, swnode_has_link(cons_fwnode, supp_fwnode));
> +}
...
> +/* Multiple distinct references create multiple supplier links. */
> +static void swnode_devlink_test_multiple_refs(struct kunit *test)
> +{
> + static const struct software_node supp1_swnode = {
> + .name = "swnode-devlink-test-supplier-1"
Keep comma.
> + };
> + static const struct software_node supp2_swnode = {
> + .name = "swnode-devlink-test-supplier-2"
Ditto.
> + };
> + static const struct software_node *supp_nodes[] = {
> + &supp1_swnode, &supp2_swnode, NULL
Here it's fine.
> + };
> +
Redundant blank line.
> + const struct property_entry props[] = {
> + PROPERTY_ENTRY_REF("foo", &supp1_swnode),
> + PROPERTY_ENTRY_REF("bar", &supp2_swnode),
> + { }
> + };
> +
> + struct fwnode_handle *fwnode;
> + int ret;
> +
> + ret = kunit_software_node_register_node_group(test, supp_nodes);
> + KUNIT_ASSERT_EQ(test, ret, 0);
> +
> + fwnode = kunit_fwnode_create_software_node(test, props, NULL);
> + KUNIT_ASSERT_NOT_ERR_OR_NULL(test, fwnode);
> +
> + ret = fwnode_call_int_op(fwnode, add_links);
> + KUNIT_EXPECT_EQ(test, ret, 0);
> +
> + KUNIT_EXPECT_EQ(test, swnode_count_suppliers(fwnode), 2);
> + KUNIT_EXPECT_TRUE(test, swnode_has_link(fwnode,
> software_node_fwnode(&supp1_swnode)));
> + KUNIT_EXPECT_TRUE(test, swnode_has_link(fwnode,
> software_node_fwnode(&supp2_swnode)));
> +}
...
> +static void swnode_devlink_test_unregistered_ref(struct kunit *test)
Same comments as per above.
...
> +static void swnode_devlink_test_remote_endpoint_excluded(struct kunit *test)
Ditto.
...
> +static void swnode_devlink_test_ref_array(struct kunit *test)
Ditto.
...
> +#define SWNODE_DEVLINK_TEST_TIMEOUT_MS 2000
(2 * MSEC_PER_SEC) ?
(will require time.h).
...
> +static int swnode_test_record_probe(struct platform_device *pdev)
> +{
> + struct swnode_test_probe_order *order = platform_get_drvdata(pdev);
> +
> + if (order && order->count < ARRAY_SIZE(order->probed)) {
+ array_size.h
> + order->probed[order->count++] = dev_name(&pdev->dev);
> + wake_up_interruptible(&order->wq);
> + }
> +
> + return 0;
> +}
...
> +static void swnode_devlink_test_probe_order(struct kunit *test)
As per above comments.
...
> +static struct kunit_suite swnode_test_suite = {
> + .name = "software-node-links",
> + .test_cases = swnode_test_cases,
> +};
> +
Redundant blank line.
> +kunit_test_suite(swnode_test_suite);
--
With Best Regards,
Andy Shevchenko