linux-stable/drivers/base/swnode.c

1128 lines
26 KiB
C
Raw Normal View History

drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
// SPDX-License-Identifier: GPL-2.0
/*
* Software nodes for the firmware node framework.
*
* Copyright (C) 2018, Intel Corporation
* Author: Heikki Krogerus <heikki.krogerus@linux.intel.com>
*/
#include <linux/container_of.h>
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
#include <linux/device.h>
#include <linux/err.h>
#include <linux/export.h>
#include <linux/idr.h>
#include <linux/init.h>
#include <linux/kobject.h>
#include <linux/kstrtox.h>
#include <linux/list.h>
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
#include <linux/property.h>
#include <linux/slab.h>
#include <linux/spinlock.h>
#include <linux/string.h>
#include <linux/sysfs.h>
#include <linux/types.h>
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
#include "base.h"
struct swnode {
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
struct kobject kobj;
struct fwnode_handle fwnode;
const struct software_node *node;
int id;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
/* hierarchy */
struct ida child_ids;
struct list_head entry;
struct list_head children;
struct swnode *parent;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
unsigned int allocated:1;
software node: Provide replacement for device_add_properties() At the moment the function device_del() is calling device_remove_properties() unconditionally. That will result into the reference count of the software node attached to the device being decremented, and in most cases it will hit 0 at that point. So in practice device_del() will unregister the software node attached to the device, even if that was not the intention of the caller. Right now software nodes can not be reused or shared because of that. So device_del() can not unregister the software nodes unconditionally like that. Unfortunately some of the users of device_add_properties() are now relying on this behaviour. Because of that, and also in general, we do need a function that can offer similar behaviour where the lifetime of the software node is bound to the lifetime of the device. But it just has to be a separate function so the behaviour is optional. We can not remove the device_remove_properties() call from device_del() before we have that new function, and before we have replaced device_add_properties() calls with it in all the places that require that behaviour. This adds function device_create_managed_software_node() that can be used for exactly that purpose. Software nodes created with it are declared "managed", and separate handling for those nodes is added to the software node code. The reference count of the "managed" nodes is decremented when the device they are attached to is removed. This will not affect the other nodes that are not declared "managed". The function device_create_managed_software_node() has also one additional feature that device_add_properties() does not have. It allows the software nodes created with it to be part of a node hierarchy by taking also an optional parent node as parameter. Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://lore.kernel.org/r/20210204141711.53775-2-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-02-04 14:17:06 +00:00
unsigned int managed:1;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
};
static DEFINE_IDA(swnode_root_ids);
static struct kset *swnode_kset;
#define kobj_to_swnode(_kobj_) container_of(_kobj_, struct swnode, kobj)
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
static const struct fwnode_operations software_node_ops;
bool is_software_node(const struct fwnode_handle *fwnode)
{
return !IS_ERR_OR_NULL(fwnode) && fwnode->ops == &software_node_ops;
}
EXPORT_SYMBOL_GPL(is_software_node);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
#define to_swnode(__fwnode) \
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
({ \
typeof(__fwnode) __to_swnode_fwnode = __fwnode; \
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
\
is_software_node(__to_swnode_fwnode) ? \
container_of(__to_swnode_fwnode, \
struct swnode, fwnode) : NULL; \
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
})
static inline struct swnode *dev_to_swnode(struct device *dev)
{
struct fwnode_handle *fwnode = dev_fwnode(dev);
if (!fwnode)
return NULL;
if (!is_software_node(fwnode))
fwnode = fwnode->secondary;
return to_swnode(fwnode);
}
static struct swnode *
software_node_to_swnode(const struct software_node *node)
{
struct swnode *swnode = NULL;
struct kobject *k;
if (!node)
return NULL;
spin_lock(&swnode_kset->list_lock);
list_for_each_entry(k, &swnode_kset->list, entry) {
swnode = kobj_to_swnode(k);
if (swnode->node == node)
break;
swnode = NULL;
}
spin_unlock(&swnode_kset->list_lock);
return swnode;
}
const struct software_node *to_software_node(const struct fwnode_handle *fwnode)
{
const struct swnode *swnode = to_swnode(fwnode);
return swnode ? swnode->node : NULL;
}
EXPORT_SYMBOL_GPL(to_software_node);
struct fwnode_handle *software_node_fwnode(const struct software_node *node)
{
struct swnode *swnode = software_node_to_swnode(node);
return swnode ? &swnode->fwnode : NULL;
}
EXPORT_SYMBOL_GPL(software_node_fwnode);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
/* -------------------------------------------------------------------------- */
/* property_entry processing */
static const struct property_entry *
property_entry_get(const struct property_entry *prop, const char *name)
{
if (!prop)
return NULL;
for (; prop->name; prop++)
if (!strcmp(name, prop->name))
return prop;
return NULL;
}
static const void *property_get_pointer(const struct property_entry *prop)
{
if (!prop->length)
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
return NULL;
return prop->is_inline ? &prop->value : prop->pointer;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
static const void *property_entry_find(const struct property_entry *props,
const char *propname, size_t length)
{
const struct property_entry *prop;
const void *pointer;
prop = property_entry_get(props, propname);
if (!prop)
return ERR_PTR(-EINVAL);
pointer = property_get_pointer(prop);
if (!pointer)
return ERR_PTR(-ENODATA);
if (length > prop->length)
return ERR_PTR(-EOVERFLOW);
return pointer;
}
static int
property_entry_count_elems_of_size(const struct property_entry *props,
const char *propname, size_t length)
{
const struct property_entry *prop;
prop = property_entry_get(props, propname);
if (!prop)
return -EINVAL;
return prop->length / length;
}
static int property_entry_read_int_array(const struct property_entry *props,
const char *name,
unsigned int elem_size, void *val,
size_t nval)
{
const void *pointer;
size_t length;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
if (!val)
return property_entry_count_elems_of_size(props, name,
elem_size);
if (!is_power_of_2(elem_size) || elem_size > sizeof(u64))
return -ENXIO;
length = nval * elem_size;
pointer = property_entry_find(props, name, length);
if (IS_ERR(pointer))
return PTR_ERR(pointer);
memcpy(val, pointer, length);
return 0;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
static int property_entry_read_string_array(const struct property_entry *props,
const char *propname,
const char **strings, size_t nval)
{
const void *pointer;
size_t length;
int array_len;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
/* Find out the array length. */
array_len = property_entry_count_elems_of_size(props, propname,
sizeof(const char *));
if (array_len < 0)
return array_len;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
/* Return how many there are if strings is NULL. */
if (!strings)
return array_len;
array_len = min_t(size_t, nval, array_len);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
length = array_len * sizeof(*strings);
pointer = property_entry_find(props, propname, length);
if (IS_ERR(pointer))
return PTR_ERR(pointer);
memcpy(strings, pointer, length);
return array_len;
}
static void property_entry_free_data(const struct property_entry *p)
{
const char * const *src_str;
size_t i, nval;
if (p->type == DEV_PROP_STRING) {
src_str = property_get_pointer(p);
nval = p->length / sizeof(*src_str);
for (i = 0; i < nval; i++)
kfree(src_str[i]);
}
if (!p->is_inline)
kfree(p->pointer);
kfree(p->name);
}
static bool property_copy_string_array(const char **dst_ptr,
const char * const *src_ptr,
size_t nval)
{
int i;
for (i = 0; i < nval; i++) {
dst_ptr[i] = kstrdup(src_ptr[i], GFP_KERNEL);
if (!dst_ptr[i] && src_ptr[i]) {
while (--i >= 0)
kfree(dst_ptr[i]);
return false;
}
}
return true;
}
static int property_entry_copy_data(struct property_entry *dst,
const struct property_entry *src)
{
const void *pointer = property_get_pointer(src);
void *dst_ptr;
size_t nval;
/*
* Properties with no data should not be marked as stored
* out of line.
*/
if (!src->is_inline && !src->length)
return -ENODATA;
/*
* Reference properties are never stored inline as
* they are too big.
*/
if (src->type == DEV_PROP_REF && src->is_inline)
return -EINVAL;
if (src->length <= sizeof(dst->value)) {
dst_ptr = &dst->value;
dst->is_inline = true;
} else {
dst_ptr = kmalloc(src->length, GFP_KERNEL);
if (!dst_ptr)
return -ENOMEM;
dst->pointer = dst_ptr;
}
if (src->type == DEV_PROP_STRING) {
nval = src->length / sizeof(const char *);
if (!property_copy_string_array(dst_ptr, pointer, nval)) {
if (!dst->is_inline)
kfree(dst->pointer);
return -ENOMEM;
}
} else {
memcpy(dst_ptr, pointer, src->length);
}
dst->length = src->length;
dst->type = src->type;
dst->name = kstrdup(src->name, GFP_KERNEL);
if (!dst->name) {
property_entry_free_data(dst);
return -ENOMEM;
}
return 0;
}
/**
* property_entries_dup - duplicate array of properties
* @properties: array of properties to copy
*
* This function creates a deep copy of the given NULL-terminated array
* of property entries.
*/
struct property_entry *
property_entries_dup(const struct property_entry *properties)
{
struct property_entry *p;
int i, n = 0;
int ret;
if (!properties)
return NULL;
while (properties[n].name)
n++;
p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL);
if (!p)
return ERR_PTR(-ENOMEM);
for (i = 0; i < n; i++) {
ret = property_entry_copy_data(&p[i], &properties[i]);
if (ret) {
while (--i >= 0)
property_entry_free_data(&p[i]);
kfree(p);
return ERR_PTR(ret);
}
}
return p;
}
EXPORT_SYMBOL_GPL(property_entries_dup);
/**
* property_entries_free - free previously allocated array of properties
* @properties: array of properties to destroy
*
* This function frees given NULL-terminated array of property entries,
* along with their data.
*/
void property_entries_free(const struct property_entry *properties)
{
const struct property_entry *p;
if (!properties)
return;
for (p = properties; p->name; p++)
property_entry_free_data(p);
kfree(properties);
}
EXPORT_SYMBOL_GPL(property_entries_free);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
/* -------------------------------------------------------------------------- */
/* fwnode operations */
static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode)
{
struct swnode *swnode = to_swnode(fwnode);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
kobject_get(&swnode->kobj);
return &swnode->fwnode;
}
static void software_node_put(struct fwnode_handle *fwnode)
{
struct swnode *swnode = to_swnode(fwnode);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
kobject_put(&swnode->kobj);
}
static bool software_node_property_present(const struct fwnode_handle *fwnode,
const char *propname)
{
struct swnode *swnode = to_swnode(fwnode);
return !!property_entry_get(swnode->node->properties, propname);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
static int software_node_read_int_array(const struct fwnode_handle *fwnode,
const char *propname,
unsigned int elem_size, void *val,
size_t nval)
{
struct swnode *swnode = to_swnode(fwnode);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
return property_entry_read_int_array(swnode->node->properties, propname,
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
elem_size, val, nval);
}
static int software_node_read_string_array(const struct fwnode_handle *fwnode,
const char *propname,
const char **val, size_t nval)
{
struct swnode *swnode = to_swnode(fwnode);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
return property_entry_read_string_array(swnode->node->properties,
propname, val, nval);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
static const char *
software_node_get_name(const struct fwnode_handle *fwnode)
{
const struct swnode *swnode = to_swnode(fwnode);
return kobject_name(&swnode->kobj);
}
static const char *
software_node_get_name_prefix(const struct fwnode_handle *fwnode)
{
struct fwnode_handle *parent;
const char *prefix;
parent = fwnode_get_parent(fwnode);
if (!parent)
return "";
/* Figure out the prefix from the parents. */
while (is_software_node(parent))
parent = fwnode_get_next_parent(parent);
prefix = fwnode_get_name_prefix(parent);
fwnode_handle_put(parent);
/* Guess something if prefix was NULL. */
return prefix ?: "/";
}
static struct fwnode_handle *
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
software_node_get_parent(const struct fwnode_handle *fwnode)
{
struct swnode *swnode = to_swnode(fwnode);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
if (!swnode || !swnode->parent)
return NULL;
return fwnode_handle_get(&swnode->parent->fwnode);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
static struct fwnode_handle *
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
software_node_get_next_child(const struct fwnode_handle *fwnode,
struct fwnode_handle *child)
{
struct swnode *p = to_swnode(fwnode);
struct swnode *c = to_swnode(child);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
if (!p || list_empty(&p->children) ||
(c && list_is_last(&c->entry, &p->children))) {
fwnode_handle_put(child);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
return NULL;
}
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
if (c)
c = list_next_entry(c, entry);
else
c = list_first_entry(&p->children, struct swnode, entry);
fwnode_handle_put(child);
return fwnode_handle_get(&c->fwnode);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
static struct fwnode_handle *
software_node_get_named_child_node(const struct fwnode_handle *fwnode,
const char *childname)
{
struct swnode *swnode = to_swnode(fwnode);
struct swnode *child;
if (!swnode || list_empty(&swnode->children))
return NULL;
list_for_each_entry(child, &swnode->children, entry) {
if (!strcmp(childname, kobject_name(&child->kobj))) {
kobject_get(&child->kobj);
return &child->fwnode;
}
}
return NULL;
}
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
static int
software_node_get_reference_args(const struct fwnode_handle *fwnode,
const char *propname, const char *nargs_prop,
unsigned int nargs, unsigned int index,
struct fwnode_reference_args *args)
{
struct swnode *swnode = to_swnode(fwnode);
const struct software_node_ref_args *ref_array;
const struct software_node_ref_args *ref;
const struct property_entry *prop;
struct fwnode_handle *refnode;
u32 nargs_prop_val;
int error;
int i;
prop = property_entry_get(swnode->node->properties, propname);
if (!prop)
return -ENOENT;
if (prop->type != DEV_PROP_REF)
return -EINVAL;
/*
* We expect that references are never stored inline, even
* single ones, as they are too big.
*/
if (prop->is_inline)
return -EINVAL;
if (index * sizeof(*ref) >= prop->length)
return -ENOENT;
ref_array = prop->pointer;
ref = &ref_array[index];
refnode = software_node_fwnode(ref->node);
if (!refnode)
return -ENOENT;
if (nargs_prop) {
error = property_entry_read_int_array(ref->node->properties,
nargs_prop, sizeof(u32),
&nargs_prop_val, 1);
if (error)
return error;
nargs = nargs_prop_val;
}
if (nargs > NR_FWNODE_REFERENCE_ARGS)
return -EINVAL;
if (!args)
return 0;
args->fwnode = software_node_get(refnode);
args->nargs = nargs;
for (i = 0; i < nargs; i++)
args->args[i] = ref->args[i];
return 0;
}
static struct fwnode_handle *
swnode_graph_find_next_port(const struct fwnode_handle *parent,
struct fwnode_handle *port)
{
struct fwnode_handle *old = port;
while ((port = software_node_get_next_child(parent, old))) {
/*
* fwnode ports have naming style "port@", so we search for any
* children that follow that convention.
*/
if (!strncmp(to_swnode(port)->node->name, "port@",
strlen("port@")))
return port;
old = port;
}
return NULL;
}
static struct fwnode_handle *
software_node_graph_get_next_endpoint(const struct fwnode_handle *fwnode,
struct fwnode_handle *endpoint)
{
struct swnode *swnode = to_swnode(fwnode);
struct fwnode_handle *parent;
struct fwnode_handle *port;
if (!swnode)
return NULL;
if (endpoint) {
port = software_node_get_parent(endpoint);
parent = software_node_get_parent(port);
} else {
parent = software_node_get_named_child_node(fwnode, "ports");
if (!parent)
parent = software_node_get(&swnode->fwnode);
port = swnode_graph_find_next_port(parent, NULL);
}
for (; port; port = swnode_graph_find_next_port(parent, port)) {
endpoint = software_node_get_next_child(port, endpoint);
if (endpoint) {
fwnode_handle_put(port);
break;
}
}
fwnode_handle_put(parent);
return endpoint;
}
static struct fwnode_handle *
software_node_graph_get_remote_endpoint(const struct fwnode_handle *fwnode)
{
struct swnode *swnode = to_swnode(fwnode);
const struct software_node_ref_args *ref;
const struct property_entry *prop;
if (!swnode)
return NULL;
prop = property_entry_get(swnode->node->properties, "remote-endpoint");
if (!prop || prop->type != DEV_PROP_REF || prop->is_inline)
return NULL;
ref = prop->pointer;
return software_node_get(software_node_fwnode(ref[0].node));
}
static struct fwnode_handle *
software_node_graph_get_port_parent(struct fwnode_handle *fwnode)
{
struct swnode *swnode = to_swnode(fwnode);
swnode = swnode->parent;
if (swnode && !strcmp(swnode->node->name, "ports"))
swnode = swnode->parent;
return swnode ? software_node_get(&swnode->fwnode) : NULL;
}
static int
software_node_graph_parse_endpoint(const struct fwnode_handle *fwnode,
struct fwnode_endpoint *endpoint)
{
struct swnode *swnode = to_swnode(fwnode);
const char *parent_name = swnode->parent->node->name;
int ret;
if (strlen("port@") >= strlen(parent_name) ||
strncmp(parent_name, "port@", strlen("port@")))
return -EINVAL;
/* Ports have naming style "port@n", we need to select the n */
ret = kstrtou32(parent_name + strlen("port@"), 10, &endpoint->port);
if (ret)
return ret;
endpoint->id = swnode->id;
endpoint->local_fwnode = fwnode;
return 0;
}
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
static const struct fwnode_operations software_node_ops = {
.get = software_node_get,
.put = software_node_put,
.property_present = software_node_property_present,
.property_read_int_array = software_node_read_int_array,
.property_read_string_array = software_node_read_string_array,
.get_name = software_node_get_name,
.get_name_prefix = software_node_get_name_prefix,
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
.get_parent = software_node_get_parent,
.get_next_child_node = software_node_get_next_child,
.get_named_child_node = software_node_get_named_child_node,
.get_reference_args = software_node_get_reference_args,
.graph_get_next_endpoint = software_node_graph_get_next_endpoint,
.graph_get_remote_endpoint = software_node_graph_get_remote_endpoint,
.graph_get_port_parent = software_node_graph_get_port_parent,
.graph_parse_endpoint = software_node_graph_parse_endpoint,
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
};
/* -------------------------------------------------------------------------- */
/**
* software_node_find_by_name - Find software node by name
* @parent: Parent of the software node
* @name: Name of the software node
*
* The function will find a node that is child of @parent and that is named
* @name. If no node is found, the function returns NULL.
*
* NOTE: you will need to drop the reference with fwnode_handle_put() after use.
*/
const struct software_node *
software_node_find_by_name(const struct software_node *parent, const char *name)
{
struct swnode *swnode = NULL;
struct kobject *k;
if (!name)
return NULL;
spin_lock(&swnode_kset->list_lock);
list_for_each_entry(k, &swnode_kset->list, entry) {
swnode = kobj_to_swnode(k);
if (parent == swnode->node->parent && swnode->node->name &&
!strcmp(name, swnode->node->name)) {
kobject_get(&swnode->kobj);
break;
}
swnode = NULL;
}
spin_unlock(&swnode_kset->list_lock);
return swnode ? swnode->node : NULL;
}
EXPORT_SYMBOL_GPL(software_node_find_by_name);
static struct software_node *software_node_alloc(const struct property_entry *properties)
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
{
struct property_entry *props;
struct software_node *node;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
props = property_entries_dup(properties);
if (IS_ERR(props))
return ERR_CAST(props);
node = kzalloc(sizeof(*node), GFP_KERNEL);
if (!node) {
property_entries_free(props);
return ERR_PTR(-ENOMEM);
}
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
node->properties = props;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
return node;
}
static void software_node_free(const struct software_node *node)
{
property_entries_free(node->properties);
kfree(node);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
static void software_node_release(struct kobject *kobj)
{
struct swnode *swnode = kobj_to_swnode(kobj);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
Revert "software node: Simplify software_node_release() function" This reverts commit 3df85a1ae51f6b256982fe9d17c2dc5bfb4cc402. The reverted commit says "It's possible to release the node ID immediately when fwnode_remove_software_node() is called, no need to wait for software_node_release() with that." However, releasing the node ID before waiting for software_node_release() to be called causes the node ID to be released before the kobject and the underlying sysfs entry; this means there is a period of time where a sysfs entry exists that is associated with an unallocated node ID. Once consequence of this is that there is a race condition where it is possible to call fwnode_create_software_node() with no parent node specified (NULL) and have it fail with -EEXIST because the node ID that was assigned is still associated with a stale sysfs entry that hasn't been cleaned up yet. Although it is difficult to reproduce this race condition under normal conditions, it can be deterministically reproduced with the following minconfig on UML: CONFIG_KUNIT_DRIVER_PE_TEST=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_TIMERS=y CONFIG_DEBUG_KOBJECT_RELEASE=y CONFIG_KUNIT=y Running the tests with this configuration causes the following failure: <snip> kobject: 'node0' ((____ptrval____)): kobject_release, parent (____ptrval____) (delayed 400) ok 1 - pe_test_uints sysfs: cannot create duplicate filename '/kernel/software_nodes/node0' CPU: 0 PID: 28 Comm: kunit_try_catch Not tainted 5.6.0-rc3-next-20200227 #14 <snip> kobject_add_internal failed for node0 with -EEXIST, don't try to register things with the same name in the same directory. kobject: 'node0' ((____ptrval____)): kobject_release, parent (____ptrval____) (delayed 100) # pe_test_uint_arrays: ASSERTION FAILED at drivers/base/test/property-entry-test.c:123 Expected node is not error, but is: -17 not ok 2 - pe_test_uint_arrays <snip> Reported-by: Heidi Fahim <heidifahim@google.com> Signed-off-by: Brendan Higgins <brendanhiggins@google.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Cc: 5.3+ <stable@vger.kernel.org> # 5.3+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2020-02-28 00:00:01 +00:00
if (swnode->parent) {
ida_free(&swnode->parent->child_ids, swnode->id);
Revert "software node: Simplify software_node_release() function" This reverts commit 3df85a1ae51f6b256982fe9d17c2dc5bfb4cc402. The reverted commit says "It's possible to release the node ID immediately when fwnode_remove_software_node() is called, no need to wait for software_node_release() with that." However, releasing the node ID before waiting for software_node_release() to be called causes the node ID to be released before the kobject and the underlying sysfs entry; this means there is a period of time where a sysfs entry exists that is associated with an unallocated node ID. Once consequence of this is that there is a race condition where it is possible to call fwnode_create_software_node() with no parent node specified (NULL) and have it fail with -EEXIST because the node ID that was assigned is still associated with a stale sysfs entry that hasn't been cleaned up yet. Although it is difficult to reproduce this race condition under normal conditions, it can be deterministically reproduced with the following minconfig on UML: CONFIG_KUNIT_DRIVER_PE_TEST=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_TIMERS=y CONFIG_DEBUG_KOBJECT_RELEASE=y CONFIG_KUNIT=y Running the tests with this configuration causes the following failure: <snip> kobject: 'node0' ((____ptrval____)): kobject_release, parent (____ptrval____) (delayed 400) ok 1 - pe_test_uints sysfs: cannot create duplicate filename '/kernel/software_nodes/node0' CPU: 0 PID: 28 Comm: kunit_try_catch Not tainted 5.6.0-rc3-next-20200227 #14 <snip> kobject_add_internal failed for node0 with -EEXIST, don't try to register things with the same name in the same directory. kobject: 'node0' ((____ptrval____)): kobject_release, parent (____ptrval____) (delayed 100) # pe_test_uint_arrays: ASSERTION FAILED at drivers/base/test/property-entry-test.c:123 Expected node is not error, but is: -17 not ok 2 - pe_test_uint_arrays <snip> Reported-by: Heidi Fahim <heidifahim@google.com> Signed-off-by: Brendan Higgins <brendanhiggins@google.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Cc: 5.3+ <stable@vger.kernel.org> # 5.3+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2020-02-28 00:00:01 +00:00
list_del(&swnode->entry);
} else {
ida_free(&swnode_root_ids, swnode->id);
Revert "software node: Simplify software_node_release() function" This reverts commit 3df85a1ae51f6b256982fe9d17c2dc5bfb4cc402. The reverted commit says "It's possible to release the node ID immediately when fwnode_remove_software_node() is called, no need to wait for software_node_release() with that." However, releasing the node ID before waiting for software_node_release() to be called causes the node ID to be released before the kobject and the underlying sysfs entry; this means there is a period of time where a sysfs entry exists that is associated with an unallocated node ID. Once consequence of this is that there is a race condition where it is possible to call fwnode_create_software_node() with no parent node specified (NULL) and have it fail with -EEXIST because the node ID that was assigned is still associated with a stale sysfs entry that hasn't been cleaned up yet. Although it is difficult to reproduce this race condition under normal conditions, it can be deterministically reproduced with the following minconfig on UML: CONFIG_KUNIT_DRIVER_PE_TEST=y CONFIG_DEBUG_KERNEL=y CONFIG_DEBUG_OBJECTS=y CONFIG_DEBUG_OBJECTS_TIMERS=y CONFIG_DEBUG_KOBJECT_RELEASE=y CONFIG_KUNIT=y Running the tests with this configuration causes the following failure: <snip> kobject: 'node0' ((____ptrval____)): kobject_release, parent (____ptrval____) (delayed 400) ok 1 - pe_test_uints sysfs: cannot create duplicate filename '/kernel/software_nodes/node0' CPU: 0 PID: 28 Comm: kunit_try_catch Not tainted 5.6.0-rc3-next-20200227 #14 <snip> kobject_add_internal failed for node0 with -EEXIST, don't try to register things with the same name in the same directory. kobject: 'node0' ((____ptrval____)): kobject_release, parent (____ptrval____) (delayed 100) # pe_test_uint_arrays: ASSERTION FAILED at drivers/base/test/property-entry-test.c:123 Expected node is not error, but is: -17 not ok 2 - pe_test_uint_arrays <snip> Reported-by: Heidi Fahim <heidifahim@google.com> Signed-off-by: Brendan Higgins <brendanhiggins@google.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Cc: 5.3+ <stable@vger.kernel.org> # 5.3+ Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2020-02-28 00:00:01 +00:00
}
if (swnode->allocated)
software_node_free(swnode->node);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
ida_destroy(&swnode->child_ids);
kfree(swnode);
}
static const struct kobj_type software_node_type = {
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
.release = software_node_release,
.sysfs_ops = &kobj_sysfs_ops,
};
static struct fwnode_handle *
swnode_register(const struct software_node *node, struct swnode *parent,
unsigned int allocated)
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
{
struct swnode *swnode;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
int ret;
swnode = kzalloc(sizeof(*swnode), GFP_KERNEL);
if (!swnode)
return ERR_PTR(-ENOMEM);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
ret = ida_alloc(parent ? &parent->child_ids : &swnode_root_ids,
GFP_KERNEL);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
if (ret < 0) {
kfree(swnode);
return ERR_PTR(ret);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
swnode->id = ret;
swnode->node = node;
swnode->parent = parent;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
swnode->kobj.kset = swnode_kset;
fwnode_init(&swnode->fwnode, &software_node_ops);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
ida_init(&swnode->child_ids);
INIT_LIST_HEAD(&swnode->entry);
INIT_LIST_HEAD(&swnode->children);
if (node->name)
ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
parent ? &parent->kobj : NULL,
"%s", node->name);
else
ret = kobject_init_and_add(&swnode->kobj, &software_node_type,
parent ? &parent->kobj : NULL,
"node%d", swnode->id);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
if (ret) {
kobject_put(&swnode->kobj);
return ERR_PTR(ret);
}
/*
* Assign the flag only in the successful case, so
* the above kobject_put() won't mess up with properties.
*/
swnode->allocated = allocated;
if (parent)
list_add_tail(&swnode->entry, &parent->children);
kobject_uevent(&swnode->kobj, KOBJ_ADD);
return &swnode->fwnode;
}
/**
* software_node_register_node_group - Register a group of software nodes
* @node_group: NULL terminated array of software node pointers to be registered
*
* Register multiple software nodes at once. If any node in the array
* has its .parent pointer set (which can only be to another software_node),
* then its parent **must** have been registered before it is; either outside
* of this function or by ordering the array such that parent comes before
* child.
*/
int software_node_register_node_group(const struct software_node **node_group)
{
unsigned int i;
int ret;
if (!node_group)
return 0;
for (i = 0; node_group[i]; i++) {
ret = software_node_register(node_group[i]);
if (ret) {
software_node_unregister_node_group(node_group);
return ret;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(software_node_register_node_group);
/**
* software_node_unregister_node_group - Unregister a group of software nodes
* @node_group: NULL terminated array of software node pointers to be unregistered
*
* Unregister multiple software nodes at once. If parent pointers are set up
* in any of the software nodes then the array **must** be ordered such that
* parents come before their children.
*
* NOTE: If you are uncertain whether the array is ordered such that
* parents will be unregistered before their children, it is wiser to
* remove the nodes individually, in the correct order (child before
* parent).
*/
void software_node_unregister_node_group(
const struct software_node **node_group)
{
unsigned int i = 0;
if (!node_group)
return;
while (node_group[i])
i++;
while (i--)
software_node_unregister(node_group[i]);
}
EXPORT_SYMBOL_GPL(software_node_unregister_node_group);
/**
* software_node_register - Register static software node
* @node: The software node to be registered
*/
int software_node_register(const struct software_node *node)
{
struct swnode *parent = software_node_to_swnode(node->parent);
if (software_node_to_swnode(node))
return -EEXIST;
if (node->parent && !parent)
return -EINVAL;
return PTR_ERR_OR_ZERO(swnode_register(node, parent, 0));
}
EXPORT_SYMBOL_GPL(software_node_register);
software node: implement software_node_unregister() Sometimes it is better to unregister individual nodes instead of trying to do them all at once with software_node_unregister_nodes(), so create software_node_unregister() so that you can unregister them one at a time. This is especially important when creating nodes in a hierarchy, with parent -> children representations. Children always need to be removed before a parent is, as the swnode logic assumes this is going to be the case. Fix up the lib/test_printf.c fwnode_pointer() test which to use this new function as it had the problem of tearing things down in the backwards order. Fixes: f1ce39df508d ("lib/test_printf: Add tests for %pfw printk modifier") Cc: stable <stable@vger.kernel.org> Cc: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Cc: Brendan Higgins <brendanhiggins@google.com> Cc: Dmitry Torokhov <dmitry.torokhov@gmail.com> Cc: Petr Mladek <pmladek@suse.com> Cc: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Cc: Rasmus Villemoes <linux@rasmusvillemoes.dk> Cc: Sakari Ailus <sakari.ailus@linux.intel.com> Cc: Sergey Senozhatsky <sergey.senozhatsky@gmail.com> Cc: Steven Rostedt <rostedt@goodmis.org> Reported-by: Naresh Kamboju <naresh.kamboju@linaro.org> Reported-by: kernel test robot <rong.a.chen@intel.com> Reported-by: Randy Dunlap <rdunlap@infradead.org> Tested-by: Petr Mladek <pmladek@suse.com> Tested-by: Randy Dunlap <rdunlap@infradead.org> Tested-by: Guenter Roeck <linux@roeck-us.net> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Randy Dunlap <rdunlap@infradead.org> Link: https://lore.kernel.org/r/20200524153041.2361-1-gregkh@linuxfoundation.org Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2020-05-24 15:30:40 +00:00
/**
* software_node_unregister - Unregister static software node
* @node: The software node to be unregistered
*/
void software_node_unregister(const struct software_node *node)
{
struct swnode *swnode;
swnode = software_node_to_swnode(node);
if (swnode)
fwnode_remove_software_node(&swnode->fwnode);
}
EXPORT_SYMBOL_GPL(software_node_unregister);
struct fwnode_handle *
fwnode_create_software_node(const struct property_entry *properties,
const struct fwnode_handle *parent)
{
struct fwnode_handle *fwnode;
struct software_node *node;
struct swnode *p;
if (IS_ERR(parent))
return ERR_CAST(parent);
p = to_swnode(parent);
if (parent && !p)
return ERR_PTR(-EINVAL);
node = software_node_alloc(properties);
if (IS_ERR(node))
return ERR_CAST(node);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
node->parent = p ? p->node : NULL;
fwnode = swnode_register(node, p, 1);
if (IS_ERR(fwnode))
software_node_free(node);
return fwnode;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
EXPORT_SYMBOL_GPL(fwnode_create_software_node);
void fwnode_remove_software_node(struct fwnode_handle *fwnode)
{
struct swnode *swnode = to_swnode(fwnode);
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
if (!swnode)
return;
kobject_put(&swnode->kobj);
}
EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
/**
* device_add_software_node - Assign software node to a device
* @dev: The device the software node is meant for.
* @node: The software node.
*
* This function will make @node the secondary firmware node pointer of @dev. If
* @dev has no primary node, then @node will become the primary node. The
* function will register @node automatically if it wasn't already registered.
*/
int device_add_software_node(struct device *dev, const struct software_node *node)
{
struct swnode *swnode;
int ret;
/* Only one software node per device. */
if (dev_to_swnode(dev))
return -EBUSY;
swnode = software_node_to_swnode(node);
if (swnode) {
kobject_get(&swnode->kobj);
} else {
ret = software_node_register(node);
if (ret)
return ret;
swnode = software_node_to_swnode(node);
}
set_secondary_fwnode(dev, &swnode->fwnode);
/*
* If the device has been fully registered by the time this function is
* called, software_node_notify() must be called separately so that the
* symlinks get created and the reference count of the node is kept in
* balance.
*/
if (device_is_registered(dev))
software_node_notify(dev);
return 0;
}
EXPORT_SYMBOL_GPL(device_add_software_node);
/**
* device_remove_software_node - Remove device's software node
* @dev: The device with the software node.
*
* This function will unregister the software node of @dev.
*/
void device_remove_software_node(struct device *dev)
{
struct swnode *swnode;
swnode = dev_to_swnode(dev);
if (!swnode)
return;
if (device_is_registered(dev))
software_node_notify_remove(dev);
set_secondary_fwnode(dev, NULL);
kobject_put(&swnode->kobj);
}
EXPORT_SYMBOL_GPL(device_remove_software_node);
software node: Provide replacement for device_add_properties() At the moment the function device_del() is calling device_remove_properties() unconditionally. That will result into the reference count of the software node attached to the device being decremented, and in most cases it will hit 0 at that point. So in practice device_del() will unregister the software node attached to the device, even if that was not the intention of the caller. Right now software nodes can not be reused or shared because of that. So device_del() can not unregister the software nodes unconditionally like that. Unfortunately some of the users of device_add_properties() are now relying on this behaviour. Because of that, and also in general, we do need a function that can offer similar behaviour where the lifetime of the software node is bound to the lifetime of the device. But it just has to be a separate function so the behaviour is optional. We can not remove the device_remove_properties() call from device_del() before we have that new function, and before we have replaced device_add_properties() calls with it in all the places that require that behaviour. This adds function device_create_managed_software_node() that can be used for exactly that purpose. Software nodes created with it are declared "managed", and separate handling for those nodes is added to the software node code. The reference count of the "managed" nodes is decremented when the device they are attached to is removed. This will not affect the other nodes that are not declared "managed". The function device_create_managed_software_node() has also one additional feature that device_add_properties() does not have. It allows the software nodes created with it to be part of a node hierarchy by taking also an optional parent node as parameter. Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://lore.kernel.org/r/20210204141711.53775-2-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-02-04 14:17:06 +00:00
/**
* 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);
software node: balance refcount for managed software nodes software_node_notify(), on KOBJ_REMOVE drops the refcount twice on managed software nodes, thus leading to underflow errors. Balance the refcount by bumping it in the device_create_managed_software_node() function. The error [1] was encountered after adding a .shutdown() op to our fsl-mc-bus driver. [1] pc : refcount_warn_saturate+0xf8/0x150 lr : refcount_warn_saturate+0xf8/0x150 sp : ffff80001009b920 x29: ffff80001009b920 x28: ffff1a2420318000 x27: 0000000000000000 x26: ffffccac15e7a038 x25: 0000000000000008 x24: ffffccac168e0030 x23: ffff1a2428a82000 x22: 0000000000080000 x21: ffff1a24287b5000 x20: 0000000000000001 x19: ffff1a24261f4400 x18: ffffffffffffffff x17: 6f72645f726f7272 x16: 0000000000000000 x15: ffff80009009b607 x14: 0000000000000000 x13: ffffccac16602670 x12: 0000000000000a17 x11: 000000000000035d x10: ffffccac16602670 x9 : ffffccac16602670 x8 : 00000000ffffefff x7 : ffffccac1665a670 x6 : ffffccac1665a670 x5 : 0000000000000000 x4 : 0000000000000000 x3 : 00000000ffffffff x2 : 0000000000000000 x1 : 0000000000000000 x0 : ffff1a2420318000 Call trace: refcount_warn_saturate+0xf8/0x150 kobject_put+0x10c/0x120 software_node_notify+0xd8/0x140 device_platform_notify+0x4c/0xb4 device_del+0x188/0x424 fsl_mc_device_remove+0x2c/0x4c rebofind sp.c__fsl_mc_device_remove+0x14/0x2c device_for_each_child+0x5c/0xac dprc_remove+0x9c/0xc0 fsl_mc_driver_remove+0x28/0x64 __device_release_driver+0x188/0x22c device_release_driver+0x30/0x50 bus_remove_device+0x128/0x134 device_del+0x16c/0x424 fsl_mc_bus_remove+0x8c/0x114 fsl_mc_bus_shutdown+0x14/0x20 platform_shutdown+0x28/0x40 device_shutdown+0x15c/0x330 __do_sys_reboot+0x218/0x2a0 __arm64_sys_reboot+0x28/0x34 invoke_syscall+0x48/0x114 el0_svc_common+0x40/0xdc do_el0_svc+0x2c/0x94 el0_svc+0x2c/0x54 el0t_64_sync_handler+0xa8/0x12c el0t_64_sync+0x198/0x19c ---[ end trace 32eb1c71c7d86821 ]--- Fixes: 151f6ff78cdf ("software node: Provide replacement for device_add_properties()") Reported-by: Jon Nettleton <jon@solid-run.com> Suggested-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Reviewed-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Signed-off-by: Laurentiu Tudor <laurentiu.tudor@nxp.com> Cc: 5.12+ <stable@vger.kernel.org> # 5.12+ [ rjw: Fix up the software_node_notify() invocation ] Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2021-09-15 08:09:39 +00:00
if (device_is_registered(dev))
software_node_notify(dev);
software node: Provide replacement for device_add_properties() At the moment the function device_del() is calling device_remove_properties() unconditionally. That will result into the reference count of the software node attached to the device being decremented, and in most cases it will hit 0 at that point. So in practice device_del() will unregister the software node attached to the device, even if that was not the intention of the caller. Right now software nodes can not be reused or shared because of that. So device_del() can not unregister the software nodes unconditionally like that. Unfortunately some of the users of device_add_properties() are now relying on this behaviour. Because of that, and also in general, we do need a function that can offer similar behaviour where the lifetime of the software node is bound to the lifetime of the device. But it just has to be a separate function so the behaviour is optional. We can not remove the device_remove_properties() call from device_del() before we have that new function, and before we have replaced device_add_properties() calls with it in all the places that require that behaviour. This adds function device_create_managed_software_node() that can be used for exactly that purpose. Software nodes created with it are declared "managed", and separate handling for those nodes is added to the software node code. The reference count of the "managed" nodes is decremented when the device they are attached to is removed. This will not affect the other nodes that are not declared "managed". The function device_create_managed_software_node() has also one additional feature that device_add_properties() does not have. It allows the software nodes created with it to be part of a node hierarchy by taking also an optional parent node as parameter. Reviewed-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Link: https://lore.kernel.org/r/20210204141711.53775-2-heikki.krogerus@linux.intel.com Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
2021-02-04 14:17:06 +00:00
return 0;
}
EXPORT_SYMBOL_GPL(device_create_managed_software_node);
void software_node_notify(struct device *dev)
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
{
struct swnode *swnode;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
int ret;
swnode = dev_to_swnode(dev);
if (!swnode)
return;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node");
if (ret)
return;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
ret = sysfs_create_link(&swnode->kobj, &dev->kobj, dev_name(dev));
if (ret) {
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
sysfs_remove_link(&dev->kobj, "software_node");
return;
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
kobject_get(&swnode->kobj);
}
void software_node_notify_remove(struct device *dev)
{
struct swnode *swnode;
swnode = dev_to_swnode(dev);
if (!swnode)
return;
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);
}
drivers: base: Introducing software nodes to the firmware node framework Software node is a new struct fwnode_handle type that can be used to describe devices in kernel (software). It is meant to complement fwnodes representing real firmware nodes when they are incomplete (for example missing device properties) and to supply the primary fwnode when the firmware lacks hardware description for a device completely. The software node type is really meant to replace the currently used "property_set" struct fwnode_handle type. The handling of struct property_set is glued to the generic device property handling code, and it is not possible to create a struct property_set independently from the device that it is bind to. struct property_set is only created when device properties are added to already initialized struct device, and control of it is only possible from the generic property handling code. Software nodes are instead designed to be created independently from the device entries (struct device). It makes them much more flexible, as then the device meant to be bind to the node can be created at a later time, and from another location. It is also possible to bind multiple devices to a single software node if needed. The software node implementation also includes support for node hierarchy, which was the main motivation for this commit. The node hierarchy was something that was requested for the struct property_set, but it did not seem reasonable to try to extend the property_set support for that purpose. struct property_set was really meant only for device property handling like the name suggests. Support for struct property_set is not yet removed in this commit, but it will be in the following one. Signed-off-by: Heikki Krogerus <heikki.krogerus@linux.intel.com> Acked-by: Linus Walleij <linus.walleij@linaro.org> Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
2018-11-09 14:21:36 +00:00
}
static int __init software_node_init(void)
{
swnode_kset = kset_create_and_add("software_nodes", NULL, kernel_kobj);
if (!swnode_kset)
return -ENOMEM;
return 0;
}
postcore_initcall(software_node_init);
static void __exit software_node_exit(void)
{
ida_destroy(&swnode_root_ids);
kset_unregister(swnode_kset);
}
__exitcall(software_node_exit);