Merge branch 'devicetree/next-overlay' into devicetree/next

Conflicts:
	drivers/of/testcase-data/testcases.dts
This commit is contained in:
Grant Likely
2014-08-11 14:06:23 +01:00
14 changed files with 1058 additions and 447 deletions

View File

@@ -38,13 +38,15 @@ struct device_node *of_chosen;
struct device_node *of_aliases;
struct device_node *of_stdout;
static struct kset *of_kset;
struct kset *of_kset;
/*
* Used to protect the of_aliases; but also overloaded to hold off addition of
* nodes to sysfs
* Used to protect the of_aliases, to hold off addition of nodes to sysfs.
* This mutex must be held whenever modifications are being made to the
* device tree. The of_{attach,detach}_node() and
* of_{add,remove,update}_property() helpers make sure this happens.
*/
DEFINE_MUTEX(of_aliases_mutex);
DEFINE_MUTEX(of_mutex);
/* use when traversing tree through the allnext, child, sibling,
* or parent members of struct device_node.
@@ -90,79 +92,7 @@ int __weak of_node_to_nid(struct device_node *np)
}
#endif
#if defined(CONFIG_OF_DYNAMIC)
/**
* of_node_get - Increment refcount of a node
* @node: Node to inc refcount, NULL is supported to
* simplify writing of callers
*
* Returns node.
*/
struct device_node *of_node_get(struct device_node *node)
{
if (node)
kobject_get(&node->kobj);
return node;
}
EXPORT_SYMBOL(of_node_get);
static inline struct device_node *kobj_to_device_node(struct kobject *kobj)
{
return container_of(kobj, struct device_node, kobj);
}
/**
* of_node_release - release a dynamically allocated node
* @kref: kref element of the node to be released
*
* In of_node_put() this function is passed to kref_put()
* as the destructor.
*/
static void of_node_release(struct kobject *kobj)
{
struct device_node *node = kobj_to_device_node(kobj);
struct property *prop = node->properties;
/* We should never be releasing nodes that haven't been detached. */
if (!of_node_check_flag(node, OF_DETACHED)) {
pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name);
dump_stack();
return;
}
if (!of_node_check_flag(node, OF_DYNAMIC))
return;
while (prop) {
struct property *next = prop->next;
kfree(prop->name);
kfree(prop->value);
kfree(prop);
prop = next;
if (!prop) {
prop = node->deadprops;
node->deadprops = NULL;
}
}
kfree(node->full_name);
kfree(node->data);
kfree(node);
}
/**
* of_node_put - Decrement refcount of a node
* @node: Node to dec refcount, NULL is supported to
* simplify writing of callers
*
*/
void of_node_put(struct device_node *node)
{
if (node)
kobject_put(&node->kobj);
}
EXPORT_SYMBOL(of_node_put);
#else
#ifndef CONFIG_OF_DYNAMIC
static void of_node_release(struct kobject *kobj)
{
/* Without CONFIG_OF_DYNAMIC, no nodes gets freed */
@@ -201,13 +131,16 @@ static const char *safe_name(struct kobject *kobj, const char *orig_name)
return name;
}
static int __of_add_property_sysfs(struct device_node *np, struct property *pp)
int __of_add_property_sysfs(struct device_node *np, struct property *pp)
{
int rc;
/* Important: Don't leak passwords */
bool secure = strncmp(pp->name, "security-", 9) == 0;
if (!of_kset || !of_node_is_attached(np))
return 0;
sysfs_bin_attr_init(&pp->attr);
pp->attr.attr.name = safe_name(&np->kobj, pp->name);
pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO;
@@ -219,12 +152,15 @@ static int __of_add_property_sysfs(struct device_node *np, struct property *pp)
return rc;
}
static int __of_node_add(struct device_node *np)
int __of_attach_node_sysfs(struct device_node *np)
{
const char *name;
struct property *pp;
int rc;
if (!of_kset)
return 0;
np->kobj.kset = of_kset;
if (!np->parent) {
/* Nodes without parents are new top level trees */
@@ -246,59 +182,20 @@ static int __of_node_add(struct device_node *np)
return 0;
}
int of_node_add(struct device_node *np)
{
int rc = 0;
BUG_ON(!of_node_is_initialized(np));
/*
* Grab the mutex here so that in a race condition between of_init() and
* of_node_add(), node addition will still be consistent.
*/
mutex_lock(&of_aliases_mutex);
if (of_kset)
rc = __of_node_add(np);
else
/* This scenario may be perfectly valid, but report it anyway */
pr_info("of_node_add(%s) before of_init()\n", np->full_name);
mutex_unlock(&of_aliases_mutex);
return rc;
}
#if defined(CONFIG_OF_DYNAMIC)
static void of_node_remove(struct device_node *np)
{
struct property *pp;
BUG_ON(!of_node_is_initialized(np));
/* only remove properties if on sysfs */
if (of_node_is_attached(np)) {
for_each_property_of_node(np, pp)
sysfs_remove_bin_file(&np->kobj, &pp->attr);
kobject_del(&np->kobj);
}
/* finally remove the kobj_init ref */
of_node_put(np);
}
#endif
static int __init of_init(void)
{
struct device_node *np;
/* Create the kset, and register existing nodes */
mutex_lock(&of_aliases_mutex);
mutex_lock(&of_mutex);
of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);
if (!of_kset) {
mutex_unlock(&of_aliases_mutex);
mutex_unlock(&of_mutex);
return -ENOMEM;
}
for_each_of_allnodes(np)
__of_node_add(np);
mutex_unlock(&of_aliases_mutex);
__of_attach_node_sysfs(np);
mutex_unlock(&of_mutex);
/* Symlink in /proc as required by userspace ABI */
if (of_allnodes)
@@ -370,8 +267,8 @@ EXPORT_SYMBOL(of_find_all_nodes);
* Find a property with a given name for a given node
* and return the value.
*/
static const void *__of_get_property(const struct device_node *np,
const char *name, int *lenp)
const void *__of_get_property(const struct device_node *np,
const char *name, int *lenp)
{
struct property *pp = __of_find_property(np, name, lenp);
@@ -1749,32 +1646,10 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_na
}
EXPORT_SYMBOL(of_count_phandle_with_args);
#if defined(CONFIG_OF_DYNAMIC)
static int of_property_notify(int action, struct device_node *np,
struct property *prop)
{
struct of_prop_reconfig pr;
/* only call notifiers if the node is attached */
if (!of_node_is_attached(np))
return 0;
pr.dn = np;
pr.prop = prop;
return of_reconfig_notify(action, &pr);
}
#else
static int of_property_notify(int action, struct device_node *np,
struct property *prop)
{
return 0;
}
#endif
/**
* __of_add_property - Add a property to a node without lock operations
*/
static int __of_add_property(struct device_node *np, struct property *prop)
int __of_add_property(struct device_node *np, struct property *prop)
{
struct property **next;
@@ -1800,22 +1675,49 @@ int of_add_property(struct device_node *np, struct property *prop)
unsigned long flags;
int rc;
rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop);
if (rc)
return rc;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags);
rc = __of_add_property(np, prop);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (rc)
return rc;
if (of_node_is_attached(np))
if (!rc)
__of_add_property_sysfs(np, prop);
mutex_unlock(&of_mutex);
if (!rc)
of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop, NULL);
return rc;
}
int __of_remove_property(struct device_node *np, struct property *prop)
{
struct property **next;
for (next = &np->properties; *next; next = &(*next)->next) {
if (*next == prop)
break;
}
if (*next == NULL)
return -ENODEV;
/* found the node */
*next = prop->next;
prop->next = np->deadprops;
np->deadprops = prop;
return 0;
}
void __of_remove_property_sysfs(struct device_node *np, struct property *prop)
{
/* at early boot, bail here and defer setup to of_init() */
if (of_kset && of_node_is_attached(np))
sysfs_remove_bin_file(&np->kobj, &prop->attr);
}
/**
* of_remove_property - Remove a property from a node.
*
@@ -1826,42 +1728,64 @@ int of_add_property(struct device_node *np, struct property *prop)
*/
int of_remove_property(struct device_node *np, struct property *prop)
{
struct property **next;
unsigned long flags;
int found = 0;
int rc;
rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop);
if (rc)
return rc;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags);
next = &np->properties;
while (*next) {
if (*next == prop) {
/* found the node */
*next = prop->next;
prop->next = np->deadprops;
np->deadprops = prop;
found = 1;
break;
}
next = &(*next)->next;
}
rc = __of_remove_property(np, prop);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (!found)
return -ENODEV;
if (!rc)
__of_remove_property_sysfs(np, prop);
/* at early boot, bail hear and defer setup to of_init() */
if (!of_kset)
return 0;
mutex_unlock(&of_mutex);
sysfs_remove_bin_file(&np->kobj, &prop->attr);
if (!rc)
of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop, NULL);
return rc;
}
int __of_update_property(struct device_node *np, struct property *newprop,
struct property **oldpropp)
{
struct property **next, *oldprop;
for (next = &np->properties; *next; next = &(*next)->next) {
if (of_prop_cmp((*next)->name, newprop->name) == 0)
break;
}
*oldpropp = oldprop = *next;
if (oldprop) {
/* replace the node */
newprop->next = oldprop->next;
*next = newprop;
oldprop->next = np->deadprops;
np->deadprops = oldprop;
} else {
/* new node */
newprop->next = NULL;
*next = newprop;
}
return 0;
}
void __of_update_property_sysfs(struct device_node *np, struct property *newprop,
struct property *oldprop)
{
/* At early boot, bail out and defer setup to of_init() */
if (!of_kset)
return;
if (oldprop)
sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
__of_add_property_sysfs(np, newprop);
}
/*
* of_update_property - Update a property in a node, if the property does
* not exist, add it.
@@ -1873,164 +1797,29 @@ int of_remove_property(struct device_node *np, struct property *prop)
*/
int of_update_property(struct device_node *np, struct property *newprop)
{
struct property **next, *oldprop;
struct property *oldprop;
unsigned long flags;
int rc;
rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
if (rc)
return rc;
if (!newprop->name)
return -EINVAL;
raw_spin_lock_irqsave(&devtree_lock, flags);
next = &np->properties;
oldprop = __of_find_property(np, newprop->name, NULL);
if (!oldprop) {
/* add the new node */
rc = __of_add_property(np, newprop);
} else while (*next) {
/* replace the node */
if (*next == oldprop) {
newprop->next = oldprop->next;
*next = newprop;
oldprop->next = np->deadprops;
np->deadprops = oldprop;
break;
}
next = &(*next)->next;
}
raw_spin_unlock_irqrestore(&devtree_lock, flags);
if (rc)
return rc;
/* At early boot, bail out and defer setup to of_init() */
if (!of_kset)
return 0;
/* Update the sysfs attribute */
if (oldprop)
sysfs_remove_bin_file(&np->kobj, &oldprop->attr);
__of_add_property_sysfs(np, newprop);
return 0;
}
#if defined(CONFIG_OF_DYNAMIC)
/*
* Support for dynamic device trees.
*
* On some platforms, the device tree can be manipulated at runtime.
* The routines in this section support adding, removing and changing
* device tree nodes.
*/
static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain);
int of_reconfig_notifier_register(struct notifier_block *nb)
{
return blocking_notifier_chain_register(&of_reconfig_chain, nb);
}
EXPORT_SYMBOL_GPL(of_reconfig_notifier_register);
int of_reconfig_notifier_unregister(struct notifier_block *nb)
{
return blocking_notifier_chain_unregister(&of_reconfig_chain, nb);
}
EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister);
int of_reconfig_notify(unsigned long action, void *p)
{
int rc;
rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p);
return notifier_to_errno(rc);
}
/**
* of_attach_node - Plug a device node into the tree and global list.
*/
int of_attach_node(struct device_node *np)
{
unsigned long flags;
int rc;
rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np);
if (rc)
return rc;
mutex_lock(&of_mutex);
raw_spin_lock_irqsave(&devtree_lock, flags);
np->sibling = np->parent->child;
np->allnext = np->parent->allnext;
np->parent->allnext = np;
np->parent->child = np;
of_node_clear_flag(np, OF_DETACHED);
rc = __of_update_property(np, newprop, &oldprop);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
of_node_add(np);
return 0;
}
if (!rc)
__of_update_property_sysfs(np, newprop, oldprop);
/**
* of_detach_node - "Unplug" a node from the device tree.
*
* The caller must hold a reference to the node. The memory associated with
* the node is not freed until its refcount goes to zero.
*/
int of_detach_node(struct device_node *np)
{
struct device_node *parent;
unsigned long flags;
int rc = 0;
mutex_unlock(&of_mutex);
rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np);
if (rc)
return rc;
if (!rc)
of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop, oldprop);
raw_spin_lock_irqsave(&devtree_lock, flags);
if (of_node_check_flag(np, OF_DETACHED)) {
/* someone already detached it */
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return rc;
}
parent = np->parent;
if (!parent) {
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return rc;
}
if (of_allnodes == np)
of_allnodes = np->allnext;
else {
struct device_node *prev;
for (prev = of_allnodes;
prev->allnext != np;
prev = prev->allnext)
;
prev->allnext = np->allnext;
}
if (parent->child == np)
parent->child = np->sibling;
else {
struct device_node *prevsib;
for (prevsib = np->parent->child;
prevsib->sibling != np;
prevsib = prevsib->sibling)
;
prevsib->sibling = np->sibling;
}
of_node_set_flag(np, OF_DETACHED);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
of_node_remove(np);
return rc;
}
#endif /* defined(CONFIG_OF_DYNAMIC) */
static void of_alias_add(struct alias_prop *ap, struct device_node *np,
int id, const char *stem, int stem_len)
@@ -2126,7 +1915,7 @@ int of_alias_get_id(struct device_node *np, const char *stem)
struct alias_prop *app;
int id = -ENODEV;
mutex_lock(&of_aliases_mutex);
mutex_lock(&of_mutex);
list_for_each_entry(app, &aliases_lookup, link) {
if (strcmp(app->stem, stem) != 0)
continue;
@@ -2136,7 +1925,7 @@ int of_alias_get_id(struct device_node *np, const char *stem)
break;
}
}
mutex_unlock(&of_aliases_mutex);
mutex_unlock(&of_mutex);
return id;
}