Merge tag 'kvm-3.9-1' of git://git.kernel.org/pub/scm/virt/kvm/kvm
[cascardo/linux.git] / drivers / of / base.c
index 2390ddb..321d3ef 100644 (file)
 #include <linux/slab.h>
 #include <linux/proc_fs.h>
 
-/**
- * struct alias_prop - Alias property in 'aliases' node
- * @link:      List node to link the structure in aliases_lookup list
- * @alias:     Alias property name
- * @np:                Pointer to device_node that the alias stands for
- * @id:                Index value from end of alias name
- * @stem:      Alias string without the index
- *
- * The structure represents one alias property of 'aliases' node as
- * an entry in aliases_lookup list.
- */
-struct alias_prop {
-       struct list_head link;
-       const char *alias;
-       struct device_node *np;
-       int id;
-       char stem[0];
-};
+#include "of_private.h"
 
-static LIST_HEAD(aliases_lookup);
+LIST_HEAD(aliases_lookup);
 
 struct device_node *of_allnodes;
 EXPORT_SYMBOL(of_allnodes);
 struct device_node *of_chosen;
 struct device_node *of_aliases;
 
-static DEFINE_MUTEX(of_aliases_mutex);
+DEFINE_MUTEX(of_aliases_mutex);
 
 /* use when traversing tree through the allnext, child, sibling,
  * or parent members of struct device_node.
  */
-DEFINE_RWLOCK(devtree_lock);
+DEFINE_RAW_SPINLOCK(devtree_lock);
 
 int of_n_addr_cells(struct device_node *np)
 {
@@ -164,16 +147,14 @@ void of_node_put(struct device_node *node)
 EXPORT_SYMBOL(of_node_put);
 #endif /* CONFIG_OF_DYNAMIC */
 
-struct property *of_find_property(const struct device_node *np,
-                                 const char *name,
-                                 int *lenp)
+static struct property *__of_find_property(const struct device_node *np,
+                                          const char *name, int *lenp)
 {
        struct property *pp;
 
        if (!np)
                return NULL;
 
-       read_lock(&devtree_lock);
        for (pp = np->properties; pp; pp = pp->next) {
                if (of_prop_cmp(pp->name, name) == 0) {
                        if (lenp)
@@ -181,7 +162,20 @@ struct property *of_find_property(const struct device_node *np,
                        break;
                }
        }
-       read_unlock(&devtree_lock);
+
+       return pp;
+}
+
+struct property *of_find_property(const struct device_node *np,
+                                 const char *name,
+                                 int *lenp)
+{
+       struct property *pp;
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&devtree_lock, flags);
+       pp = __of_find_property(np, name, lenp);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
        return pp;
 }
@@ -199,23 +193,35 @@ struct device_node *of_find_all_nodes(struct device_node *prev)
 {
        struct device_node *np;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock(&devtree_lock);
        np = prev ? prev->allnext : of_allnodes;
        for (; np != NULL; np = np->allnext)
                if (of_node_get(np))
                        break;
        of_node_put(prev);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock(&devtree_lock);
        return np;
 }
 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)
