On Tue, Feb 2, 2021 at 1:50 PM Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> wrote: > > Adding function device_create_managed_software_node() that > is designed to work as a drop-in replacement for > device_add_properties(). The function has one additional > feature compared to device_add_properties(). It takes also > an optional parent node as parameter, and that way allow the > nodes created with it to be part of a node hierarchy. > > The lifetime of the software nodes created with this > function will be tied to the device they are assigned to. > The function will therefore behave exactly the same way as > device_add_properties() is expected to behave, except that > it does not simply assume that the nodes attached to the > device are always destroyed in device_del() unconditionally. > > The nodes created with this function are guaranteed to be > removed when the device is removed even after device_del() > stops calling device_remove_properties() unconditionally. > > Signed-off-by: Heikki Krogerus <heikki.krogerus@xxxxxxxxxxxxxxx> > --- > drivers/base/swnode.c | 43 ++++++++++++++++++++++++++++++++++++++++ > include/linux/property.h | 4 ++++ > 2 files changed, 47 insertions(+) > > diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c > index 20faa9f4f5ed2..37179a8b1ceba 100644 > --- a/drivers/base/swnode.c > +++ b/drivers/base/swnode.c > @@ -24,6 +24,7 @@ struct swnode { > struct swnode *parent; > > unsigned int allocated:1; > + unsigned int managed:1; > }; > > static DEFINE_IDA(swnode_root_ids); > @@ -1045,6 +1046,43 @@ void device_remove_software_node(struct device *dev) > } > EXPORT_SYMBOL_GPL(device_remove_software_node); > > +/** > + * device_create_managed_software_node - Create a software node for a device > + * @dev: The device the software node is assigned to. > + * @properties: Device properties for the software node. > + * @parent: Parent of the software node. > + * > + * Creates a software node as a managed resource for @dev, which means the > + * lifetime of the newly created software node is tied to the lifetime of @dev. > + * Software nodes created with this function should not be reused or shared > + * because of that. The function takes a deep copy of @properties for the > + * software node. > + * > + * Since the new software node is assigned directly to @dev, and since it should > + * not be shared, it is not returned to the caller. The function returns 0 on > + * success, and errno in case of an error. > + */ > +int device_create_managed_software_node(struct device *dev, > + const struct property_entry *properties, > + const struct software_node *parent) > +{ > + struct fwnode_handle *p = software_node_fwnode(parent); > + struct fwnode_handle *fwnode; > + > + if (parent && !p) > + return -EINVAL; > + > + fwnode = fwnode_create_software_node(properties, p); > + if (IS_ERR(fwnode)) > + return PTR_ERR(fwnode); > + > + to_swnode(fwnode)->managed = true; > + set_secondary_fwnode(dev, fwnode); > + > + return 0; > +} > +EXPORT_SYMBOL_GPL(device_create_managed_software_node); > + > int software_node_notify(struct device *dev, unsigned long action) > { > struct swnode *swnode; > @@ -1073,6 +1111,11 @@ int software_node_notify(struct device *dev, unsigned long action) > sysfs_remove_link(&swnode->kobj, dev_name(dev)); > sysfs_remove_link(&dev->kobj, "software_node"); > kobject_put(&swnode->kobj); > + > + if (swnode->managed) { > + set_secondary_fwnode(dev, NULL); > + kobject_put(&swnode->kobj); Where does the corresponding kobject_get() get called? > + } > break; > default: > break; > diff --git a/include/linux/property.h b/include/linux/property.h > index b0e413dc59271..dafccfce02624 100644 > --- a/include/linux/property.h > +++ b/include/linux/property.h > @@ -491,4 +491,8 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode); > int device_add_software_node(struct device *dev, const struct software_node *swnode); > void device_remove_software_node(struct device *dev); > > +int device_create_managed_software_node(struct device *dev, > + const struct property_entry *properties, > + const struct software_node *parent); > + > #endif /* _LINUX_PROPERTY_H_ */ > -- > 2.30.0 >