diff options
Diffstat (limited to 'drivers/base/swnode.c')
| -rw-r--r-- | drivers/base/swnode.c | 99 |
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); |