+{
+       struct property *pp = __of_find_property(np, name, lenp);
+
+       return pp ? pp->value : NULL;
+}
+
 /*
  * Find a property with a given name for a given node
  * and return the value.
  */
 const void *of_get_property(const struct device_node *np, const char *name,
-                        int *lenp)
+                           int *lenp)
 {
        struct property *pp = of_find_property(np, name, lenp);
 
@@ -226,13 +232,13 @@ EXPORT_SYMBOL(of_get_property);
 /** Checks if the given "compat" string matches one of the strings in
  * the device's "compatible" property
  */
-int of_device_is_compatible(const struct device_node *device,
-               const char *compat)
+static int __of_device_is_compatible(const struct device_node *device,
+                                    const char *compat)
 {
        const char* cp;
        int cplen, l;
 
-       cp = of_get_property(device, "compatible", &cplen);
+       cp = __of_get_property(device, "compatible", &cplen);
        if (cp == NULL)
                return 0;
        while (cplen > 0) {
@@ -245,6 +251,21 @@ int of_device_is_compatible(const struct device_node *device,
 
        return 0;
 }
+
+/** Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+int of_device_is_compatible(const struct device_node *device,
+               const char *compat)
+{
+       unsigned long flags;
+       int res;
+
+       raw_spin_lock_irqsave(&devtree_lock, flags);
+       res = __of_device_is_compatible(device, compat);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
+       return res;
+}
 EXPORT_SYMBOL(of_device_is_compatible);
 
 /**
@@ -269,19 +290,19 @@ int of_machine_is_compatible(const char *compat)
 EXPORT_SYMBOL(of_machine_is_compatible);
 
 /**
- *  of_device_is_available - check if a device is available for use
+ *  __of_device_is_available - check if a device is available for use
  *
- *  @device: Node to check for availability
+ *  @device: Node to check for availability, with locks already held
  *
  *  Returns 1 if the status property is absent or set to "okay" or "ok",
  *  0 otherwise
  */
-int of_device_is_available(const struct device_node *device)
+static int __of_device_is_available(const struct device_node *device)
 {
        const char *status;
        int statlen;
 
-       status = of_get_property(device, "status", &statlen);
+       status = __of_get_property(device, "status", &statlen);
        if (status == NULL)
                return 1;
 
@@ -292,6 +313,26 @@ int of_device_is_available(const struct device_node *device)
 
        return 0;
 }
+
+/**
+ *  of_device_is_available - check if a device is available for use
+ *
+ *  @device: Node to check for availability
+ *
+ *  Returns 1 if the status property is absent or set to "okay" or "ok",
+ *  0 otherwise
+ */
+int of_device_is_available(const struct device_node *device)
+{
+       unsigned long flags;
+       int res;
+
+       raw_spin_lock_irqsave(&devtree_lock, flags);
+       res = __of_device_is_available(device);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
+       return res;
+
+}
 EXPORT_SYMBOL(of_device_is_available);
 
 /**
@@ -304,13 +345,14 @@ EXPORT_SYMBOL(of_device_is_available);
 struct device_node *of_get_parent(const struct device_node *node)
 {
        struct device_node *np;
+       unsigned long flags;
 
        if (!node)
                return NULL;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        np = of_node_get(node->parent);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
 }
 EXPORT_SYMBOL(of_get_parent);
@@ -329,14 +371,15 @@ EXPORT_SYMBOL(of_get_parent);
 struct device_node *of_get_next_parent(struct device_node *node)
 {
        struct device_node *parent;
+       unsigned long flags;
 
        if (!node)
                return NULL;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        parent = of_node_get(node->parent);
        of_node_put(node);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return parent;
 }
 
@@ -352,14 +395,15 @@ struct device_node *of_get_next_child(const struct device_node *node,
        struct device_node *prev)
 {
        struct device_node *next;
+       unsigned long flags;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        next = prev ? prev->sibling : node->child;
        for (; next; next = next->sibling)
                if (of_node_get(next))
                        break;
        of_node_put(prev);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return next;
 }
 EXPORT_SYMBOL(of_get_next_child);
@@ -377,16 +421,16 @@ struct device_node *of_get_next_available_child(const struct device_node *node,
 {
        struct device_node *next;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock(&devtree_lock);
        next = prev ? prev->sibling : node->child;
        for (; next; next = next->sibling) {
-               if (!of_device_is_available(next))
+               if (!__of_device_is_available(next))
                        continue;
                if (of_node_get(next))
                        break;
        }
        of_node_put(prev);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock(&devtree_lock);
        return next;
 }
 EXPORT_SYMBOL(of_get_next_available_child);
@@ -424,14 +468,15 @@ EXPORT_SYMBOL(of_get_child_by_name);
 struct device_node *of_find_node_by_path(const char *path)
 {
        struct device_node *np = of_allnodes;
+       unsigned long flags;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        for (; np; np = np->allnext) {
                if (np->full_name && (of_node_cmp(np->full_name, path) == 0)
                    && of_node_get(np))
                        break;
        }
-       read_unlock(&devtree_lock);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
 }
 EXPORT_SYMBOL(of_find_node_by_path);
@@ -451,15 +496,16 @@ struct device_node *of_find_node_by_name(struct device_node *from,
        const char *name)
 {
        struct device_node *np;
+       unsigned long flags;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        np = from ? from->allnext : of_allnodes;
        for (; np; np = np->allnext)
                if (np->name && (of_node_cmp(np->name, name) == 0)
                    && of_node_get(np))
                        break;
        of_node_put(from);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
 }
 EXPORT_SYMBOL(of_find_node_by_name);
@@ -480,15 +526,16 @@ struct device_node *of_find_node_by_type(struct device_node *from,
        const char *type)
 {
        struct device_node *np;
+       unsigned long flags;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        np = from ? from->allnext : of_allnodes;
        for (; np; np = np->allnext)
                if (np->type && (of_node_cmp(np->type, type) == 0)
                    && of_node_get(np))
                        break;
        of_node_put(from);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
 }
 EXPORT_SYMBOL(of_find_node_by_type);
@@ -511,18 +558,20 @@ struct device_node *of_find_compatible_node(struct device_node *from,
        const char *type, const char *compatible)
 {
        struct device_node *np;
+       unsigned long flags;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        np = from ? from->allnext : of_allnodes;
        for (; np; np = np->allnext) {
                if (type
                    && !(np->type && (of_node_cmp(np->type, type) == 0)))
                        continue;
-               if (of_device_is_compatible(np, compatible) && of_node_get(np))
+               if (__of_device_is_compatible(np, compatible) &&
+                   of_node_get(np))
                        break;
        }
        of_node_put(from);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
 }
 EXPORT_SYMBOL(of_find_compatible_node);
@@ -544,8 +593,9 @@ struct device_node *of_find_node_with_property(struct device_node *from,
 {
        struct device_node *np;
        struct property *pp;
+       unsigned long flags;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        np = from ? from->allnext : of_allnodes;
        for (; np; np = np->allnext) {
                for (pp = np->properties; pp; pp = pp->next) {
@@ -557,20 +607,14 @@ struct device_node *of_find_node_with_property(struct device_node *from,
        }
 out:
        of_node_put(from);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
 }
 EXPORT_SYMBOL(of_find_node_with_property);
 
-/**
- * of_match_node - Tell if an device_node has a matching of_match structure
- *     @matches:       array of of device match structures to search in
- *     @node:          the of device structure to match against
- *
- *     Low level utility function used by device matching.
- */
-const struct of_device_id *of_match_node(const struct of_device_id *matches,
-                                        const struct device_node *node)
+static
+const struct of_device_id *__of_match_node(const struct of_device_id *matches,
+                                          const struct device_node *node)
 {
        if (!matches)
                return NULL;
@@ -584,14 +628,33 @@ const struct of_device_id *of_match_node(const struct of_device_id *matches,
                        match &= node->type
                                && !strcmp(matches->type, node->type);
                if (matches->compatible[0])
-                       match &= of_device_is_compatible(node,
-                                               matches->compatible);
+                       match &= __of_device_is_compatible(node,
+                                                          matches->compatible);
                if (match)
                        return matches;
                matches++;
        }
        return NULL;
 }
+
+/**
+ * of_match_node - Tell if an device_node has a matching of_match structure
+ *     @matches:       array of of device match structures to search in
+ *     @node:          the of device structure to match against
+ *
+ *     Low level utility function used by device matching.
+ */
+const struct of_device_id *of_match_node(const struct of_device_id *matches,
+                                        const struct device_node *node)
+{
+       const struct of_device_id *match;
+       unsigned long flags;
+
+       raw_spin_lock_irqsave(&devtree_lock, flags);
+       match = __of_match_node(matches, node);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
+       return match;
+}
 EXPORT_SYMBOL(of_match_node);
 
 /**
@@ -612,21 +675,24 @@ struct device_node *of_find_matching_node_and_match(struct device_node *from,
                                        const struct of_device_id **match)
 {
        struct device_node *np;
+       const struct of_device_id *m;
+       unsigned long flags;
 
        if (match)
                *match = NULL;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        np = from ? from->allnext : of_allnodes;
        for (; np; np = np->allnext) {
-               if (of_match_node(matches, np) && of_node_get(np)) {
+               m = __of_match_node(matches, np);
+               if (m && of_node_get(np)) {
                        if (match)
-                               *match = matches;
+                               *match = m;
                        break;
                }
        }
        of_node_put(from);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
 }
 EXPORT_SYMBOL(of_find_matching_node_and_match);
@@ -669,12 +735,12 @@ struct device_node *of_find_node_by_phandle(phandle handle)
 {
        struct device_node *np;
 
-       read_lock(&devtree_lock);
+       raw_spin_lock(&devtree_lock);
        for (np = of_allnodes; np; np = np->allnext)
                if (np->phandle == handle)
                        break;
        of_node_get(np);
-       read_unlock(&devtree_lock);
+       raw_spin_unlock(&devtree_lock);
        return np;
 }
 EXPORT_SYMBOL(of_find_node_by_phandle);
@@ -1025,12 +1091,13 @@ EXPORT_SYMBOL(of_parse_phandle);
  * To get a device_node of the `node2' node you may call this:
  * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &args);
  */
-int of_parse_phandle_with_args(const struct device_node *np, const char *list_name,
-                               const char *cells_name, int index,
-                               struct of_phandle_args *out_args)
+static int __of_parse_phandle_with_args(const struct device_node *np,
+                                       const char *list_name,
+                                       const char *cells_name, int index,
+                                       struct of_phandle_args *out_args)
 {
        const __be32 *list, *list_end;
-       int size, cur_index = 0;
+       int rc = 0, size, cur_index = 0;
        uint32_t count = 0;
        struct device_node *node = NULL;
        phandle phandle;
@@ -1043,6 +1110,7 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
 
        /* Loop over the phandles until all the requested entry is found */
        while (list < list_end) {
+               rc = -EINVAL;
                count = 0;
 
                /*
@@ -1059,13 +1127,13 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
                        if (!node) {
                                pr_err("%s: could not find phandle\n",
                                         np->full_name);
-                               break;
+                               goto err;
                        }
                        if (of_property_read_u32(node, cells_name, &count)) {
                                pr_err("%s: could not get %s for %s\n",
                                         np->full_name, cells_name,
                                         node->full_name);
-                               break;
+                               goto err;
                        }
 
                        /*
@@ -1075,7 +1143,7 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
                        if (list + count > list_end) {
                                pr_err("%s: arguments longer than property\n",
                                         np->full_name);
-                               break;
+                               goto err;
                        }
                }
 
@@ -1085,9 +1153,10 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
                 * index matches, then fill the out_args structure and return,
                 * or return -ENOENT for an empty entry.
                 */
+               rc = -ENOENT;
                if (cur_index == index) {
                        if (!phandle)
-                               return -ENOENT;
+                               goto err;
 
                        if (out_args) {
                                int i;
@@ -1098,6 +1167,10 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
                                for (i = 0; i < count; i++)
                                        out_args->args[i] = be32_to_cpup(list++);
                        }
+
+                       /* Found it! return success */
+                       if (node)
+                               of_node_put(node);
                        return 0;
                }
 
@@ -1107,13 +1180,51 @@ int of_parse_phandle_with_args(const struct device_node *np, const char *list_na
                cur_index++;
        }
 
-       /* Loop exited without finding a valid entry; return an error */
+       /*
+        * Unlock node before returning result; will be one of:
+        * -ENOENT : index is for empty phandle
+        * -EINVAL : parsing error on data
+        * [1..n]  : Number of phandle (count mode; when index = -1)
+        */
+       rc = index < 0 ? cur_index : -ENOENT;
+ err:
        if (node)
                of_node_put(node);
-       return -EINVAL;
+       return rc;
+}
+
+int of_parse_phandle_with_args(const struct device_node *np, const char *list_name,
+                               const char *cells_name, int index,
+                               struct of_phandle_args *out_args)
+{
+       if (index < 0)
+               return -EINVAL;
+       return __of_parse_phandle_with_args(np, list_name, cells_name, index, out_args);
 }
 EXPORT_SYMBOL(of_parse_phandle_with_args);
 
+/**
+ * of_count_phandle_with_args() - Find the number of phandles references in a property
+ * @np:                pointer to a device tree node containing a list
+ * @list_name: property name that contains a list
+ * @cells_name:        property name that specifies phandles' arguments count
+ *
+ * Returns the number of phandle + argument tuples within a property. It
+ * is a typical pattern to encode a list of phandle and variable
+ * arguments into a single property. The number of arguments is encoded
+ * by a property in the phandle-target node. For example, a gpios
+ * property would contain a list of GPIO specifies consisting of a
+ * phandle and 1 or more arguments. The number of arguments are
+ * determined by the #gpio-cells property in the node pointed to by the
+ * phandle.
+ */
+int of_count_phandle_with_args(const struct device_node *np, const char *list_name,
+                               const char *cells_name)
+{
+       return __of_parse_phandle_with_args(np, list_name, cells_name, -1, NULL);
+}
+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)
@@ -1146,18 +1257,18 @@ int of_add_property(struct device_node *np, struct property *prop)
                return rc;
 
        prop->next = NULL;
-       write_lock_irqsave(&devtree_lock, flags);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        next = &np->properties;
        while (*next) {
                if (strcmp(prop->name, (*next)->name) == 0) {
                        /* duplicate ! don't insert it */
-                       write_unlock_irqrestore(&devtree_lock, flags);
+                       raw_spin_unlock_irqrestore(&devtree_lock, flags);
                        return -1;
                }
                next = &(*next)->next;
        }
        *next = prop;
-       write_unlock_irqrestore(&devtree_lock, flags);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
 #ifdef CONFIG_PROC_DEVICETREE
        /* try to add to proc as well if it was initialized */
@@ -1187,7 +1298,7 @@ int of_remove_property(struct device_node *np, struct property *prop)
        if (rc)
                return rc;
 
-       write_lock_irqsave(&devtree_lock, flags);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        next = &np->properties;
        while (*next) {
                if (*next == prop) {
@@ -1200,7 +1311,7 @@ int of_remove_property(struct device_node *np, struct property *prop)
                }
                next = &(*next)->next;
        }
-       write_unlock_irqrestore(&devtree_lock, flags);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
        if (!found)
                return -ENODEV;
@@ -1240,7 +1351,7 @@ int of_update_property(struct device_node *np, struct property *newprop)
        if (!oldprop)
                return of_add_property(np, newprop);
 
-       write_lock_irqsave(&devtree_lock, flags);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        next = &np->properties;
        while (*next) {
                if (*next == oldprop) {
@@ -1254,7 +1365,7 @@ int of_update_property(struct device_node *np, struct property *newprop)
                }
                next = &(*next)->next;
        }
-       write_unlock_irqrestore(&devtree_lock, flags);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
        if (!found)
                return -ENODEV;
@@ -1327,12 +1438,12 @@ int of_attach_node(struct device_node *np)
        if (rc)
                return rc;
 
-       write_lock_irqsave(&devtree_lock, flags);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
        np->sibling = np->parent->child;
        np->allnext = of_allnodes;
        np->parent->child = np;
        of_allnodes = np;
-       write_unlock_irqrestore(&devtree_lock, flags);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
        of_add_proc_dt_entry(np);
        return 0;
@@ -1375,17 +1486,17 @@ int of_detach_node(struct device_node *np)
        if (rc)
                return rc;
 
-       write_lock_irqsave(&devtree_lock, flags);
+       raw_spin_lock_irqsave(&devtree_lock, flags);
 
        if (of_node_check_flag(np, OF_DETACHED)) {
                /* someone already detached it */
-               write_unlock_irqrestore(&devtree_lock, flags);
+               raw_spin_unlock_irqrestore(&devtree_lock, flags);
                return rc;
        }
 
        parent = np->parent;
        if (!parent) {
-               write_unlock_irqrestore(&devtree_lock, flags);
+               raw_spin_unlock_irqrestore(&devtree_lock, flags);
                return rc;
        }
 
@@ -1412,7 +1523,7 @@ int of_detach_node(struct device_node *np)
        }
 
        of_node_set_flag(np, OF_DETACHED);
-       write_unlock_irqrestore(&devtree_lock, flags);
+       raw_spin_unlock_irqrestore(&devtree_lock, flags);
 
        of_remove_proc_dt_entry(np);
        return rc;