2378 lines · 63.0 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/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_allnodes;EXPORT_SYMBOL(of_allnodes);struct device_node *of_chosen;struct device_node *of_aliases;static struct device_node *of_stdout; static struct kset *of_kset; /* * Used to protect the of_aliases; but also overloaded to hold off addition of * nodes to sysfs */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)		kobject_get(&node->kobj);	return node;}EXPORT_SYMBOL(of_node_get); static inline struct device_node *kobj_to_device_node(struct kobject *kobj){	return container_of(kobj, struct device_node, kobj);} /** *	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 kobject *kobj){	struct device_node *node = kobj_to_device_node(kobj);	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();		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)		kobject_put(&node->kobj);}EXPORT_SYMBOL(of_node_put);#elsestatic void of_node_release(struct kobject *kobj){	/* Without CONFIG_OF_DYNAMIC, no nodes gets freed */}#endif /* CONFIG_OF_DYNAMIC */ 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 property *pp = container_of(bin_attr, struct property, attr);	return memory_read_from_buffer(buf, count, &offset, pp->value, pp->length);} static const char *safe_name(struct kobject *kobj, const char *orig_name){	const char *name = orig_name;	struct kernfs_node *kn;	int i = 0; 	/* 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);	} 	if (name != orig_name)		pr_warn("device-tree: Duplicate name in %s, renamed to \"%s\"\n",			kobject_name(kobj), name);	return name;} static int __of_add_property_sysfs(struct device_node *np, struct property *pp){	int rc; 	/* Important: Don't leak passwords */	bool secure = strncmp(pp->name, "security-", 9) == 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;} static int __of_node_add(struct device_node *np){	const char *name;	struct property *pp;	int rc; 	np->kobj.kset = of_kset;	if (!np->parent) {		/* Nodes without parents are new top level trees */		rc = kobject_add(&np->kobj, NULL, "%s",				 safe_name(&of_kset->kobj, "base"));	} else {		name = safe_name(&np->parent->kobj, kbasename(np->full_name));		if (!name || !name[0])			return -EINVAL; 		rc = kobject_add(&np->kobj, &np->parent->kobj, "%s", name);	}	if (rc)		return rc; 	for_each_property_of_node(np, pp)		__of_add_property_sysfs(np, pp); 	return 0;} int of_node_add(struct device_node *np){	int rc = 0; 	BUG_ON(!of_node_is_initialized(np)); 	/*	 * Grab the mutex here so that in a race condition between of_init() and	 * of_node_add(), node addition will still be consistent.	 */	mutex_lock(&of_aliases_mutex);	if (of_kset)		rc = __of_node_add(np);	else		/* This scenario may be perfectly valid, but report it anyway */		pr_info("of_node_add(%s) before of_init()\n", np->full_name);	mutex_unlock(&of_aliases_mutex);	return rc;} #if defined(CONFIG_OF_DYNAMIC)static void of_node_remove(struct device_node *np){	struct property *pp; 	BUG_ON(!of_node_is_initialized(np)); 	/* only remove properties if on sysfs */	if (of_node_is_attached(np)) {		for_each_property_of_node(np, pp)			sysfs_remove_bin_file(&np->kobj, &pp->attr);		kobject_del(&np->kobj);	} 	/* finally remove the kobj_init ref */	of_node_put(np);}#endif static int __init of_init(void){	struct device_node *np; 	/* Create the kset, and register existing nodes */	mutex_lock(&of_aliases_mutex);	of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj);	if (!of_kset) {		mutex_unlock(&of_aliases_mutex);		return -ENOMEM;	}	for_each_of_allnodes(np)		__of_node_add(np);	mutex_unlock(&of_aliases_mutex); 	/* Symlink in /proc as required by userspace ABI */	if (of_allnodes)		proc_symlink("device-tree", NULL, "/sys/firmware/devicetree/base"); 	return 0;}core_initcall(of_init); 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); /** * __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

Lines 1–500 of 2378.

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t