2371 lines · 62.0 KB · C
RawDownload
// 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. */ #define pr_fmt(fmt)	"OF: " fmt #include <linux/cleanup.h>#include <linux/console.h>#include <linux/ctype.h>#include <linux/cpu.h>#include <linux/module.h>#include <linux/of.h>#include <linux/of_device.h>#include <linux/of_graph.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/string.h>#include <linux/proc_fs.h> #include "of_private.h" LIST_HEAD(aliases_lookup); struct device_node *of_root;EXPORT_SYMBOL(of_root);struct device_node *of_chosen;EXPORT_SYMBOL(of_chosen);struct device_node *of_aliases;struct device_node *of_stdout;static const char *of_stdout_options; struct kset *of_kset; /* * 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); bool of_node_name_eq(const struct device_node *np, const char *name){	const char *node_name;	size_t len; 	if (!np)		return false; 	node_name = kbasename(np->full_name);	len = strchrnul(node_name, '@') - node_name; 	return (strlen(name) == len) && (strncmp(node_name, name, len) == 0);}EXPORT_SYMBOL(of_node_name_eq); bool of_node_name_prefix(const struct device_node *np, const char *prefix){	if (!np)		return false; 	return strncmp(kbasename(np->full_name), prefix, strlen(prefix)) == 0;}EXPORT_SYMBOL(of_node_name_prefix); static bool __of_node_is_type(const struct device_node *np, const char *type){	const char *match;	int len; 	if (!np || !type)		return false; 	match = __of_get_property(np, "device_type", &len);	if (!match || len <= 0 || strnlen(match, len) >= len)		return false; 	return !strcmp(match, type);} #define EXCLUDED_DEFAULT_CELLS_PLATFORMS ( \	IS_ENABLED(CONFIG_SPARC) || \	of_find_compatible_node(NULL, NULL, "coreboot") \) 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; 	return of_bus_n_addr_cells(np);}EXPORT_SYMBOL(of_n_addr_cells); 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; 	return of_bus_n_size_cells(np);}EXPORT_SYMBOL(of_n_size_cells); #ifdef CONFIG_NUMAint __weak of_node_to_nid(struct device_node *np){	return NUMA_NO_NODE;}#endif #define OF_PHANDLE_CACHE_BITS	7#define OF_PHANDLE_CACHE_SZ	BIT(OF_PHANDLE_CACHE_BITS) static struct device_node *phandle_cache[OF_PHANDLE_CACHE_SZ]; static u32 of_phandle_cache_hash(phandle handle){	return hash_32(handle, OF_PHANDLE_CACHE_BITS);} /* * Caller must hold devtree_lock. */void __of_phandle_cache_inv_entry(phandle handle){	u32 handle_hash;	struct device_node *np; 	if (!handle)		return; 	handle_hash = of_phandle_cache_hash(handle); 	np = phandle_cache[handle_hash];	if (np && handle == np->phandle)		phandle_cache[handle_hash] = NULL;} void __init of_core_init(void){	struct device_node *np; 	of_platform_register_reconfig_notifier(); 	/* 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("failed to register existing nodes\n");		return;	}	for_each_of_allnodes(np) {		__of_attach_node_sysfs(np);		if (np->phandle && !phandle_cache[of_phandle_cache_hash(np->phandle)])			phandle_cache[of_phandle_cache_hash(np->phandle)] = 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");} static struct property *__of_find_property(const struct device_node *np,					   const char *name, int *lenp){	struct property *pp; 	if (!np)		return NULL; 	for (pp = np->properties; pp; pp = pp->next) {		if (of_prop_cmp(pp->name, name) == 0) {			if (lenp)				*lenp = pp->length;			break;		}	} 	return pp;} struct property *of_find_property(const struct device_node *np,				  const char *name,				  int *lenp){	struct property *pp;	unsigned long flags; 	raw_spin_lock_irqsave(&devtree_lock, flags);	pp = __of_find_property(np, name, lenp);	raw_spin_unlock_irqrestore(&devtree_lock, flags); 	return pp;}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 *		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;	unsigned long flags; 	raw_spin_lock_irqsave(&devtree_lock, flags);	np = __of_find_all_nodes(prev);	of_node_get(np);	of_node_put(prev);	raw_spin_unlock_irqrestore(&devtree_lock, flags);	return np;}EXPORT_SYMBOL(of_find_all_nodes); /* * Find a property with a given name for a given node * and return the value. */const void *__of_get_property(const struct device_node *np,			      const char *name, int *lenp){	const struct property *pp = __of_find_property(np, name, lenp); 	return pp ? pp->value : NULL;} /* * Find a property with a given name for a given node * and return the value. */const void *of_get_property(const struct device_node *np, const char *name,			    int *lenp){	const struct property *pp = of_find_property(np, name, lenp); 	return pp ? pp->value : NULL;}EXPORT_SYMBOL(of_get_property); /** * __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 *type, const char *name){	const 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;	} 	/* 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(const struct device_node *device,		const char *compat){	unsigned long flags;	int res; 	raw_spin_lock_irqsave(&devtree_lock, flags);	res = __of_device_is_compatible(device, compat, NULL, NULL);	raw_spin_unlock_irqrestore(&devtree_lock, flags);	return res;}EXPORT_SYMBOL(of_device_is_compatible); /** 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(const struct device_node *device,			       const char *const *compat){	unsigned int tmp, score = 0; 	if (!compat)		return 0; 	while (*compat) {		tmp = of_device_is_compatible(device, *compat);		if (tmp > score)			score = tmp;		compat++;	} 	return score;}EXPORT_SYMBOL_GPL(of_device_compatible_match); /** * 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(const char *const *compats){	struct device_node *root;	int rc = 0; 	root = of_find_node_by_path("/");	if (root) {		rc = of_device_compatible_match(root, compats);		of_node_put(root);	} 	return rc != 0;}EXPORT_SYMBOL(of_machine_compatible_match); /** * of_machine_read_compatible - Get the compatible string of this machine * @compatible: address at which the address of the compatible string will be *              stored * @index: index of the compatible entry in the list * * Returns: * 0 on success, negative error number on failure. */int of_machine_read_compatible(const char **compatible, unsigned int index){	return of_property_read_string_index(of_root, "compatible", index, compatible);}EXPORT_SYMBOL_GPL(of_machine_read_compatible); /** * of_machine_read_model - Get the model string of this machine * @model: address at which the address of the model string will be stored * * Returns: * 0 on success, negative error number on failure. */int of_machine_read_model(const char **model){	return of_property_read_string(of_root, "model", model);}EXPORT_SYMBOL_GPL(of_machine_read_model); /** * of_machine_get_match - Test root of device tree against an of_device_id array * @matches:	NULL terminated array of of_device_id match structures to search in * * Returns matched entry or NULL */const struct of_device_id *of_machine_get_match(const struct of_device_id *matches){	struct device_node *root;	const struct of_device_id *match = NULL; 	root = of_find_node_by_path("/");	if (root) {		match = of_match_node(matches, root);		of_node_put(root);	} 	return match;}EXPORT_SYMBOL(of_machine_get_match); /** * of_machine_get_match_data - Tell if root of device tree has a matching of_match structure * @matches:	NULL terminated array of of_device_id match structures to search in * * Returns data associated with matched entry or NULL */const void *of_machine_get_match_data(const struct of_device_id *matches)

Lines 1–500 of 2371.