// SPDX-License-Identifier: GPL-2.0+ /* * Procedures for creating, accessing and interpreting the device tree. * * Paul Mackerras August 1996. * Copyright (C) 1996-2005 Paul Mackerras. * * Adapted for 64bit PowerPC by Dave Engebretsen and Peter Bergner. * {engebret|bergner}@us.ibm.com * * Adapted for sparc and sparc64 by David S. Miller davem@davemloft.net * * Reconsolidated from arch/x/kernel/prom.c by Stephen Rothwell and * Grant Likely.
*/
/* * 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);
int of_bus_n_addr_cells(struct device_node *np)
{
u32 cells;
for (; np; np = np->parent) { if (!of_property_read_u32(np, "#address-cells", &cells)) return cells; /* * Default root value and walking parent nodes for "#address-cells" * is deprecated. Any platforms which hit this warning should * be added to the excluded list.
*/
WARN_ONCE(!EXCLUDED_DEFAULT_CELLS_PLATFORMS, "Missing '#address-cells' in %pOF\n", np);
} return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;
}
int of_n_addr_cells(struct device_node *np)
{ if (np->parent)
np = np->parent;
int of_bus_n_size_cells(struct device_node *np)
{
u32 cells;
for (; np; np = np->parent) { if (!of_property_read_u32(np, "#size-cells", &cells)) return cells; /* * Default root value and walking parent nodes for "#size-cells" * is deprecated. Any platforms which hit this warning should * be added to the excluded list.
*/
WARN_ONCE(!EXCLUDED_DEFAULT_CELLS_PLATFORMS, "Missing '#size-cells' in %pOF\n", np);
} return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;
}
int of_n_size_cells(struct device_node *np)
{ if (np->parent)
np = np->parent;
struct device_node *__of_find_all_nodes(struct device_node *prev)
{ struct device_node *np; if (!prev) {
np = of_root;
} elseif (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 * of_node_put() will be called on it * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_find_all_nodes(struct device_node *prev)
{ struct device_node *np; unsignedlong flags;
/* * Find a property with a given name for a given node * and return the value.
*/ constvoid *__of_get_property(conststruct device_node *np, constchar *name, int *lenp)
{ conststruct 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.
*/ constvoid *of_get_property(conststruct device_node *np, constchar *name, int *lenp)
{ conststruct property *pp = of_find_property(np, name, lenp);
/** * __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
*/ staticint __of_device_is_compatible(conststruct device_node *device, constchar *compat, constchar *type, constchar *name)
{ conststruct property *prop; constchar *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;
}
/* Matching type is better than matching name */ if (type && type[0]) { if (!__of_node_is_type(device, type)) return 0;
score += 2;
}
/* Matching name is a bit better than not */ if (name && name[0]) { if (!of_node_name_eq(device, name)) return 0;
score++;
}
return score;
}
/** Checks if the given "compat" string matches one of the strings in * the device's "compatible" property
*/ int of_device_is_compatible(conststruct device_node *device, constchar *compat)
{ unsignedlong flags; int res;
/** Checks if the device is compatible with any of the entries in * a NULL terminated array of strings. Returns the best match * score or 0.
*/ int of_device_compatible_match(conststruct device_node *device, constchar *const *compat)
{ unsignedint tmp, score = 0;
if (!compat) return 0;
while (*compat) {
tmp = of_device_is_compatible(device, *compat); if (tmp > score)
score = tmp;
compat++;
}
/** * of_machine_compatible_match - Test root of device tree against a compatible array * @compats: NULL terminated array of compatible strings to look for in root node's compatible property. * * Returns true if the root node has any of the given compatible values in its * compatible property.
*/ bool of_machine_compatible_match(constchar *const *compats)
{ struct device_node *root; int rc = 0;
status = __of_get_property(device, "status", &statlen); if (status == NULL) returnfalse;
if (statlen > 0) { while (*strings) { unsignedint len = strlen(*strings);
if ((*strings)[len - 1] == '-') { if (!strncmp(status, *strings, len)) returntrue;
} else { if (!strcmp(status, *strings)) returntrue;
}
strings++;
}
}
returnfalse;
}
/** * __of_device_is_available - check if a device is available for use * * @device: Node to check for availability, with locks already held * * Return: True if the status property is absent or set to "okay" or "ok", * false otherwise
*/ staticbool __of_device_is_available(conststruct device_node *device)
{ staticconstchar * const ok[] = {"okay", "ok", NULL};
/** * __of_device_is_reserved - check if a device is reserved * * @device: Node to check for availability, with locks already held * * Return: True if the status property is set to "reserved", false otherwise
*/ staticbool __of_device_is_reserved(conststruct device_node *device)
{ staticconstchar * const reserved[] = {"reserved", NULL};
return __of_device_is_status(device, reserved);
}
/** * of_device_is_available - check if a device is available for use * * @device: Node to check for availability * * Return: True if the status property is absent or set to "okay" or "ok", * false otherwise
*/ bool of_device_is_available(conststruct device_node *device)
{ unsignedlong flags; bool 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);
/** * __of_device_is_fail - check if a device has status "fail" or "fail-..." * * @device: Node to check status for, with locks already held * * Return: True if the status property is set to "fail" or "fail-..." (for any * error code suffix), false otherwise
*/ staticbool __of_device_is_fail(conststruct device_node *device)
{ staticconstchar * const fail[] = {"fail", "fail-", NULL};
return __of_device_is_status(device, fail);
}
/** * of_device_is_big_endian - check if a device has BE registers * * @device: Node to check for endianness * * Return: 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(conststruct device_node *device)
{ if (of_property_read_bool(device, "big-endian")) returntrue; if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) &&
of_property_read_bool(device, "native-endian")) returntrue; returnfalse;
}
EXPORT_SYMBOL(of_device_is_big_endian);
/** * of_get_parent - Get a node's parent if any * @node: Node to get parent * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_get_parent(conststruct device_node *node)
{ struct device_node *np; unsignedlong flags;
/** * 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. * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_get_next_parent(struct device_node *node)
{ struct device_node *parent; unsignedlong flags;
/** * of_get_next_child - Iterate a node childs * @node: parent node * @prev: previous child of the parent node, or NULL to get first * * Return: 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(conststruct device_node *node, struct device_node *prev)
{ struct device_node *next; unsignedlong flags;
/** * of_get_next_child_with_prefix - Find the next child node with prefix * @node: parent node * @prev: previous child of the parent node, or NULL to get first * @prefix: prefix that the node name should have * * This function is like of_get_next_child(), except that it automatically * skips any nodes whose name doesn't have the given prefix. * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_get_next_child_with_prefix(conststruct device_node *node, struct device_node *prev, constchar *prefix)
{ struct device_node *next; unsignedlong flags;
if (!node) return NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
next = prev ? prev->sibling : node->child; for (; next; next = next->sibling) { if (!of_node_name_prefix(next, prefix)) continue; if (of_node_get(next)) break;
}
of_node_put(prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags); return next;
}
EXPORT_SYMBOL(of_get_next_child_with_prefix);
raw_spin_lock_irqsave(&devtree_lock, flags);
next = prev ? prev->sibling : node->child; for (; next; next = next->sibling) { if (!checker(next)) continue; if (of_node_get(next)) break;
}
of_node_put(prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags); return next;
}
/** * of_get_next_available_child - Find the next available child node * @node: parent node * @prev: previous child of the parent node, or NULL to get first * * This function is like of_get_next_child(), except that it * automatically skips any disabled nodes (i.e. status = "disabled").
*/ struct device_node *of_get_next_available_child(conststruct device_node *node, struct device_node *prev)
{ return of_get_next_status_child(node, prev, __of_device_is_available);
}
EXPORT_SYMBOL(of_get_next_available_child);
/** * of_get_next_reserved_child - Find the next reserved child node * @node: parent node * @prev: previous child of the parent node, or NULL to get first * * This function is like of_get_next_child(), except that it * automatically skips any disabled nodes (i.e. status = "disabled").
*/ struct device_node *of_get_next_reserved_child(conststruct device_node *node, struct device_node *prev)
{ return of_get_next_status_child(node, prev, __of_device_is_reserved);
}
EXPORT_SYMBOL(of_get_next_reserved_child);
/** * of_get_next_cpu_node - Iterate on cpu nodes * @prev: previous child of the /cpus node, or NULL to get first * * Unusable CPUs (those with the status property set to "fail" or "fail-...") * will be skipped. * * Return: A cpu 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_cpu_node(struct device_node *prev)
{ struct device_node *next = NULL; unsignedlong flags; struct device_node *node;
if (!prev)
node = of_find_node_by_path("/cpus");
raw_spin_lock_irqsave(&devtree_lock, flags); if (prev)
next = prev->sibling; elseif (node) {
next = node->child;
of_node_put(node);
} for (; next; next = next->sibling) { if (__of_device_is_fail(next)) continue; if (!(of_node_name_eq(next, "cpu") ||
__of_node_is_type(next, "cpu"))) continue; if (of_node_get(next)) break;
}
of_node_put(prev);
raw_spin_unlock_irqrestore(&devtree_lock, flags); return next;
}
EXPORT_SYMBOL(of_get_next_cpu_node);
/** * of_get_compatible_child - Find compatible child node * @parent: parent node * @compatible: compatible string * * Lookup child node whose compatible property contains the given compatible * string. * * Return: a node pointer with refcount incremented, use of_node_put() on it * when done; or NULL if not found.
*/ struct device_node *of_get_compatible_child(conststruct device_node *parent, constchar *compatible)
{ struct device_node *child;
for_each_child_of_node(parent, child) { if (of_device_is_compatible(child, compatible)) break;
}
/** * of_get_child_by_name - Find the child node by name for a given parent * @node: parent node * @name: child name to look for. * * This function looks for child node for given matching name * * Return: A node pointer if found, with refcount incremented, use * of_node_put() on it when done. * Returns NULL if node is not found.
*/ struct device_node *of_get_child_by_name(conststruct device_node *node, constchar *name)
{ struct device_node *child;
for_each_child_of_node(node, child) if (of_node_name_eq(child, name)) break; return child;
}
EXPORT_SYMBOL(of_get_child_by_name);
/** * of_get_available_child_by_name - Find the available child node by name for a given parent * @node: parent node * @name: child name to look for. * * This function looks for child node for given matching name and checks the * device's availability for use. * * Return: A node pointer if found, with refcount incremented, use * of_node_put() on it when done. * Returns NULL if node is not found.
*/ struct device_node *of_get_available_child_by_name(conststruct device_node *node, constchar *name)
{ struct device_node *child;
/** * 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 * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_find_node_opts_by_path(constchar *path, constchar **opts)
{ struct device_node *np = NULL; conststruct property *pp; unsignedlong flags; constchar *separator = strchr(path, ':');
if (strcmp(path, "/") == 0) return of_node_get(of_root);
/* The path could begin with an alias */ if (*path != '/') { int len; constchar *p = strchrnul(path, '/');
if (separator && separator < p)
p = separator;
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); if (!np)
np = of_node_get(of_root);
np = __of_find_node_by_full_path(np, path);
raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;
}
EXPORT_SYMBOL(of_find_node_opts_by_path);
/** * of_find_node_by_name - Find a node by its "name" property * @from: The node to start searching from or NULL; the node * you pass will not be searched, only the next one * will. Typically, you pass what the previous call * returned. of_node_put() will be called on @from. * @name: The name string to match against * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_find_node_by_name(struct device_node *from, constchar *name)
{ struct device_node *np; unsignedlong flags;
/** * of_find_node_by_type - Find a node by its "device_type" property * @from: The node to start searching from, or NULL to start searching * the entire device tree. The node you pass will not be * searched, only the next one will; typically, you pass * what the previous call returned. of_node_put() will be * called on from for you. * @type: The type string to match against * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_find_node_by_type(struct device_node *from, constchar *type)
{ struct device_node *np; unsignedlong flags;
/** * of_find_compatible_node - Find a node based on type and one of the * tokens in its "compatible" property * @from: The node to start searching from or NULL, the node * you pass will not be searched, only the next one * will; typically, you pass what the previous call * returned. of_node_put() will be called on it * @type: The type string to match "device_type" or NULL to ignore * @compatible: The string to match to one of the tokens in the device * "compatible" list. * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_find_compatible_node(struct device_node *from, constchar *type, constchar *compatible)
{ struct device_node *np; unsignedlong flags;
/** * of_find_node_with_property - Find a node which has a property with * the given name. * @from: The node to start searching from or NULL, the node * you pass will not be searched, only the next one * will; typically, you pass what the previous call * returned. of_node_put() will be called on it * @prop_name: The name of the property to look for. * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_find_node_with_property(struct device_node *from, constchar *prop_name)
{ struct device_node *np; unsignedlong flags;
/** * 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 * * Low level utility function used by device matching.
*/ conststruct of_device_id *of_match_node(conststruct of_device_id *matches, conststruct device_node *node)
{ conststruct of_device_id *match; unsignedlong flags;
/** * of_find_matching_node_and_match - Find a node based on an of_device_id * match table. * @from: The node to start searching from or NULL, the node * you pass will not be searched, only the next one * will; typically, you pass what the previous call * returned. of_node_put() will be called on it * @matches: array of of device match structures to search in * @match: Updated to point at the matches entry which matched * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_find_matching_node_and_match(struct device_node *from, conststruct of_device_id *matches, conststruct of_device_id **match)
{ struct device_node *np; conststruct of_device_id *m; unsignedlong flags;
if (match)
*match = NULL;
raw_spin_lock_irqsave(&devtree_lock, flags);
for_each_of_allnodes_from(from, np) {
m = __of_match_node(matches, np); if (m && of_node_get(np)) { if (match)
*match = m; break;
}
}
of_node_put(from);
raw_spin_unlock_irqrestore(&devtree_lock, flags); return np;
}
EXPORT_SYMBOL(of_find_matching_node_and_match);
/** * of_alias_from_compatible - Lookup appropriate alias for a device node * depending on compatible * @node: pointer to a device tree node * @alias: Pointer to buffer that alias value will be copied into * @len: Length of alias value * * Based on the value of the compatible property, this routine will attempt * to choose an appropriate alias value for a particular device tree node. * It does this by stripping the manufacturer prefix (as delimited by a ',') * from the first entry in the compatible list property. * * Note: The matching on just the "product" side of the compatible is a relic * from I2C and SPI. Please do not add any new user. * * Return: This routine returns 0 on success, <0 on failure.
*/ int of_alias_from_compatible(conststruct device_node *node, char *alias, int len)
{ constchar *compatible, *p; int cplen;
compatible = of_get_property(node, "compatible", &cplen); if (!compatible || strlen(compatible) > cplen) return -ENODEV;
p = strchr(compatible, ',');
strscpy(alias, p ? p + 1 : compatible, len); return 0;
}
EXPORT_SYMBOL_GPL(of_alias_from_compatible);
/** * of_find_node_by_phandle - Find a node given a phandle * @handle: phandle of the node to find * * Return: A node pointer with refcount incremented, use * of_node_put() on it when done.
*/ struct device_node *of_find_node_by_phandle(phandle handle)
{ struct device_node *np = NULL; unsignedlong flags;
u32 handle_hash;
if (!handle) return NULL;
handle_hash = of_phandle_cache_hash(handle);
raw_spin_lock_irqsave(&devtree_lock, flags);
if (phandle_cache[handle_hash] &&
handle == phandle_cache[handle_hash]->phandle)
np = phandle_cache[handle_hash];
if (!np) {
for_each_of_allnodes(np) if (np->phandle == handle &&
!of_node_check_flag(np, OF_DETACHED)) {
phandle_cache[handle_hash] = np; break;
}
}
int of_phandle_iterator_next(struct of_phandle_iterator *it)
{
uint32_t count = 0;
if (it->node) {
of_node_put(it->node);
it->node = NULL;
}
if (!it->cur || it->phandle_end >= it->list_end) return -ENOENT;
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) {
/* * Find the provider node and parse the #*-cells property to * determine the argument length.
*/
it->node = of_find_node_by_phandle(it->phandle);
if (it->cells_name) { if (!it->node) {
pr_err("%pOF: could not find phandle %d\n",
it->parent, it->phandle); goto err;
}
if (of_property_read_u32(it->node, it->cells_name,
&count)) { /* * If both cell_count and cells_name is given, * fall back to cell_count in absence * of the cells_name property
*/ if (it->cell_count >= 0) {
count = it->cell_count;
} else {
pr_err("%pOF: could not get %s for %pOF\n",
it->parent,
it->cells_name,
it->node); goto err;
}
}
} else {
count = it->cell_count;
}
/* * Make sure that the arguments actually fit in the remaining * property data length
*/ if (it->cur + count > it->list_end) { if (it->cells_name)
pr_err("%pOF: %s = %d found %td\n",
it->parent, it->cells_name,
count, it->list_end - it->cur); else
pr_err("%pOF: phandle %s needs %d, found %td\n",
it->parent, of_node_full_name(it->node),
count, it->list_end - it->cur); goto err;
}
}
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;
}
int __of_parse_phandle_with_args(conststruct device_node *np, constchar *list_name, constchar *cells_name, int cell_count, int index, struct of_phandle_args *out_args)
{ struct of_phandle_iterator it; int rc, cur_index = 0;
if (index < 0) return -EINVAL;
/* 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 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 (!it.phandle) goto err;
/** * of_parse_phandle_with_args_map() - Find a node pointed by phandle in a list and remap it * @np: pointer to a device tree node containing a list * @list_name: property name that contains a list * @stem_name: stem of property names that specify 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. The difference between this function and of_parse_phandle_with_args() * is that this API remaps a phandle if the node the phandle points to has * a <@stem_name>-map property. * * 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>; * }; * * phandle3: node3 { * #list-cells = <1>; * list-map = <0 &phandle2 3>, * <1 &phandle2 2>, * <2 &phandle1 5 1>; * list-map-mask = <0x3>; * }; * * node4 { * list = <&phandle1 1 2 &phandle3 0>; * }; * * To get a device_node of the ``node2`` node you may call this: * of_parse_phandle_with_args(node4, "list", "list", 1, &args);
*/ int of_parse_phandle_with_args_map(conststruct device_node *np, constchar *list_name, constchar *stem_name, int index, struct of_phandle_args *out_args)
{ char *cells_name __free(kfree) = kasprintf(GFP_KERNEL, "#%s-cells", stem_name); char *map_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map", stem_name); char *mask_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map-mask", stem_name); char *pass_name __free(kfree) = kasprintf(GFP_KERNEL, "%s-map-pass-thru", stem_name); struct device_node *cur, *new = NULL; const __be32 *map, *mask, *pass; staticconst __be32 dummy_mask[] = { [0 ... (MAX_PHANDLE_ARGS - 1)] = cpu_to_be32(~0) }; staticconst __be32 dummy_pass[] = { [0 ... (MAX_PHANDLE_ARGS - 1)] = cpu_to_be32(0) };
__be32 initial_match_array[MAX_PHANDLE_ARGS]; const __be32 *match_array = initial_match_array; int i, ret, map_len, match;
u32 list_size, new_size;
if (index < 0) return -EINVAL;
if (!cells_name || !map_name || !mask_name || !pass_name) return -ENOMEM;
ret = __of_parse_phandle_with_args(np, list_name, cells_name, -1, index,
out_args); if (ret) return ret;
/* Get the #<list>-cells property */
cur = out_args->np;
ret = of_property_read_u32(cur, cells_name, &list_size); if (ret < 0) goto put;
/* Precalculate the match array - this simplifies match loop */ for (i = 0; i < list_size; i++)
initial_match_array[i] = cpu_to_be32(out_args->args[i]);
ret = -EINVAL; while (cur) { /* Get the <list>-map property */
map = of_get_property(cur, map_name, &map_len); if (!map) { return 0;
}
map_len /= sizeof(u32);
/* Get the <list>-map-mask property (optional) */
mask = of_get_property(cur, mask_name, NULL); if (!mask)
mask = dummy_mask; /* Iterate through <list>-map property */
match = 0; while (map_len > (list_size + 1) && !match) { /* Compare specifiers */
match = 1; for (i = 0; i < list_size; i++, map_len--)
match &= !((match_array[i] ^ *map++) & mask[i]);
of_node_put(new); new = of_find_node_by_phandle(be32_to_cpup(map));
map++;
map_len--;
/* Check if not found */ if (!new) {
ret = -EINVAL; goto put;
}
if (!of_device_is_available(new))
match = 0;
ret = of_property_read_u32(new, cells_name, &new_size); if (ret) goto put;
/* Check for malformed properties */ if (WARN_ON(new_size > MAX_PHANDLE_ARGS) ||
map_len < new_size) {
ret = -EINVAL; goto put;
}
/* Move forward by new node's #<list>-cells amount */
map += new_size;
map_len -= new_size;
} if (!match) {
ret = -ENOENT; goto put;
}
/* Get the <list>-map-pass-thru property (optional) */
pass = of_get_property(cur, pass_name, NULL); if (!pass)
pass = dummy_pass;
/* * Successfully parsed a <list>-map translation; copy new * specifier into the out_args structure, keeping the * bits specified in <list>-map-pass-thru.
*/ for (i = 0; i < new_size; i++) {
__be32 val = *(map - new_size + i);
if (i < list_size) {
val &= ~pass[i];
val |= cpu_to_be32(out_args->args[i]) & pass[i];
}
initial_match_array[i] = val;
out_args->args[i] = be32_to_cpu(val);
}
out_args->args_count = list_size = new_size; /* Iterate again with new provider */
out_args->np = new;
of_node_put(cur);
cur = new; new = NULL;
}
put:
of_node_put(cur);
of_node_put(new); return ret;
}
EXPORT_SYMBOL(of_parse_phandle_with_args_map);
/** * 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 * * Return: 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(conststruct device_node *np, constchar *list_name, constchar *cells_name)
{ struct of_phandle_iterator it; int rc, cur_index = 0;
/* * If cells_name is NULL we assume a cell count of 0. This makes * counting the phandles trivial as each 32bit word in the list is a * phandle and no arguments are to consider. So we don't iterate through * the list but just use the length to determine the phandle count.
*/ if (!cells_name) { const __be32 *list; int size;
list = of_get_property(np, list_name, &size); if (!list) return -ENOENT;
if (!rc)
of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop, NULL);
return rc;
}
EXPORT_SYMBOL_GPL(of_add_property);
int __of_remove_property(struct device_node *np, struct property *prop)
{ unsignedlong flags; int rc = -ENODEV;
raw_spin_lock_irqsave(&devtree_lock, flags);
if (__of_remove_property_from_list(&np->properties, prop)) { /* Found the property, add it to deadprops list */
prop->next = np->deadprops;
np->deadprops = prop;
rc = 0;
}
raw_spin_unlock_irqrestore(&devtree_lock, flags); if (rc) return rc;
__of_remove_property_sysfs(np, prop); return 0;
}
/** * of_remove_property - Remove a property from a node. * @np: Caller's Device Node * @prop: Property to remove * * 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_remove_property(struct device_node *np, struct property *prop)
{ int 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)
{ struct property *oldprop; int rc;
/** * of_alias_scan - Scan all properties of the 'aliases' node * @dt_alloc: An allocator that provides a virtual address to memory * for storing the resulting tree * * The function scans all the properties of the 'aliases' node and populates * the global lookup table with the properties.
*/ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align))
{ conststruct property *pp;
/* Skip those we do not want to proceed */ if (is_pseudo_property(pp->name)) continue;
np = of_find_node_by_path(pp->value); if (!np) continue;
/* walk the alias backwards to extract the id and work out
* the 'stem' string */ while (isdigit(*(end-1)) && end > start)
end--;
len = end - start;
if (kstrtoint(end, 10, &id) < 0) continue;
/* Allocate an alias_prop with enough space for the stem */
ap = dt_alloc(sizeof(*ap) + len + 1, __alignof__(*ap)); if (!ap) continue;
memset(ap, 0, sizeof(*ap) + len + 1);
ap->alias = start;
of_alias_add(ap, np, id, start, len);
}
}
/** * of_alias_get_id - Get alias id for the given device_node * @np: Pointer to the given device_node * @stem: Alias stem of the given device_node * * The function travels the lookup table to get the alias id for the given * device_node and alias stem. * * Return: The alias id if found.
*/ int of_alias_get_id(conststruct device_node *np, constchar *stem)
{ struct alias_prop *app; int id = -ENODEV;
if (np == app->np) {
id = app->id; break;
}
}
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(constchar *stem)
{ struct alias_prop *app; int id = -ENODEV;
/** * 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. * * Return: TRUE if console successfully setup. Otherwise return FALSE.
*/ bool of_console_check(conststruct device_node *dn, char *name, int index)
{ if (!dn || dn != of_stdout || console_set_on_cmdline) returnfalse;
/* * XXX: cast `options' to char pointer to suppress complication * warnings: printk, UART and console drivers expect char pointer.
*/ return !add_preferred_console(name, index, (char *)of_stdout_options);
}
EXPORT_SYMBOL_GPL(of_console_check);
/** * of_find_next_cache_node - Find a node's subsidiary cache * @np: node of type "cpu" or "cache" * * Return: 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(conststruct device_node *np)
{ struct device_node *child, *cache_node;
/* OF on pmac has nodes instead of properties named "l2-cache" * beneath CPU nodes.
*/ if (IS_ENABLED(CONFIG_PPC_PMAC) && of_node_is_type(np, "cpu"))
for_each_child_of_node(np, child) if (of_node_is_type(child, "cache")) return child;
return NULL;
}
/** * of_find_last_cache_level - Find the level at which the last cache is * present for the given logical cpu * * @cpu: cpu number(logical index) for which the last cache level is needed * * Return: The level at which the last cache is present. It is exactly * same as the total number of cache levels for the given logical cpu.
*/ int of_find_last_cache_level(unsignedint cpu)
{
u32 cache_level = 0; struct device_node *prev = NULL, *np = of_cpu_device_node_get(cpu);
/** * of_map_id - Translate an ID through a downstream mapping. * @np: root complex device node. * @id: device ID to map. * @map_name: property name of the map to use. * @map_mask_name: optional property name of the mask to use. * @target: optional pointer to a target device node. * @id_out: optional pointer to receive the translated ID. * * Given a device ID, look up the appropriate implementation-defined * platform ID and/or the target device which receives transactions on that * ID, as per the "iommu-map" and "msi-map" bindings. Either of @target or * @id_out may be NULL if only the other is required. If @target points to * a non-NULL device node pointer, only entries targeting that node will be * matched; if it points to a NULL value, it will receive the device node of * the first matching target phandle, with a reference held. * * Return: 0 on success or a standard error code on failure.
*/ int of_map_id(conststruct device_node *np, u32 id, constchar *map_name, constchar *map_mask_name, struct device_node **target, u32 *id_out)
{
u32 map_mask, masked_id; int map_len; const __be32 *map = NULL;
if (!np || !map_name || (!target && !id_out)) return -EINVAL;
map = of_get_property(np, map_name, &map_len); if (!map) { if (target) return -ENODEV; /* Otherwise, no map implies no translation */
*id_out = id; return 0;
}
/* The default is to select all bits. */
map_mask = 0xffffffff;
/* * Can be overridden by "{iommu,msi}-map-mask" property. * If of_property_read_u32() fails, the default is used.
*/ if (map_mask_name)
of_property_read_u32(np, map_mask_name, &map_mask);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.