1942 lines · 51.4 KB · C
RawDownload
/* * 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. * *      This program is free software; you can redistribute it and/or *      modify it under the terms of the GNU General Public License *      as published by the Free Software Foundation; either version *      2 of the License, or (at your option) any later version. */#include <linux/ctype.h>#include <linux/cpu.h>#include <linux/module.h>#include <linux/of.h>#include <linux/spinlock.h>#include <linux/slab.h>#include <linux/proc_fs.h> #include "of_private.h" LIST_HEAD(aliases_lookup); struct device_node *of_allnodes;EXPORT_SYMBOL(of_allnodes);struct device_node *of_chosen;struct device_node *of_aliases;static struct device_node *of_stdout; DEFINE_MUTEX(of_aliases_mutex); /* use when traversing tree through the allnext, child, sibling, * or parent members of struct device_node. */DEFINE_RAW_SPINLOCK(devtree_lock); int of_n_addr_cells(struct device_node *np){	const __be32 *ip; 	do {		if (np->parent)			np = np->parent;		ip = of_get_property(np, "#address-cells", NULL);		if (ip)			return be32_to_cpup(ip);	} while (np->parent);	/* No #address-cells property for the root node */	return OF_ROOT_NODE_ADDR_CELLS_DEFAULT;}EXPORT_SYMBOL(of_n_addr_cells); int of_n_size_cells(struct device_node *np){	const __be32 *ip; 	do {		if (np->parent)			np = np->parent;		ip = of_get_property(np, "#size-cells", NULL);		if (ip)			return be32_to_cpup(ip);	} while (np->parent);	/* No #size-cells property for the root node */	return OF_ROOT_NODE_SIZE_CELLS_DEFAULT;}EXPORT_SYMBOL(of_n_size_cells); #ifdef CONFIG_NUMAint __weak of_node_to_nid(struct device_node *np){	return numa_node_id();}#endif #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){	if (node)		kref_get(&node->kref);	return node;}EXPORT_SYMBOL(of_node_get); static inline struct device_node *kref_to_device_node(struct kref *kref){	return container_of(kref, struct device_node, kref);} /** *	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 device_node *node = kref_to_device_node(kref);	struct property *prop = node->properties; 	/* 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;	} 	if (!of_node_check_flag(node, OF_DYNAMIC))		return; 	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;		}	}	kfree(node->full_name);	kfree(node->data);	kfree(node);} /** *	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){	if (node)		kref_put(&node->kref, of_node_release);}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){	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); /** * 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 * * Returns 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 = prev ? prev->allnext : of_allnodes;	for (; np != NULL; np = np->allnext)		if (of_node_get(np))			break;	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. */static const void *__of_get_property(const struct device_node *np,				     const char *name, int *lenp){	struct property *pp = __of_find_property(np, name, lenp); 	return pp ? pp->value : NULL;} /* * Find a property with a given name for a given node * and return the value. */const void *of_get_property(const struct device_node *np, const char *name,			    int *lenp){	struct property *pp = of_find_property(np, name, lenp); 	return pp ? pp->value : NULL;}EXPORT_SYMBOL(of_get_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; 	if (__of_find_n_match_cpu_property(cpun, "reg", cpu, thread))		return true; 	return false;} /** * 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); /** Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */static int __of_device_is_compatible(const struct device_node *device,				     const char *compat){	const char* cp;	int cplen, l; 	cp = __of_get_property(device, "compatible", &cplen);	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;	} 	return 0;} /** Checks if the given "compat" string matches one of the strings in * the device's "compatible" property */int of_device_is_compatible(const struct device_node *device,		const char *compat){	unsigned long flags;	int res; 	raw_spin_lock_irqsave(&devtree_lock, flags);	res = __of_device_is_compatible(device, compat);	raw_spin_unlock_irqrestore(&devtree_lock, flags);	return res;}EXPORT_SYMBOL(of_device_is_compatible); /** * 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 * compatible property. */int of_machine_is_compatible(const char *compat){	struct device_node *root;	int rc = 0; 	root = of_find_node_by_path("/");	if (root) {		rc = of_device_is_compatible(root, compat);		of_node_put(root);	}	return rc;}EXPORT_SYMBOL(of_machine_is_compatible); /** *  __of_device_is_available - check if a device is available for use * *  @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 */static int __of_device_is_available(const struct device_node *device){	const char *status;	int statlen; 	status = __of_get_property(device, "status", &statlen);	if (status == NULL)		return 1; 	if (statlen > 0) {		if (!strcmp(status, "okay") || !strcmp(status, "ok"))			return 1;	} 	return 0;} /** *  of_device_is_available - check if a device is available for use * *  @device: Node to check for availability * *  Returns 1 if the status property is absent or set to "okay" or "ok", *  0 otherwise */int of_device_is_available(const struct device_node *device){	unsigned long flags;	int res; 	raw_spin_lock_irqsave(&devtree_lock, flags);	res = __of_device_is_available(device);	raw_spin_unlock_irqrestore(&devtree_lock, flags);	return res; }EXPORT_SYMBOL(of_device_is_available); /** *	of_get_parent - Get a node's parent if any *	@node:	Node to get parent * *	Returns a node pointer with refcount incremented, use *	of_node_put() on it when done. */struct device_node *of_get_parent(const struct device_node *node){	struct device_node *np;	unsigned long flags; 	if (!node)		return NULL; 	raw_spin_lock_irqsave(&devtree_lock, flags);	np = of_node_get(node->parent);	raw_spin_unlock_irqrestore(&devtree_lock, flags);	return np;}EXPORT_SYMBOL(of_get_parent); /** *	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. * *	Returns 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;	unsigned long flags; 	if (!node)		return NULL; 	raw_spin_lock_irqsave(&devtree_lock, flags);	parent = of_node_get(node->parent);	of_node_put(node);	raw_spin_unlock_irqrestore(&devtree_lock, flags);	return parent;}EXPORT_SYMBOL(of_get_next_parent); /**

Lines 1–500 of 1942.