summaryrefslogtreecommitdiff
path: root/drivers/base/swnode.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/base/swnode.c')
-rw-r--r--drivers/base/swnode.c99
1 files changed, 57 insertions, 42 deletions
diff --git a/drivers/base/swnode.c b/drivers/base/swnode.c
index b1726a3515f6..869228a65cb3 100644
--- a/drivers/base/swnode.c
+++ b/drivers/base/swnode.c
@@ -332,7 +332,7 @@ property_entries_dup(const struct property_entry *properties)
while (properties[n].name)
n++;
- p = kcalloc(n + 1, sizeof(*p), GFP_KERNEL);
+ p = kzalloc_objs(*p, n + 1);
if (!p)
return ERR_PTR(-ENOMEM);
@@ -374,20 +374,28 @@ EXPORT_SYMBOL_GPL(property_entries_free);
/* -------------------------------------------------------------------------- */
/* fwnode operations */
-static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode)
+static struct swnode *swnode_get(struct swnode *swnode)
{
- struct swnode *swnode = to_swnode(fwnode);
-
kobject_get(&swnode->kobj);
+ return swnode;
+}
+
+static void swnode_put(struct swnode *swnode)
+{
+ kobject_put(&swnode->kobj);
+}
+
+static struct fwnode_handle *software_node_get(struct fwnode_handle *fwnode)
+{
+ struct swnode *swnode = swnode_get(to_swnode(fwnode));
+
return &swnode->fwnode;
}
static void software_node_put(struct fwnode_handle *fwnode)
{
- struct swnode *swnode = to_swnode(fwnode);
-
- kobject_put(&swnode->kobj);
+ swnode_put(to_swnode(fwnode));
}
static bool software_node_property_present(const struct fwnode_handle *fwnode,
@@ -493,7 +501,7 @@ software_node_get_named_child_node(const struct fwnode_handle *fwnode,
list_for_each_entry(child, &swnode->children, entry) {
if (!strcmp(childname, kobject_name(&child->kobj))) {
- kobject_get(&child->kobj);
+ swnode_get(child);
return &child->fwnode;
}
}
@@ -529,20 +537,35 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
if (prop->is_inline)
return -EINVAL;
- if (index * sizeof(*ref) >= prop->length)
+ if ((index + 1) * sizeof(*ref) > prop->length)
return -ENOENT;
ref_array = prop->pointer;
ref = &ref_array[index];
- refnode = software_node_fwnode(ref->node);
+ /*
+ * A software node can reference other software nodes or firmware
+ * nodes (which are the abstraction layer sitting on top of them).
+ * This is done to ensure we can create references to static software
+ * nodes before they're registered with the firmware node framework.
+ * At the time the reference is being resolved, we expect the swnodes
+ * in question to already have been registered and to be backed by
+ * a firmware node. This is why we use the fwnode API below to read the
+ * relevant properties and bump the reference count.
+ */
+
+ if (ref->swnode)
+ refnode = software_node_fwnode(ref->swnode);
+ else if (ref->fwnode)
+ refnode = ref->fwnode;
+ else
+ return -EINVAL;
+
if (!refnode)
- return -ENOENT;
+ return -ENOTCONN;
if (nargs_prop) {
- error = property_entry_read_int_array(ref->node->properties,
- nargs_prop, sizeof(u32),
- &nargs_prop_val, 1);
+ error = fwnode_property_read_u32(refnode, nargs_prop, &nargs_prop_val);
if (error)
return error;
@@ -555,7 +578,7 @@ software_node_get_reference_args(const struct fwnode_handle *fwnode,
if (!args)
return 0;
- args->fwnode = software_node_get(refnode);
+ args->fwnode = fwnode_handle_get(refnode);
args->nargs = nargs;
for (i = 0; i < nargs; i++)
@@ -635,7 +658,10 @@ software_node_graph_get_remote_endpoint(const struct fwnode_handle *fwnode)
ref = prop->pointer;
- return software_node_get(software_node_fwnode(ref[0].node));
+ if (!ref->swnode)
+ return NULL;
+
+ return software_node_get(software_node_fwnode(ref->swnode));
}
static struct fwnode_handle *
@@ -719,7 +745,7 @@ software_node_find_by_name(const struct software_node *parent, const char *name)
swnode = kobj_to_swnode(k);
if (parent == swnode->node->parent && swnode->node->name &&
!strcmp(name, swnode->node->name)) {
- kobject_get(&swnode->kobj);
+ swnode_get(swnode);
break;
}
swnode = NULL;
@@ -740,7 +766,7 @@ static struct software_node *software_node_alloc(const struct property_entry *pr
if (IS_ERR(props))
return ERR_CAST(props);
- node = kzalloc(sizeof(*node), GFP_KERNEL);
+ node = kzalloc_obj(*node);
if (!node) {
property_entries_free(props);
return ERR_PTR(-ENOMEM);
@@ -787,7 +813,7 @@ swnode_register(const struct software_node *node, struct swnode *parent,
struct swnode *swnode;
int ret;
- swnode = kzalloc(sizeof(*swnode), GFP_KERNEL);
+ swnode = kzalloc_obj(*swnode);
if (!swnode)
return ERR_PTR(-ENOMEM);
@@ -817,13 +843,13 @@ swnode_register(const struct software_node *node, struct swnode *parent,
parent ? &parent->kobj : NULL,
"node%d", swnode->id);
if (ret) {
- kobject_put(&swnode->kobj);
+ swnode_put(swnode);
return ERR_PTR(ret);
}
/*
* Assign the flag only in the successful case, so
- * the above kobject_put() won't mess up with properties.
+ * the above swnode_put() won't mess up with properties.
*/
swnode->allocated = allocated;
@@ -844,7 +870,7 @@ swnode_register(const struct software_node *node, struct swnode *parent,
* 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)
+int software_node_register_node_group(const struct software_node * const *node_group)
{
unsigned int i;
int ret;
@@ -877,8 +903,7 @@ EXPORT_SYMBOL_GPL(software_node_register_node_group);
* remove the nodes individually, in the correct order (child before
* parent).
*/
-void software_node_unregister_node_group(
- const struct software_node **node_group)
+void software_node_unregister_node_group(const struct software_node * const *node_group)
{
unsigned int i = 0;
@@ -961,7 +986,7 @@ void fwnode_remove_software_node(struct fwnode_handle *fwnode)
if (!swnode)
return;
- kobject_put(&swnode->kobj);
+ swnode_put(swnode);
}
EXPORT_SYMBOL_GPL(fwnode_remove_software_node);
@@ -985,7 +1010,7 @@ int device_add_software_node(struct device *dev, const struct software_node *nod
swnode = software_node_to_swnode(node);
if (swnode) {
- kobject_get(&swnode->kobj);
+ swnode_get(swnode);
} else {
ret = software_node_register(node);
if (ret)
@@ -1027,7 +1052,7 @@ void device_remove_software_node(struct device *dev)
software_node_notify_remove(dev);
set_secondary_fwnode(dev, NULL);
- kobject_put(&swnode->kobj);
+ swnode_put(swnode);
}
EXPORT_SYMBOL_GPL(device_remove_software_node);
@@ -1080,6 +1105,7 @@ void software_node_notify(struct device *dev)
if (!swnode)
return;
+ swnode_get(swnode);
ret = sysfs_create_link(&dev->kobj, &swnode->kobj, "software_node");
if (ret)
return;
@@ -1089,8 +1115,6 @@ void software_node_notify(struct device *dev)
sysfs_remove_link(&dev->kobj, "software_node");
return;
}
-
- kobject_get(&swnode->kobj);
}
void software_node_notify_remove(struct device *dev)
@@ -1103,26 +1127,17 @@ void software_node_notify_remove(struct device *dev)
sysfs_remove_link(&swnode->kobj, dev_name(dev));
sysfs_remove_link(&dev->kobj, "software_node");
- kobject_put(&swnode->kobj);
+ swnode_put(swnode);
if (swnode->managed) {
set_secondary_fwnode(dev, NULL);
- kobject_put(&swnode->kobj);
+ swnode_put(swnode);
}
}
-static int __init software_node_init(void)
+void __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);
+ pr_err("failed to register software nodes\n");
}
-__exitcall(software_node_exit);