of: find_node_by_full_name rewrite to compare each level
[linux-block.git] / drivers / of / base.c
index d7c4629a3a2decb6a0bcacc9e561daee882abbbc..87b4968f3d8fe72946a88069db5cd9ba29ce5782 100644 (file)
@@ -155,7 +155,7 @@ int __of_add_property_sysfs(struct device_node *np, struct property *pp)
 
        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;
+       pp->attr.attr.mode = secure ? 0400 : 0444;
        pp->attr.size = secure ? 0 : pp->length;
        pp->attr.read = of_node_property_read;
 
@@ -773,16 +773,31 @@ static struct device_node *__of_find_node_by_path(struct device_node *parent,
                return NULL;
 
        __for_each_child_of_node(parent, child) {
-               const char *name = strrchr(child->full_name, '/');
-               if (WARN(!name, "malformed device_node %s\n", child->full_name))
-                       continue;
-               name++;
+               const char *name = kbasename(child->full_name);
                if (strncmp(path, name, len) == 0 && (strlen(name) == len))
                        return child;
        }
        return NULL;
 }
 
+struct device_node *__of_find_node_by_full_path(struct device_node *node,
+                                               const char *path)
+{
+       const char *separator = strchr(path, ':');
+
+       while (node && *path == '/') {
+               struct device_node *tmp = node;
+
+               path++; /* Increment past '/' delimiter */
+               node = __of_find_node_by_path(node, path);
+               of_node_put(tmp);
+               path = strchrnul(path, '/');
+               if (separator && separator < path)
+                       break;
+       }
+       return node;
+}
+
 /**
  *     of_find_node_opts_by_path - Find a node matching a full OF path
  *     @path: Either the full path to match, or if the path does not
@@ -842,16 +857,7 @@ struct device_node *of_find_node_opts_by_path(const char *path, const char **opt
        raw_spin_lock_irqsave(&devtree_lock, flags);
        if (!np)
                np = of_node_get(of_root);
-       while (np && *path == '/') {
-               struct device_node *tmp = np;
-
-               path++; /* Increment past '/' delimiter */
-               np = __of_find_node_by_path(np, path);
-               of_node_put(tmp);
-               path = strchrnul(path, '/');
-               if (separator && separator < path)
-                       break;
-       }
+       np = __of_find_node_by_full_path(np, path);
        raw_spin_unlock_irqrestore(&devtree_lock, flags);
        return np;
 }
@@ -1212,6 +1218,37 @@ int of_property_read_u32_index(const struct device_node *np,
 }
 EXPORT_SYMBOL_GPL(of_property_read_u32_index);
 
+/**
+ * of_property_read_u64_index - Find and read a u64 from a multi-value property.
+ *
+ * @np:                device node from which the property value is to be read.
+ * @propname:  name of the property to be searched.
+ * @index:     index of the u64 in the list of values
+ * @out_value: pointer to return value, modified only if no error.
+ *
+ * Search for a property in a device node and read nth 64-bit value from
+ * it. Returns 0 on success, -EINVAL if the property does not exist,
+ * -ENODATA if property does not have a value, and -EOVERFLOW if the
+ * property data isn't large enough.
+ *
+ * The out_value is modified only if a valid u64 value can be decoded.
+ */
+int of_property_read_u64_index(const struct device_node *np,
+                                      const char *propname,
+                                      u32 index, u64 *out_value)
+{
+       const u64 *val = of_find_property_value_of_size(np, propname,
+                                       ((index + 1) * sizeof(*out_value)),
+                                       0, NULL);
+
+       if (IS_ERR(val))
+               return PTR_ERR(val);
+
+       *out_value = be64_to_cpup(((__be64 *)val) + index);
+       return 0;
+}
+EXPORT_SYMBOL_GPL(of_property_read_u64_index);
+
 /**
  * of_property_read_variable_u8_array - Find and read an array of u8 from a
  * property, with bounds on the minimum and maximum array size.
@@ -2250,15 +2287,14 @@ EXPORT_SYMBOL_GPL(of_console_check);
  */
 struct device_node *of_find_next_cache_node(const struct device_node *np)
 {
-       struct device_node *child;
-       const phandle *handle;
+       struct device_node *child, *cache_node;
 
-       handle = of_get_property(np, "l2-cache", NULL);
-       if (!handle)
-               handle = of_get_property(np, "next-level-cache", NULL);
+       cache_node = of_parse_phandle(np, "l2-cache", 0);
+       if (!cache_node)
+               cache_node = of_parse_phandle(np, "next-level-cache", 0);
 
-       if (handle)
-               return of_find_node_by_phandle(be32_to_cpup(handle));
+       if (cache_node)
+               return cache_node;
 
        /* OF on pmac has nodes instead of properties named "l2-cache"
         * beneath CPU nodes.