of: add helper to lookup compatible child node
Add of_get_compatible_child() helper that can be used to lookup compatible child nodes. Several drivers currently use of_find_compatible_node() to lookup child nodes while failing to notice that the of_find_ functions search the entire tree depth-first (from a given start node) and therefore can match unrelated nodes. The fact that these functions also drop a reference to the node they start searching from (e.g. the parent node) is typically also overlooked, something which can lead to use-after-free bugs. Signed-off-by: Johan Hovold <johan@kernel.org> Signed-off-by: Rob Herring <robh@kernel.org>
This commit is contained in:
		
							parent
							
								
									5b394b2ddf
								
							
						
					
					
						commit
						36156f9241
					
				| @ -719,6 +719,31 @@ struct device_node *of_get_next_available_child(const struct device_node *node, | |||||||
| } | } | ||||||
| EXPORT_SYMBOL(of_get_next_available_child); | EXPORT_SYMBOL(of_get_next_available_child); | ||||||
| 
 | 
 | ||||||
|  | /**
 | ||||||
|  |  * 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. | ||||||
|  |  * | ||||||
|  |  * Returns 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(const struct device_node *parent, | ||||||
|  | 				const char *compatible) | ||||||
|  | { | ||||||
|  | 	struct device_node *child; | ||||||
|  | 
 | ||||||
|  | 	for_each_child_of_node(parent, child) { | ||||||
|  | 		if (of_device_is_compatible(child, compatible)) | ||||||
|  | 			break; | ||||||
|  | 	} | ||||||
|  | 
 | ||||||
|  | 	return child; | ||||||
|  | } | ||||||
|  | EXPORT_SYMBOL(of_get_compatible_child); | ||||||
|  | 
 | ||||||
| /**
 | /**
 | ||||||
|  *	of_get_child_by_name - Find the child node by name for a given parent |  *	of_get_child_by_name - Find the child node by name for a given parent | ||||||
|  *	@node:	parent node |  *	@node:	parent node | ||||||
|  | |||||||
| @ -290,6 +290,8 @@ extern struct device_node *of_get_next_child(const struct device_node *node, | |||||||
| extern struct device_node *of_get_next_available_child( | extern struct device_node *of_get_next_available_child( | ||||||
| 	const struct device_node *node, struct device_node *prev); | 	const struct device_node *node, struct device_node *prev); | ||||||
| 
 | 
 | ||||||
|  | extern struct device_node *of_get_compatible_child(const struct device_node *parent, | ||||||
|  | 					const char *compatible); | ||||||
| extern struct device_node *of_get_child_by_name(const struct device_node *node, | extern struct device_node *of_get_child_by_name(const struct device_node *node, | ||||||
| 					const char *name); | 					const char *name); | ||||||
| 
 | 
 | ||||||
| @ -632,6 +634,12 @@ static inline bool of_have_populated_dt(void) | |||||||
| 	return false; | 	return false; | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | static inline struct device_node *of_get_compatible_child(const struct device_node *parent, | ||||||
|  | 					const char *compatible) | ||||||
|  | { | ||||||
|  | 	return NULL; | ||||||
|  | } | ||||||
|  | 
 | ||||||
| static inline struct device_node *of_get_child_by_name( | static inline struct device_node *of_get_child_by_name( | ||||||
| 					const struct device_node *node, | 					const struct device_node *node, | ||||||
| 					const char *name) | 					const char *name) | ||||||
|  | |||||||
		Loading…
	
		Reference in New Issue
	
	Block a user