--- zzzz-none-000/linux-3.10.107/drivers/of/base.c 2017-06-27 09:49:32.000000000 +0000 +++ scorpion-7490-727/linux-3.10.107/drivers/of/base.c 2021-02-04 17:41:59.000000000 +0000 @@ -17,25 +17,39 @@ * as published by the Free Software Foundation; either version * 2 of the License, or (at your option) any later version. */ +#include #include +#include #include #include +#include #include #include +#include #include #include "of_private.h" LIST_HEAD(aliases_lookup); -struct device_node *of_allnodes; -EXPORT_SYMBOL(of_allnodes); +struct device_node *of_root; +EXPORT_SYMBOL(of_root); struct device_node *of_chosen; struct device_node *of_aliases; +struct device_node *of_stdout; +static const char *of_stdout_options; -DEFINE_MUTEX(of_aliases_mutex); +struct kset *of_kset; -/* use when traversing tree through the allnext, child, sibling, +/* + * 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_mutex); + +/* use when traversing tree through the child, sibling, * or parent members of struct device_node. */ DEFINE_RAW_SPINLOCK(devtree_lock); @@ -72,80 +86,137 @@ } EXPORT_SYMBOL(of_n_size_cells); -#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) +#ifdef CONFIG_NUMA +int __weak of_node_to_nid(struct device_node *np) { - if (node) - kref_get(&node->kref); - return node; + return NUMA_NO_NODE; } -EXPORT_SYMBOL(of_node_get); +#endif -static inline struct device_node *kref_to_device_node(struct kref *kref) +#ifndef CONFIG_OF_DYNAMIC +static void of_node_release(struct kobject *kobj) { - return container_of(kref, struct device_node, kref); + /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ } +#endif /* CONFIG_OF_DYNAMIC */ -/** - * 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 kref *kref) +struct kobj_type of_node_ktype = { + .release = of_node_release, +}; + +static ssize_t of_node_property_read(struct file *filp, struct kobject *kobj, + struct bin_attribute *bin_attr, char *buf, + loff_t offset, size_t count) { - struct device_node *node = kref_to_device_node(kref); - struct property *prop = node->properties; + struct property *pp = container_of(bin_attr, struct property, attr); + return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length); +} - /* 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(); - kref_init(&node->kref); - return; - } +/* always return newly allocated name, caller must free after use */ +static const char *safe_name(struct kobject *kobj, const char *orig_name) +{ + const char *name = orig_name; + struct kernfs_node *kn; + int i = 0; - if (!of_node_check_flag(node, OF_DYNAMIC)) - return; + /* don't be a hero. After 16 tries give up */ + while (i < 16 && (kn = sysfs_get_dirent(kobj->sd, name))) { + sysfs_put(kn); + if (name != orig_name) + kfree(name); + name = kasprintf(GFP_KERNEL, "%s#%i", orig_name, ++i); + } - 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; - } + if (name == orig_name) { + name = kstrdup(orig_name, GFP_KERNEL); + } else { + pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n", + kobject_name(kobj), name); } - kfree(node->full_name); - kfree(node->data); - kfree(node); + return name; } -/** - * 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) +int __of_add_property_sysfs(struct device_node *np, struct property *pp) { - if (node) - kref_put(&node->kref, of_node_release); + int rc; + + /* Important: Don't leak passwords */ + bool secure = strncmp(pp->name, "security-", 9) == 0; + + if (!IS_ENABLED(CONFIG_SYSFS) || IS_ENABLED(CONFIG_AVM_THIN_SYSFS)) + return 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; + pp->attr.size = secure ? 0 : pp->length; + pp->attr.read = of_node_property_read; + + rc = sysfs_create_bin_file(&np->kobj, &pp->attr); + WARN(rc, "error adding attribute %s to node %s\n", pp->name, np->full_name); + return rc; +} + +int __of_attach_node_sysfs(struct device_node *np) +{ + const char *name; + struct kobject *parent; + struct property *pp; + int rc; + + if (!IS_ENABLED(CONFIG_SYSFS) || IS_ENABLED(CONFIG_AVM_THIN_SYSFS)) + return 0; + + if (!of_kset) + return 0; + + np->kobj.kset = of_kset; + if (!np->parent) { + /* Nodes without parents are new top level trees */ + name = safe_name(&of_kset->kobj, "base"); + parent = NULL; + } else { + name = safe_name(&np->parent->kobj, kbasename(np->full_name)); + parent = &np->parent->kobj; + } + if (!name) + return -ENOMEM; + rc = kobject_add(&np->kobj, parent, "%s", name); + kfree(name); + if (rc) + return rc; + + for_each_property_of_node(np, pp) + __of_add_property_sysfs(np, pp); + + return 0; +} + +void __init of_core_init(void) +{ +#if !defined(CONFIG_AVM_THIN_SYSFS) + struct device_node *np; + + /* Create the kset, and register existing nodes */ + mutex_lock(&of_mutex); + of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); + if (!of_kset) { + mutex_unlock(&of_mutex); + pr_err("devicetree: failed to register existing nodes\n"); + return; + } + for_each_of_allnodes(np) + __of_attach_node_sysfs(np); + mutex_unlock(&of_mutex); + + /* Symlink in /proc as required by userspace ABI */ + if (of_root) + proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base"); +#endif } -EXPORT_SYMBOL(of_node_put); -#endif /* CONFIG_OF_DYNAMIC */ static struct property *__of_find_property(const struct device_node *np, const char *name, int *lenp) @@ -181,6 +252,23 @@ } EXPORT_SYMBOL(of_find_property); +struct device_node *__of_find_all_nodes(struct device_node *prev) +{ + struct device_node *np; + if (!prev) { + np = of_root; + } else if (prev->child) { + np = prev->child; + } else { + /* Walk back up looking for a sibling, or the end of the structure */ + np = prev; + while (np->parent && !np->sibling) + np = np->parent; + np = np->sibling; /* Might be null at the end of the tree */ + } + return np; +} + /** * of_find_all_nodes - Get next node in global list * @prev: Previous node or NULL to start iteration @@ -195,10 +283,8 @@ unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); - np = prev ? prev->allnext : of_allnodes; - for (; np != NULL; np = np->allnext) - if (of_node_get(np)) - break; + np = __of_find_all_nodes(prev); + of_node_get(np); of_node_put(prev); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np; @@ -209,8 +295,8 @@ * 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); @@ -230,27 +316,172 @@ } EXPORT_SYMBOL(of_get_property); -/** Checks if the given "compat" string matches one of the strings in - * the device's "compatible" property +/* + * arch_match_cpu_phys_id - Match the given logical CPU and physical id + * + * @cpu: logical cpu index of a core/thread + * @phys_id: physical identifier of a core/thread + * + * CPU logical to physical index mapping is architecture specific. + * However this __weak function provides a default match of physical + * id to logical cpu index. phys_id provided here is usually values read + * from the device tree which must match the hardware internal registers. + * + * Returns true if the physical identifier and the logical cpu index + * correspond to the same core/thread, false otherwise. + */ +bool __weak arch_match_cpu_phys_id(int cpu, u64 phys_id) +{ + return (u32)phys_id == cpu; +} + +/** + * Checks if the given "prop_name" property holds the physical id of the + * core/thread corresponding to the logical cpu 'cpu'. If 'thread' is not + * NULL, local thread number within the core is returned in it. + */ +static bool __of_find_n_match_cpu_property(struct device_node *cpun, + const char *prop_name, int cpu, unsigned int *thread) +{ + const __be32 *cell; + int ac, prop_len, tid; + u64 hwid; + + ac = of_n_addr_cells(cpun); + cell = of_get_property(cpun, prop_name, &prop_len); + if (!cell || !ac) + return false; + prop_len /= sizeof(*cell) * ac; + for (tid = 0; tid < prop_len; tid++) { + hwid = of_read_number(cell, ac); + if (arch_match_cpu_phys_id(cpu, hwid)) { + if (thread) + *thread = tid; + return true; + } + cell += ac; + } + return false; +} + +/* + * arch_find_n_match_cpu_physical_id - See if the given device node is + * for the cpu corresponding to logical cpu 'cpu'. Return true if so, + * else false. If 'thread' is non-NULL, the local thread number within the + * core is returned in it. + */ +bool __weak arch_find_n_match_cpu_physical_id(struct device_node *cpun, + int cpu, unsigned int *thread) +{ + /* Check for non-standard "ibm,ppc-interrupt-server#s" property + * for thread ids on PowerPC. If it doesn't exist fallback to + * standard "reg" property. + */ + if (IS_ENABLED(CONFIG_PPC) && + __of_find_n_match_cpu_property(cpun, + "ibm,ppc-interrupt-server#s", + cpu, thread)) + return true; + + return __of_find_n_match_cpu_property(cpun, "reg", cpu, thread); +} + +/** + * of_get_cpu_node - Get device node associated with the given logical CPU + * + * @cpu: CPU number(logical index) for which device node is required + * @thread: if not NULL, local thread number within the physical core is + * returned + * + * The main purpose of this function is to retrieve the device node for the + * given logical CPU index. It should be used to initialize the of_node in + * cpu device. Once of_node in cpu device is populated, all the further + * references can use that instead. + * + * CPU logical to physical index mapping is architecture specific and is built + * before booting secondary cores. This function uses arch_match_cpu_phys_id + * which can be overridden by architecture specific implementation. + * + * Returns a node pointer for the logical cpu if found, else NULL. + */ +struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) +{ + struct device_node *cpun; + + for_each_node_by_type(cpun, "cpu") { + if (arch_find_n_match_cpu_physical_id(cpun, cpu, thread)) + return cpun; + } + return NULL; +} +EXPORT_SYMBOL(of_get_cpu_node); + +/** + * __of_device_is_compatible() - Check if the node matches given constraints + * @device: pointer to node + * @compat: required compatible string, NULL or "" for any match + * @type: required device_type value, NULL or "" for any match + * @name: required node name, NULL or "" for any match + * + * Checks if the given @compat, @type and @name strings match the + * properties of the given @device. A constraints can be skipped by + * passing NULL or an empty string as the constraint. + * + * Returns 0 for no match, and a positive integer on match. The return + * value is a relative score with larger values indicating better + * matches. The score is weighted for the most specific compatible value + * to get the highest score. Matching type is next, followed by matching + * name. Practically speaking, this results in the following priority + * order for matches: + * + * 1. specific compatible && type && name + * 2. specific compatible && type + * 3. specific compatible && name + * 4. specific compatible + * 5. general compatible && type && name + * 6. general compatible && type + * 7. general compatible && name + * 8. general compatible + * 9. type && name + * 10. type + * 11. name */ static int __of_device_is_compatible(const struct device_node *device, - const char *compat) + const char *compat, const char *type, const char *name) { - const char* cp; - int cplen, l; + struct property *prop; + const char *cp; + int index = 0, score = 0; + + /* Compatible match has highest priority */ + if (compat && compat[0]) { + prop = __of_find_property(device, "compatible", NULL); + for (cp = of_prop_next_string(prop, NULL); cp; + cp = of_prop_next_string(prop, cp), index++) { + if (of_compat_cmp(cp, compat, strlen(compat)) == 0) { + score = INT_MAX/2 - (index << 2); + break; + } + } + if (!score) + return 0; + } - cp = __of_get_property(device, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (of_compat_cmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; + /* Matching type is better than matching name */ + if (type && type[0]) { + if (!device->type || of_node_cmp(type, device->type)) + return 0; + score += 2; } - return 0; + /* Matching name is a bit better than not */ + if (name && name[0]) { + if (!device->name || of_node_cmp(name, device->name)) + return 0; + score++; + } + + return score; } /** Checks if the given "compat" string matches one of the strings in @@ -263,7 +494,7 @@ int res; raw_spin_lock_irqsave(&devtree_lock, flags); - res = __of_device_is_compatible(device, compat); + res = __of_device_is_compatible(device, compat, NULL, NULL); raw_spin_unlock_irqrestore(&devtree_lock, flags); return res; } @@ -273,7 +504,7 @@ * of_machine_is_compatible - Test root of device tree for a given compatible value * @compat: compatible string to look for in root node's compatible property. * - * Returns true if the root node has the given value in its + * Returns a positive integer if the root node has the given value in its * compatible property. */ int of_machine_is_compatible(const char *compat) @@ -295,24 +526,27 @@ * * @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 + * Returns true if the status property is absent or set to "okay" or "ok", + * false otherwise */ -static int __of_device_is_available(const struct device_node *device) +static bool __of_device_is_available(const struct device_node *device) { const char *status; int statlen; + if (!device) + return false; + status = __of_get_property(device, "status", &statlen); if (status == NULL) - return 1; + return true; if (statlen > 0) { if (!strcmp(status, "okay") || !strcmp(status, "ok")) - return 1; + return true; } - return 0; + return false; } /** @@ -320,13 +554,13 @@ * * @device: Node to check for availability * - * Returns 1 if the status property is absent or set to "okay" or "ok", - * 0 otherwise + * Returns true if the status property is absent or set to "okay" or "ok", + * false otherwise */ -int of_device_is_available(const struct device_node *device) +bool of_device_is_available(const struct device_node *device) { unsigned long flags; - int res; + bool res; raw_spin_lock_irqsave(&devtree_lock, flags); res = __of_device_is_available(device); @@ -337,6 +571,29 @@ EXPORT_SYMBOL(of_device_is_available); /** + * of_device_is_big_endian - check if a device has BE registers + * + * @device: Node to check for endianness + * + * Returns true if the device has a "big-endian" property, or if the kernel + * was compiled for BE *and* the device has a "native-endian" property. + * Returns false otherwise. + * + * Callers would nominally use ioread32be/iowrite32be if + * of_device_is_big_endian() == true, or readl/writel otherwise. + */ +bool of_device_is_big_endian(const struct device_node *device) +{ + if (of_property_read_bool(device, "big-endian")) + return true; + if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) && + of_property_read_bool(device, "native-endian")) + return true; + return false; +} +EXPORT_SYMBOL(of_device_is_big_endian); + +/** * of_get_parent - Get a node's parent if any * @node: Node to get parent * @@ -362,9 +619,9 @@ * of_get_next_parent - Iterate to a node's parent * @node: Node to get parent of * - * This is like of_get_parent() except that it drops the - * refcount on the passed node, making it suitable for iterating - * through a node's parents. + * This is like of_get_parent() except that it drops the + * refcount on the passed node, making it suitable for iterating + * through a node's parents. * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. @@ -385,13 +642,33 @@ } EXPORT_SYMBOL(of_get_next_parent); +static struct device_node *__of_get_next_child(const struct device_node *node, + struct device_node *prev) +{ + struct device_node *next; + + if (!node) + return NULL; + + next = prev ? prev->sibling : node->child; + for (; next; next = next->sibling) + if (of_node_get(next)) + break; + of_node_put(prev); + return next; +} +#define __for_each_child_of_node(parent, child) \ + for (child = __of_get_next_child(parent, NULL); child != NULL; \ + child = __of_get_next_child(parent, child)) + /** * of_get_next_child - Iterate a node childs * @node: parent node * @prev: previous child of the parent node, or NULL to get first * - * Returns a node pointer with refcount incremented, use - * of_node_put() on it when done. + * Returns a node pointer with refcount incremented, use of_node_put() on + * it when done. Returns NULL when prev is the last child. Decrements the + * refcount of prev. */ struct device_node *of_get_next_child(const struct device_node *node, struct device_node *prev) @@ -400,11 +677,7 @@ unsigned long flags; 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); + next = __of_get_next_child(node, prev); raw_spin_unlock_irqrestore(&devtree_lock, flags); return next; } @@ -424,6 +697,9 @@ struct device_node *next; unsigned long flags; + if (!node) + return NULL; + raw_spin_lock_irqsave(&devtree_lock, flags); next = prev ? prev->sibling : node->child; for (; next; next = next->sibling) { @@ -461,28 +737,97 @@ } EXPORT_SYMBOL(of_get_child_by_name); +static struct device_node *__of_find_node_by_path(struct device_node *parent, + const char *path) +{ + struct device_node *child; + int len; + + len = strcspn(path, "/:"); + if (!len) + 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++; + if (strncmp(path, name, len) == 0 && (strlen(name) == len)) + return child; + } + return NULL; +} + /** - * of_find_node_by_path - Find a node matching a full OF path - * @path: The full path to match + * 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 + * start with '/', the name of a property of the /aliases + * node (an alias). In the case of an alias, the node + * matching the alias' value will be returned. + * @opts: Address of a pointer into which to store the start of + * an options string appended to the end of the path with + * a ':' separator. + * + * Valid paths: + * /foo/bar Full path + * foo Valid alias + * foo/bar Valid alias + relative path * * Returns a node pointer with refcount incremented, use * of_node_put() on it when done. */ -struct device_node *of_find_node_by_path(const char *path) +struct device_node *of_find_node_opts_by_path(const char *path, const char **opts) { - struct device_node *np = of_allnodes; + struct device_node *np = NULL; + struct property *pp; unsigned long flags; + const char *separator = strchr(path, ':'); + if (opts) + *opts = separator ? separator + 1 : NULL; + + if (strcmp(path, "/") == 0) + return of_node_get(of_root); + + /* The path could begin with an alias */ + if (*path != '/') { + int len; + const char *p = separator; + + if (!p) + p = strchrnul(path, '/'); + len = p - path; + + /* of_aliases must not be NULL */ + if (!of_aliases) + return NULL; + + for_each_property_of_node(of_aliases, pp) { + if (strlen(pp->name) == len && !strncmp(pp->name, path, len)) { + np = of_find_node_by_path(pp->value); + break; + } + } + if (!np) + return NULL; + path = p; + } + + /* Step down the tree matching path components */ 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)) + if (!np) + np = of_node_get(of_root); + while (np && *path == '/') { + path++; /* Increment past '/' delimiter */ + np = __of_find_node_by_path(np, path); + path = strchrnul(path, '/'); + if (separator && separator < path) break; } raw_spin_unlock_irqrestore(&devtree_lock, flags); return np; } -EXPORT_SYMBOL(of_find_node_by_path); +EXPORT_SYMBOL(of_find_node_opts_by_path); /** * of_find_node_by_name - Find a node by its "name" property @@ -502,8 +847,7 @@ unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); - np = from ? from->allnext : of_allnodes; - for (; np; np = np->allnext) + for_each_of_allnodes_from(from, np) if (np->name && (of_node_cmp(np->name, name) == 0) && of_node_get(np)) break; @@ -532,8 +876,7 @@ unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); - np = from ? from->allnext : of_allnodes; - for (; np; np = np->allnext) + for_each_of_allnodes_from(from, np) if (np->type && (of_node_cmp(np->type, type) == 0) && of_node_get(np)) break; @@ -564,15 +907,10 @@ unsigned long flags; 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) && + for_each_of_allnodes_from(from, np) + if (__of_device_is_compatible(np, compatible, type, NULL) && of_node_get(np)) break; - } of_node_put(from); raw_spin_unlock_irqrestore(&devtree_lock, flags); return np; @@ -599,8 +937,7 @@ unsigned long flags; raw_spin_lock_irqsave(&devtree_lock, flags); - np = from ? from->allnext : of_allnodes; - for (; np; np = np->allnext) { + for_each_of_allnodes_from(from, np) { for (pp = np->properties; pp; pp = pp->next) { if (of_prop_cmp(pp->name, prop_name) == 0) { of_node_get(np); @@ -619,29 +956,26 @@ const struct of_device_id *__of_match_node(const struct of_device_id *matches, const struct device_node *node) { + const struct of_device_id *best_match = NULL; + int score, best_score = 0; + if (!matches) return NULL; - while (matches->name[0] || matches->type[0] || matches->compatible[0]) { - int match = 1; - if (matches->name[0]) - match &= node->name - && !strcmp(matches->name, node->name); - if (matches->type[0]) - match &= node->type - && !strcmp(matches->type, node->type); - if (matches->compatible[0]) - match &= __of_device_is_compatible(node, - matches->compatible); - if (match) - return matches; - matches++; + for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) { + score = __of_device_is_compatible(node, matches->compatible, + matches->type, matches->name); + if (score > best_score) { + best_match = matches; + best_score = score; + } } - return NULL; + + return best_match; } /** - * of_match_node - Tell if an device_node has a matching of_match structure + * of_match_node - Tell if a 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 * @@ -685,8 +1019,7 @@ *match = NULL; raw_spin_lock_irqsave(&devtree_lock, flags); - np = from ? from->allnext : of_allnodes; - for (; np; np = np->allnext) { + for_each_of_allnodes_from(from, np) { m = __of_match_node(matches, np); if (m && of_node_get(np)) { if (match) @@ -739,8 +1072,11 @@ struct device_node *np; unsigned long flags; + if (!handle) + return NULL; + raw_spin_lock_irqsave(&devtree_lock, flags); - for (np = of_allnodes; np; np = np->allnext) + for_each_of_allnodes(np) if (np->phandle == handle) break; of_node_get(np); @@ -750,6 +1086,38 @@ EXPORT_SYMBOL(of_find_node_by_phandle); /** + * of_property_count_elems_of_size - Count the number of elements in a property + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @elem_size: size of the individual element + * + * Search for a property in a device node and count the number of elements of + * size elem_size in it. Returns number of elements on sucess, -EINVAL if the + * property does not exist or its length does not match a multiple of elem_size + * and -ENODATA if the property does not have a value. + */ +int of_property_count_elems_of_size(const struct device_node *np, + const char *propname, int elem_size) +{ + struct property *prop = of_find_property(np, propname, NULL); + + if (!prop) + return -EINVAL; + if (!prop->value) + return -ENODATA; + + if (prop->length % elem_size != 0) { + pr_err("size of %s in node %s is not a multiple of %d\n", + propname, np->full_name, elem_size); + return -EINVAL; + } + + return prop->length / elem_size; +} +EXPORT_SYMBOL_GPL(of_property_count_elems_of_size); + +/** * of_find_property_value_of_size * * @np: device node from which the property value is to be read. @@ -812,7 +1180,7 @@ * * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. - * @out_value: pointer to return value, modified only if return value is 0. + * @out_values: pointer to return value, modified only if return value is 0. * @sz: number of array elements to read * * Search for a property in a device node and read 8-bit value(s) from @@ -823,7 +1191,7 @@ * dts entry of array should be like: * property = /bits/ 8 <0x50 0x60 0x70>; * - * The out_value is modified only if a valid u8 value can be decoded. + * The out_values is modified only if a valid u8 value can be decoded. */ int of_property_read_u8_array(const struct device_node *np, const char *propname, u8 *out_values, size_t sz) @@ -845,7 +1213,7 @@ * * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. - * @out_value: pointer to return value, modified only if return value is 0. + * @out_values: pointer to return value, modified only if return value is 0. * @sz: number of array elements to read * * Search for a property in a device node and read 16-bit value(s) from @@ -856,7 +1224,7 @@ * dts entry of array should be like: * property = /bits/ 16 <0x5000 0x6000 0x7000>; * - * The out_value is modified only if a valid u16 value can be decoded. + * The out_values is modified only if a valid u16 value can be decoded. */ int of_property_read_u16_array(const struct device_node *np, const char *propname, u16 *out_values, size_t sz) @@ -879,7 +1247,7 @@ * * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. - * @out_value: pointer to return value, modified only if return value is 0. + * @out_values: pointer to return value, modified only if return value is 0. * @sz: number of array elements to read * * Search for a property in a device node and read 32-bit value(s) from @@ -887,7 +1255,7 @@ * -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 u32 value can be decoded. + * The out_values is modified only if a valid u32 value can be decoded. */ int of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, @@ -933,6 +1301,40 @@ EXPORT_SYMBOL_GPL(of_property_read_u64); /** + * of_property_read_u64_array - Find and read an array of 64 bit integers + * from a property. + * + * @np: device node from which the property value is to be read. + * @propname: name of the property to be searched. + * @out_values: pointer to return value, modified only if return value is 0. + * @sz: number of array elements to read + * + * Search for a property in a device node and read 64-bit value(s) 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_values is modified only if a valid u64 value can be decoded. + */ +int of_property_read_u64_array(const struct device_node *np, + const char *propname, u64 *out_values, + size_t sz) +{ + const __be32 *val = of_find_property_value_of_size(np, propname, + (sz * sizeof(*out_values))); + + if (IS_ERR(val)) + return PTR_ERR(val); + + while (sz--) { + *out_values++ = of_read_number(val, 2); + val += 2; + } + return 0; +} +EXPORT_SYMBOL_GPL(of_property_read_u64_array); + +/** * of_property_read_string - Find and read a string from a property * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. @@ -1000,7 +1402,7 @@ EXPORT_SYMBOL_GPL(of_property_match_string); /** - * of_property_read_string_util() - Utility helper for parsing string properties + * of_property_read_string_helper() - Utility helper for parsing string properties * @np: device node from which the property value is to be read. * @propname: name of the property to be searched. * @out_strs: output array of string pointers. @@ -1036,148 +1438,164 @@ } EXPORT_SYMBOL_GPL(of_property_read_string_helper); -/** - * of_parse_phandle - Resolve a phandle property to a device_node pointer - * @np: Pointer to device node holding phandle property - * @phandle_name: Name of property holding a phandle value - * @index: For properties holding a table of phandles, this is the index into - * the table - * - * Returns the device_node pointer with refcount incremented. Use - * of_node_put() on it when done. - */ -struct device_node *of_parse_phandle(const struct device_node *np, - const char *phandle_name, int index) +void of_print_phandle_args(const char *msg, const struct of_phandle_args *args) { - const __be32 *phandle; + int i; + printk("%s %s", msg, of_node_full_name(args->np)); + for (i = 0; i < args->args_count; i++) + printk(i ? ",%08x" : ":%08x", args->args[i]); + printk("\n"); +} + +int of_phandle_iterator_init(struct of_phandle_iterator *it, + const struct device_node *np, + const char *list_name, + const char *cells_name, + int cell_count) +{ + const __be32 *list; int size; - phandle = of_get_property(np, phandle_name, &size); - if ((!phandle) || (size < sizeof(*phandle) * (index + 1))) - return NULL; + memset(it, 0, sizeof(*it)); - return of_find_node_by_phandle(be32_to_cpup(phandle + index)); + list = of_get_property(np, list_name, &size); + if (!list) + return -ENOENT; + + it->cells_name = cells_name; + it->cell_count = cell_count; + it->parent = np; + it->list_end = list + size / sizeof(*list); + it->phandle_end = list; + it->cur = list; + + return 0; } -EXPORT_SYMBOL(of_parse_phandle); -/** - * of_parse_phandle_with_args() - Find a node pointed by phandle in a list - * @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 - * @index: index of a phandle to parse out - * @out_args: optional pointer to output arguments structure (will be filled) - * - * This function is useful to parse lists of phandles and their arguments. - * Returns 0 on success and fills out_args, on error returns appropriate - * errno value. - * - * Caller is responsible to call of_node_put() on the returned out_args->node - * pointer. - * - * Example: - * - * phandle1: node1 { - * #list-cells = <2>; - * } - * - * phandle2: node2 { - * #list-cells = <1>; - * } - * - * node3 { - * list = <&phandle1 1 2 &phandle2 3>; - * } - * - * To get a device_node of the `node2' node you may call this: - * of_parse_phandle_with_args(node3, "list", "#list-cells", 1, &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) +int of_phandle_iterator_next(struct of_phandle_iterator *it) { - const __be32 *list, *list_end; - int rc = 0, size, cur_index = 0; uint32_t count = 0; - struct device_node *node = NULL; - phandle phandle; - /* Retrieve the phandle list property */ - list = of_get_property(np, list_name, &size); - if (!list) + if (it->node) { + of_node_put(it->node); + it->node = NULL; + } + + if (!it->cur || it->phandle_end >= it->list_end) return -ENOENT; - list_end = list + size / sizeof(*list); - /* Loop over the phandles until all the requested entry is found */ - while (list < list_end) { - rc = -EINVAL; - count = 0; + it->cur = it->phandle_end; + + /* If phandle is 0, then it is an empty entry with no arguments. */ + it->phandle = be32_to_cpup(it->cur++); + + if (it->phandle) { /* - * If phandle is 0, then it is an empty entry with no - * arguments. Skip forward to the next entry. + * Find the provider node and parse the #*-cells property to + * determine the argument length. */ - phandle = be32_to_cpup(list++); - if (phandle) { - /* - * Find the provider node and parse the #*-cells - * property to determine the argument length - */ - node = of_find_node_by_phandle(phandle); - if (!node) { + it->node = of_find_node_by_phandle(it->phandle); + + if (it->cells_name) { + if (!it->node) { pr_err("%s: could not find phandle\n", - np->full_name); + it->parent->full_name); goto err; } - if (of_property_read_u32(node, cells_name, &count)) { + + if (of_property_read_u32(it->node, it->cells_name, + &count)) { pr_err("%s: could not get %s for %s\n", - np->full_name, cells_name, - node->full_name); + it->parent->full_name, + it->cells_name, + it->node->full_name); goto err; } + } else { + count = it->cell_count; + } - /* - * Make sure that the arguments actually fit in the - * remaining property data length - */ - if (list + count > list_end) { - pr_err("%s: arguments longer than property\n", - np->full_name); - goto err; - } + /* + * Make sure that the arguments actually fit in the remaining + * property data length + */ + if (it->cur + count > it->list_end) { + pr_err("%s: arguments longer than property\n", + it->parent->full_name); + goto err; } + } + + it->phandle_end = it->cur + count; + it->cur_count = count; + return 0; + +err: + if (it->node) { + of_node_put(it->node); + it->node = NULL; + } + + return -EINVAL; +} + +int of_phandle_iterator_args(struct of_phandle_iterator *it, + uint32_t *args, + int size) +{ + int i, count; + + count = it->cur_count; + + if (WARN_ON(size < count)) + count = size; + + for (i = 0; i < count; i++) + args[i] = be32_to_cpup(it->cur++); + + return count; +} + +static int __of_parse_phandle_with_args(const struct device_node *np, + const char *list_name, + const char *cells_name, + int cell_count, int index, + struct of_phandle_args *out_args) +{ + struct of_phandle_iterator it; + int rc, cur_index = 0; + + /* Loop over the phandles until all the requested entry is found */ + of_for_each_phandle(&it, rc, np, list_name, cells_name, cell_count) { /* - * All of the error cases above bail out of the loop, so at + * All of the error cases bail out of the loop, so at * this point, the parsing is successful. If the requested * 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) + if (!it.phandle) goto err; if (out_args) { - int i; - if (WARN_ON(count > MAX_PHANDLE_ARGS)) - count = MAX_PHANDLE_ARGS; - out_args->np = node; - out_args->args_count = count; - for (i = 0; i < count; i++) - out_args->args[i] = be32_to_cpup(list++); + int c; + + c = of_phandle_iterator_args(&it, + out_args->args, + MAX_PHANDLE_ARGS); + out_args->np = it.node; + out_args->args_count = c; } else { - of_node_put(node); + of_node_put(it.node); } /* Found it! return success */ return 0; } - of_node_put(node); - node = NULL; - list += count; cur_index++; } @@ -1185,26 +1603,125 @@ * 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); + if (it.node) + of_node_put(it.node); return rc; } +/** + * of_parse_phandle - Resolve a phandle property to a device_node pointer + * @np: Pointer to device node holding phandle property + * @phandle_name: Name of property holding a phandle value + * @index: For properties holding a table of phandles, this is the index into + * the table + * + * Returns the device_node pointer with refcount incremented. Use + * of_node_put() on it when done. + */ +struct device_node *of_parse_phandle(const struct device_node *np, + const char *phandle_name, int index) +{ + struct of_phandle_args args; + + if (index < 0) + return NULL; + + if (__of_parse_phandle_with_args(np, phandle_name, NULL, 0, + index, &args)) + return NULL; + + return args.np; +} +EXPORT_SYMBOL(of_parse_phandle); + +/** + * of_parse_phandle_with_args() - Find a node pointed by phandle in a list + * @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 + * @index: index of a phandle to parse out + * @out_args: optional pointer to output arguments structure (will be filled) + * + * This function is useful to parse lists of phandles and their arguments. + * Returns 0 on success and fills out_args, on error returns appropriate + * errno value. + * + * Caller is responsible to call of_node_put() on the returned out_args->np + * pointer. + * + * Example: + * + * phandle1: node1 { + * #list-cells = <2>; + * } + * + * phandle2: node2 { + * #list-cells = <1>; + * } + * + * node3 { + * list = <&phandle1 1 2 &phandle2 3>; + * } + * + * 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) { if (index < 0) return -EINVAL; - return __of_parse_phandle_with_args(np, list_name, cells_name, index, out_args); + return __of_parse_phandle_with_args(np, list_name, cells_name, 0, + index, out_args); } EXPORT_SYMBOL(of_parse_phandle_with_args); /** + * of_parse_phandle_with_fixed_args() - Find a node pointed by phandle in a list + * @np: pointer to a device tree node containing a list + * @list_name: property name that contains a list + * @cell_count: number of argument cells following the phandle + * @index: index of a phandle to parse out + * @out_args: optional pointer to output arguments structure (will be filled) + * + * This function is useful to parse lists of phandles and their arguments. + * Returns 0 on success and fills out_args, on error returns appropriate + * errno value. + * + * Caller is responsible to call of_node_put() on the returned out_args->np + * pointer. + * + * Example: + * + * phandle1: node1 { + * } + * + * phandle2: node2 { + * } + * + * node3 { + * list = <&phandle1 0 2 &phandle2 2 3>; + * } + * + * To get a device_node of the `node2' node you may call this: + * of_parse_phandle_with_fixed_args(node3, "list", 2, 1, &args); + */ +int of_parse_phandle_with_fixed_args(const struct device_node *np, + const char *list_name, int cell_count, + int index, struct of_phandle_args *out_args) +{ + if (index < 0) + return -EINVAL; + return __of_parse_phandle_with_args(np, list_name, NULL, cell_count, + index, out_args); +} +EXPORT_SYMBOL(of_parse_phandle_with_fixed_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 @@ -1222,305 +1739,209 @@ 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); + struct of_phandle_iterator it; + int rc, cur_index = 0; -#if defined(CONFIG_OF_DYNAMIC) -static int of_property_notify(int action, struct device_node *np, - struct property *prop) -{ - struct of_prop_reconfig pr; - - 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; + rc = of_phandle_iterator_init(&it, np, list_name, cells_name, 0); + if (rc) + return rc; + + while ((rc = of_phandle_iterator_next(&it)) == 0) + cur_index += 1; + + if (rc != -ENOENT) + return rc; + + return cur_index; } -#endif +EXPORT_SYMBOL(of_count_phandle_with_args); /** - * of_add_property - Add a property to a node + * __of_add_property - Add a property to a node without lock operations */ -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; - unsigned long flags; - int rc; - - rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop); - if (rc) - return rc; prop->next = NULL; - raw_spin_lock_irqsave(&devtree_lock, flags); next = &np->properties; while (*next) { - if (strcmp(prop->name, (*next)->name) == 0) { + if (strcmp(prop->name, (*next)->name) == 0) /* duplicate ! don't insert it */ - raw_spin_unlock_irqrestore(&devtree_lock, flags); - return -1; - } + return -EEXIST; + next = &(*next)->next; } *next = prop; - raw_spin_unlock_irqrestore(&devtree_lock, flags); - -#ifdef CONFIG_PROC_DEVICETREE - /* try to add to proc as well if it was initialized */ - if (np->pde) - proc_device_tree_add_prop(np->pde, prop); -#endif /* CONFIG_PROC_DEVICETREE */ return 0; } /** - * of_remove_property - Remove a property from a node. - * - * Note that we don't actually remove it, since we have given out - * who-knows-how-many pointers to the data using get-property. - * Instead we just move the property to the "dead properties" - * list, so it won't be found any more. + * of_add_property - Add a property to a node */ -int of_remove_property(struct device_node *np, struct property *prop) +int of_add_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_add_property(np, prop); raw_spin_unlock_irqrestore(&devtree_lock, flags); - if (!found) - return -ENODEV; + if (!rc) + __of_add_property_sysfs(np, prop); -#ifdef CONFIG_PROC_DEVICETREE - /* try to remove the proc node as well */ - if (np->pde) - proc_device_tree_remove_prop(np->pde, prop); -#endif /* CONFIG_PROC_DEVICETREE */ + mutex_unlock(&of_mutex); - return 0; + if (!rc) + of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop, NULL); + + return rc; } -/* - * of_update_property - Update a property in a node, if the property does - * not exist, add it. - * - * Note that we don't actually remove it, since we have given out - * who-knows-how-many pointers to the data using get-property. - * Instead we just move the property to the "dead properties" list, - * and add the new property to the property list - */ -int of_update_property(struct device_node *np, struct property *newprop) +int __of_remove_property(struct device_node *np, struct property *prop) { - struct property **next, *oldprop; - unsigned long flags; - int rc, found = 0; - - rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); - if (rc) - return rc; - - if (!newprop->name) - return -EINVAL; - - oldprop = of_find_property(np, newprop->name, NULL); - if (!oldprop) - return of_add_property(np, newprop); + struct property **next; - raw_spin_lock_irqsave(&devtree_lock, flags); - next = &np->properties; - while (*next) { - if (*next == oldprop) { - /* found the node */ - newprop->next = oldprop->next; - *next = newprop; - oldprop->next = np->deadprops; - np->deadprops = oldprop; - found = 1; + for (next = &np->properties; *next; next = &(*next)->next) { + if (*next == prop) break; - } - next = &(*next)->next; } - raw_spin_unlock_irqrestore(&devtree_lock, flags); - - if (!found) + if (*next == NULL) return -ENODEV; -#ifdef CONFIG_PROC_DEVICETREE - /* try to add to proc as well if it was initialized */ - if (np->pde) - proc_device_tree_update_prop(np->pde, newprop, oldprop); -#endif /* CONFIG_PROC_DEVICETREE */ + /* found the node */ + *next = prop->next; + prop->next = np->deadprops; + np->deadprops = prop; 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) +void __of_sysfs_remove_bin_file(struct device_node *np, struct property *prop) { - int rc; - - rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); - return notifier_to_errno(rc); + sysfs_remove_bin_file(&np->kobj, &prop->attr); + kfree(prop->attr.attr.name); } -#ifdef CONFIG_PROC_DEVICETREE -static void of_add_proc_dt_entry(struct device_node *dn) +void __of_remove_property_sysfs(struct device_node *np, struct property *prop) { - struct proc_dir_entry *ent; + if (!IS_ENABLED(CONFIG_SYSFS) || IS_ENABLED(CONFIG_AVM_THIN_SYSFS)) + return; - ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde); - if (ent) - proc_device_tree_add_node(dn, ent); + /* at early boot, bail here and defer setup to of_init() */ + if (of_kset && of_node_is_attached(np)) + __of_sysfs_remove_bin_file(np, prop); } -#else -static void of_add_proc_dt_entry(struct device_node *dn) -{ - return; -} -#endif /** - * of_attach_node - Plug a device node into the tree and global list. + * of_remove_property - Remove a property from a node. + * + * Note that we don't actually remove it, since we have given out + * who-knows-how-many pointers to the data using get-property. + * Instead we just move the property to the "dead properties" + * list, so it won't be found any more. */ -int of_attach_node(struct device_node *np) +int of_remove_property(struct device_node *np, struct property *prop) { 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 = of_allnodes; - np->parent->child = np; - of_allnodes = np; + rc = __of_remove_property(np, prop); raw_spin_unlock_irqrestore(&devtree_lock, flags); - of_add_proc_dt_entry(np); - return 0; + if (!rc) + __of_remove_property_sysfs(np, prop); + + mutex_unlock(&of_mutex); + + if (!rc) + of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop, NULL); + + return rc; } -#ifdef CONFIG_PROC_DEVICETREE -static void of_remove_proc_dt_entry(struct device_node *dn) +int __of_update_property(struct device_node *np, struct property *newprop, + struct property **oldpropp) { - proc_remove(dn->pde); + 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; } -#else -static void of_remove_proc_dt_entry(struct device_node *dn) + +void __of_update_property_sysfs(struct device_node *np, struct property *newprop, + struct property *oldprop) { - return; + if (!IS_ENABLED(CONFIG_SYSFS) || IS_ENABLED(CONFIG_AVM_THIN_SYSFS)) + return; + + /* At early boot, bail out and defer setup to of_init() */ + if (!of_kset) + return; + + if (oldprop) + __of_sysfs_remove_bin_file(np, oldprop); + __of_add_property_sysfs(np, newprop); } -#endif -/** - * of_detach_node - "Unplug" a node from the device tree. +/* + * of_update_property - Update a property in a node, if the property does + * not exist, add it. * - * The caller must hold a reference to the node. The memory associated with - * the node is not freed until its refcount goes to zero. + * Note that we don't actually remove it, since we have given out + * who-knows-how-many pointers to the data using get-property. + * Instead we just move the property to the "dead properties" list, + * and add the new property to the property list */ -int of_detach_node(struct device_node *np) +int of_update_property(struct device_node *np, struct property *newprop) { - struct device_node *parent; + struct property *oldprop; unsigned long flags; - int rc = 0; + int rc; - rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); - if (rc) - return rc; + if (!newprop->name) + return -EINVAL; - raw_spin_lock_irqsave(&devtree_lock, flags); + mutex_lock(&of_mutex); - if (of_node_check_flag(np, OF_DETACHED)) { - /* someone already detached it */ - raw_spin_unlock_irqrestore(&devtree_lock, flags); - return rc; - } + raw_spin_lock_irqsave(&devtree_lock, flags); + rc = __of_update_property(np, newprop, &oldprop); + raw_spin_unlock_irqrestore(&devtree_lock, flags); - parent = np->parent; - if (!parent) { - raw_spin_unlock_irqrestore(&devtree_lock, flags); - return rc; - } + if (!rc) + __of_update_property_sysfs(np, newprop, oldprop); - 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; - } + mutex_unlock(&of_mutex); - of_node_set_flag(np, OF_DETACHED); - raw_spin_unlock_irqrestore(&devtree_lock, flags); + if (!rc) + of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop, oldprop); - of_remove_proc_dt_entry(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) @@ -1535,23 +1956,35 @@ } /** - * of_alias_scan - Scan all properties of 'aliases' node + * of_alias_scan - Scan all properties of the 'aliases' node * - * The function scans all the properties of 'aliases' node and populate - * the the global lookup table with the properties. It returns the - * number of alias_prop found, or error code in error case. + * The function scans all the properties of the 'aliases' node and populates + * the global lookup table with the properties. It returns the + * number of alias properties found, or an error code in case of failure. * * @dt_alloc: An allocator that provides a virtual address to memory - * for the resulting tree + * for storing the resulting tree */ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) { struct property *pp; + of_aliases = of_find_node_by_path("/aliases"); of_chosen = of_find_node_by_path("/chosen"); if (of_chosen == NULL) of_chosen = of_find_node_by_path("/chosen@0"); - of_aliases = of_find_node_by_path("/aliases"); + + if (of_chosen) { + /* linux,stdout-path and /aliases/stdout are for legacy compatibility */ + const char *name = of_get_property(of_chosen, "stdout-path", NULL); + if (!name) + name = of_get_property(of_chosen, "linux,stdout-path", NULL); + if (IS_ENABLED(CONFIG_PPC) && !name) + name = of_get_property(of_aliases, "stdout", NULL); + if (name) + of_stdout = of_find_node_opts_by_path(name, &of_stdout_options); + } + if (!of_aliases) return; @@ -1596,15 +2029,15 @@ * @np: Pointer to the given device_node * @stem: Alias stem of the given device_node * - * The function travels the lookup table to get alias id for the given - * device_node and alias stem. It returns the alias id if find it. + * The function travels the lookup table to get the alias id for the given + * device_node and alias stem. It returns the alias id if found. */ 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; @@ -1614,12 +2047,38 @@ break; } } - mutex_unlock(&of_aliases_mutex); + mutex_unlock(&of_mutex); return id; } EXPORT_SYMBOL_GPL(of_alias_get_id); +/** + * of_alias_get_highest_id - Get highest alias id for the given stem + * @stem: Alias stem to be examined + * + * The function travels the lookup table to get the highest alias id for the + * given alias stem. It returns the alias id if found. + */ +int of_alias_get_highest_id(const char *stem) +{ + struct alias_prop *app; + int id = -ENODEV; + + mutex_lock(&of_mutex); + list_for_each_entry(app, &aliases_lookup, link) { + if (strcmp(app->stem, stem) != 0) + continue; + + if (app->id > id) + id = app->id; + } + mutex_unlock(&of_mutex); + + return id; +} +EXPORT_SYMBOL_GPL(of_alias_get_highest_id); + const __be32 *of_prop_next_u32(struct property *prop, const __be32 *cur, u32 *pu) { @@ -1660,3 +2119,256 @@ return curv; } EXPORT_SYMBOL_GPL(of_prop_next_string); + +/** + * of_console_check() - Test and setup console for DT setup + * @dn - Pointer to device node + * @name - Name to use for preferred console without index. ex. "ttyS" + * @index - Index to use for preferred console. + * + * Check if the given device node matches the stdout-path property in the + * /chosen node. If it does then register it as the preferred console and return + * TRUE. Otherwise return FALSE. + */ +bool of_console_check(struct device_node *dn, char *name, int index) +{ + if (!dn || dn != of_stdout || console_set_on_cmdline) + return false; + return !add_preferred_console(name, index, + kstrdup(of_stdout_options, GFP_KERNEL)); +} +EXPORT_SYMBOL_GPL(of_console_check); + +/** + * of_find_next_cache_node - Find a node's subsidiary cache + * @np: node of type "cpu" or "cache" + * + * Returns a node pointer with refcount incremented, use + * of_node_put() on it when done. Caller should hold a reference + * to np. + */ +struct device_node *of_find_next_cache_node(const struct device_node *np) +{ + struct device_node *child; + const phandle *handle; + + handle = of_get_property(np, "l2-cache", NULL); + if (!handle) + handle = of_get_property(np, "next-level-cache", NULL); + + if (handle) + return of_find_node_by_phandle(be32_to_cpup(handle)); + + /* OF on pmac has nodes instead of properties named "l2-cache" + * beneath CPU nodes. + */ + if (!strcmp(np->type, "cpu")) + for_each_child_of_node(np, child) + if (!strcmp(child->type, "cache")) + return child; + + return NULL; +} + +/** + * of_graph_parse_endpoint() - parse common endpoint node properties + * @node: pointer to endpoint device_node + * @endpoint: pointer to the OF endpoint data structure + * + * The caller should hold a reference to @node. + */ +int of_graph_parse_endpoint(const struct device_node *node, + struct of_endpoint *endpoint) +{ + struct device_node *port_node = of_get_parent(node); + + WARN_ONCE(!port_node, "%s(): endpoint %s has no parent node\n", + __func__, node->full_name); + + memset(endpoint, 0, sizeof(*endpoint)); + + endpoint->local_node = node; + /* + * It doesn't matter whether the two calls below succeed. + * If they don't then the default value 0 is used. + */ + of_property_read_u32(port_node, "reg", &endpoint->port); + of_property_read_u32(node, "reg", &endpoint->id); + + of_node_put(port_node); + + return 0; +} +EXPORT_SYMBOL(of_graph_parse_endpoint); + +/** + * of_graph_get_port_by_id() - get the port matching a given id + * @parent: pointer to the parent device node + * @id: id of the port + * + * Return: A 'port' node pointer with refcount incremented. The caller + * has to use of_node_put() on it when done. + */ +struct device_node *of_graph_get_port_by_id(struct device_node *parent, u32 id) +{ + struct device_node *node, *port; + + node = of_get_child_by_name(parent, "ports"); + if (node) + parent = node; + + for_each_child_of_node(parent, port) { + u32 port_id = 0; + + if (of_node_cmp(port->name, "port") != 0) + continue; + of_property_read_u32(port, "reg", &port_id); + if (id == port_id) + break; + } + + of_node_put(node); + + return port; +} +EXPORT_SYMBOL(of_graph_get_port_by_id); + +/** + * of_graph_get_next_endpoint() - get next endpoint node + * @parent: pointer to the parent device node + * @prev: previous endpoint node, or NULL to get first + * + * Return: An 'endpoint' node pointer with refcount incremented. Refcount + * of the passed @prev node is decremented. + */ +struct device_node *of_graph_get_next_endpoint(const struct device_node *parent, + struct device_node *prev) +{ + struct device_node *endpoint; + struct device_node *port; + + if (!parent) + return NULL; + + /* + * Start by locating the port node. If no previous endpoint is specified + * search for the first port node, otherwise get the previous endpoint + * parent port node. + */ + if (!prev) { + struct device_node *node; + + node = of_get_child_by_name(parent, "ports"); + if (node) + parent = node; + + port = of_get_child_by_name(parent, "port"); + of_node_put(node); + + if (!port) { + pr_err("%s(): no port node found in %s\n", + __func__, parent->full_name); + return NULL; + } + } else { + port = of_get_parent(prev); + if (WARN_ONCE(!port, "%s(): endpoint %s has no parent node\n", + __func__, prev->full_name)) + return NULL; + } + + while (1) { + /* + * Now that we have a port node, get the next endpoint by + * getting the next child. If the previous endpoint is NULL this + * will return the first child. + */ + endpoint = of_get_next_child(port, prev); + if (endpoint) { + of_node_put(port); + return endpoint; + } + + /* No more endpoints under this port, try the next one. */ + prev = NULL; + + do { + port = of_get_next_child(parent, port); + if (!port) + return NULL; + } while (of_node_cmp(port->name, "port")); + } +} +EXPORT_SYMBOL(of_graph_get_next_endpoint); + +/** + * of_graph_get_endpoint_by_regs() - get endpoint node of specific identifiers + * @parent: pointer to the parent device node + * @port_reg: identifier (value of reg property) of the parent port node + * @reg: identifier (value of reg property) of the endpoint node + * + * Return: An 'endpoint' node pointer which is identified by reg and at the same + * is the child of a port node identified by port_reg. reg and port_reg are + * ignored when they are -1. + */ +struct device_node *of_graph_get_endpoint_by_regs( + const struct device_node *parent, int port_reg, int reg) +{ + struct of_endpoint endpoint; + struct device_node *node = NULL; + + for_each_endpoint_of_node(parent, node) { + of_graph_parse_endpoint(node, &endpoint); + if (((port_reg == -1) || (endpoint.port == port_reg)) && + ((reg == -1) || (endpoint.id == reg))) + return node; + } + + return NULL; +} +EXPORT_SYMBOL(of_graph_get_endpoint_by_regs); + +/** + * of_graph_get_remote_port_parent() - get remote port's parent node + * @node: pointer to a local endpoint device_node + * + * Return: Remote device node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *of_graph_get_remote_port_parent( + const struct device_node *node) +{ + struct device_node *np; + unsigned int depth; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + + /* Walk 3 levels up only if there is 'ports' node. */ + for (depth = 3; depth && np; depth--) { + np = of_get_next_parent(np); + if (depth == 2 && of_node_cmp(np->name, "ports")) + break; + } + return np; +} +EXPORT_SYMBOL(of_graph_get_remote_port_parent); + +/** + * of_graph_get_remote_port() - get remote port node + * @node: pointer to a local endpoint device_node + * + * Return: Remote port node associated with remote endpoint node linked + * to @node. Use of_node_put() on it when done. + */ +struct device_node *of_graph_get_remote_port(const struct device_node *node) +{ + struct device_node *np; + + /* Get remote endpoint node. */ + np = of_parse_phandle(node, "remote-endpoint", 0); + if (!np) + return NULL; + return of_get_next_parent(np); +} +EXPORT_SYMBOL(of_graph_get_remote_port);