RE: [PATCH v2 2/5] software node: add fw_devlink support
"Bird, Tim" <[email protected]> Mon, 6 Jul 2026 16:55:03 +0000
| Newsgroups | org.kernel.vger.linux-embedded |
|---|---|
| Message-ID | <MW5PR13MB5632A162A56D546F43DE7F79FDF12@MW5PR13MB5632.namprd13.prod.outlook.com> |
Hey Bartosz, Can you also please CC: [email protected] on this patch set, i= n the future? There are a few embedded Linux developers working on boot-time for the Linu= x kernel, who are interested in this work. Thanks, -- Tim > -----Original Message----- > From: Bartosz Golaszewski <[email protected]> > Sent: Monday, July 6, 2026 6:54 AM > To: Brendan Higgins <[email protected]>; David Gow <david@davidgo= w.net>; Rae Moar <[email protected]>; Andy > Shevchenko <[email protected]>; Daniel Scally <djrscally@= gmail.com>; Heikki Krogerus <[email protected]>; > Sakari Ailus <[email protected]>; Bartosz Golaszewski <brgl@ke= rnel.org>; Greg Kroah-Hartman <[email protected]>; > Rafael J. Wysocki <[email protected]>; Danilo Krummrich <[email protected]>= ; Linus Walleij <[email protected]>; Dmitry Torokhov > <[email protected]> > Cc: [email protected]; [email protected]; kunit-= [email protected]; [email protected]; driver- > [email protected]; [email protected]; Bartosz Golaszewski <ba= [email protected]> > Subject: [PATCH v2 2/5] software node: add fw_devlink support >=20 > Software nodes can be used to describe supplier-consumer relationships be= tween devices they represent using reference property entries. > Unlike for OF-nodes, driver core cannot yet use these references to creat= e a probe order that avoids needless >=20 > Software nodes can be used to describe supplier-consumer relationships > between devices they represent using reference property entries. Unlike > for OF-nodes, driver core cannot yet use these references to create a > probe order that avoids needless probe deferrals on missing providers. >=20 > Implement software_node_add_links() modelled on of_fwnode_add_links(). > For every DEV_PROP_REF property we resolve each referenced supplier and > create an fwnode link from the node to it. The driver core later promotes > these to device links and defers the consumer until the suppliers are > ready. >=20 > There's no allowlist like the one DT needs - devicetree phandles appear > in plenty of non-supplier contexts, but a software node only carries a > reference property when its author explicitly points at another node, so > we treat every reference as an intentional supplier dependency and link > all of them. Graph "remote-endpoint" references are skipped for now: they > go 2-ways between endpoint nodes and would create graph cycles without > the port-parent lifting DT does via get_con_dev(). References to > suppliers that aren't registered yet and self-references are ignored. >=20 > fw_devlink resolves the supplier device through fwnode->dev but the core > only records the owning device on the primary fwnode. When the software > node is a device's secondary fwnode, mirror the device pointer onto it in > software_node_notify() so the consumer can actually find the supplier > instead of deferring forever. >=20 > While at it: purge the fwnode links in software_node_release() now that > software nodes can own them. >=20 > Signed-off-by: Bartosz Golaszewski <[email protected]> > --- > drivers/base/swnode.c | 79 +++++++++++++++++++++++++++++++++++++++++++++= ++++++ > 1 file changed, 79 insertions(+) >=20 > diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c > index 869228a65cb365567ddac7db6ad7b8743e0dbca9..e6e2d6926fef2db82eb1f2bf4= 39e80aacf48668a 100644 > --- a/drivers/base/swnode.c > +++ b/drivers/base/swnode.c > @@ -699,6 +699,62 @@ software_node_graph_parse_endpoint(const struct fwno= de_handle *fwnode, > return 0; > } >=20 > +static int software_node_add_links(struct fwnode_handle *fwnode) > +{ > + const struct software_node_ref_args *ref, *ref_array; > + struct swnode *swnode =3D to_swnode(fwnode); > + const struct property_entry *prop; > + struct fwnode_handle *refnode; > + unsigned int count; > + > + if (!swnode || !swnode->node->properties) > + return 0; > + > + /* > + * Unlike Device Tree, where phandles appear in many non-supplier > + * contexts and a curated allowlist is required, a software node only > + * carries a DEV_PROP_REF property when the author explicitly describes > + * a reference to another node. Every such reference is therefore an > + * intentional supplier dependency, so we create fwnode links for all > + * of them. > + */ > + for (prop =3D swnode->node->properties; prop->name; prop++) { > + if (prop->type !=3D DEV_PROP_REF || prop->is_inline) > + continue; > + > + /* > + * TODO: Graph "remote-endpoint" references go both ways > + * between endpoint child nodes and would create endpoint > + * cycles. Let's leave it out for now until we have potential > + * users. > + */ > + if (!strcmp(prop->name, "remote-endpoint")) > + continue; > + > + ref_array =3D prop->pointer; > + count =3D prop->length / sizeof(*ref_array); > + > + for (unsigned int i =3D 0; i < count; i++) { > + ref =3D &ref_array[i]; > + > + if (ref->swnode) > + refnode =3D software_node_fwnode(ref->swnode); > + else if (ref->fwnode) > + refnode =3D ref->fwnode; > + else > + continue; > + > + /* Supplier not registered yet, or self-reference. */ > + if (!refnode || refnode =3D=3D &swnode->fwnode) > + continue; > + > + fwnode_link_add(&swnode->fwnode, refnode, 0); > + } > + } > + > + return 0; > +} > + > static const struct fwnode_operations software_node_ops =3D { > .get =3D software_node_get, > .put =3D software_node_put, > @@ -716,6 +772,7 @@ static const struct fwnode_operations software_node_o= ps =3D { > .graph_get_remote_endpoint =3D software_node_graph_get_remote_endpoint, > .graph_get_port_parent =3D software_node_graph_get_port_parent, > .graph_parse_endpoint =3D software_node_graph_parse_endpoint, > + .add_links =3D software_node_add_links, > }; >=20 > /* ---------------------------------------------------------------------= ----- */ > @@ -787,6 +844,8 @@ static void software_node_release(struct kobject *kob= j) > { > struct swnode *swnode =3D kobj_to_swnode(kobj); >=20 > + fwnode_links_purge(&swnode->fwnode); > + > if (swnode->parent) { > ida_free(&swnode->parent->child_ids, swnode->id); > list_del(&swnode->entry); > @@ -1105,6 +1164,17 @@ void software_node_notify(struct device *dev) > if (!swnode) > return; >=20 > + /* > + * When the software node is the device's secondary firmware node, > + * the core only records the owning device on the primary fwnode > + * (see device_add()). fw_devlink resolves a supplier device through > + * fwnode->dev, so without this a consumer referencing the software > + * node could never find the supplier device and would defer forever. > + * Make fwnode.dev point to its owner in that case. > + */ > + if (dev_fwnode(dev) !=3D &swnode->fwnode && !swnode->fwnode.dev) > + swnode->fwnode.dev =3D dev; > + > swnode_get(swnode); > ret =3D sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node"); > if (ret) > @@ -1127,6 +1197,15 @@ void software_node_notify_remove(struct device *de= v) >=20 > sysfs_remove_link(&swnode->kobj, dev_name(dev)); > sysfs_remove_link(&dev->kobj, "software_node"); > + > + /* > + * Drop the device pointer mirrored onto a secondary software node in > + * software_node_notify(). For a primary software node the core owns > + * fwnode->dev and clears it in device_del(). > + */ > + if (dev_fwnode(dev) !=3D &swnode->fwnode && swnode->fwnode.dev =3D=3D d= ev) > + swnode->fwnode.dev =3D NULL; > + > swnode_put(swnode); >=20 > if (swnode->managed) { >=20 > -- > 2.47.3 >=20