diff options
author | Johan Hovold <johan@kernel.org> | 2018-08-27 04:21:45 -0400 |
---|---|---|
committer | Rob Herring <robh@kernel.org> | 2018-08-29 09:06:46 -0400 |
commit | 36156f9241cb0f9e37d998052873ca7501ad4b36 (patch) | |
tree | 203d1e52a9e5a942a2b99ae0ecb984fa87453df8 | |
parent | 5b394b2ddf0347bef56e50c69a58773c94343ff3 (diff) |
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>
-rw-r--r-- | drivers/of/base.c | 25 | ||||
-rw-r--r-- | include/linux/of.h | 8 |
2 files changed, 33 insertions, 0 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 466e3c8582f0..bc420d2aa5f5 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -720,6 +720,31 @@ struct device_node *of_get_next_available_child(const struct device_node *node, | |||
720 | EXPORT_SYMBOL(of_get_next_available_child); | 720 | EXPORT_SYMBOL(of_get_next_available_child); |
721 | 721 | ||
722 | /** | 722 | /** |
723 | * of_get_compatible_child - Find compatible child node | ||
724 | * @parent: parent node | ||
725 | * @compatible: compatible string | ||
726 | * | ||
727 | * Lookup child node whose compatible property contains the given compatible | ||
728 | * string. | ||
729 | * | ||
730 | * Returns a node pointer with refcount incremented, use of_node_put() on it | ||
731 | * when done; or NULL if not found. | ||
732 | */ | ||
733 | struct device_node *of_get_compatible_child(const struct device_node *parent, | ||
734 | const char *compatible) | ||
735 | { | ||
736 | struct device_node *child; | ||
737 | |||
738 | for_each_child_of_node(parent, child) { | ||
739 | if (of_device_is_compatible(child, compatible)) | ||
740 | break; | ||
741 | } | ||
742 | |||
743 | return child; | ||
744 | } | ||
745 | EXPORT_SYMBOL(of_get_compatible_child); | ||
746 | |||
747 | /** | ||
723 | * of_get_child_by_name - Find the child node by name for a given parent | 748 | * of_get_child_by_name - Find the child node by name for a given parent |
724 | * @node: parent node | 749 | * @node: parent node |
725 | * @name: child name to look for. | 750 | * @name: child name to look for. |
diff --git a/include/linux/of.h b/include/linux/of.h index 4d25e4f952d9..b99a1a8c2952 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
@@ -290,6 +290,8 @@ extern struct device_node *of_get_next_child(const struct device_node *node, | |||
290 | extern struct device_node *of_get_next_available_child( | 290 | extern struct device_node *of_get_next_available_child( |
291 | const struct device_node *node, struct device_node *prev); | 291 | const struct device_node *node, struct device_node *prev); |
292 | 292 | ||
293 | extern struct device_node *of_get_compatible_child(const struct device_node *parent, | ||
294 | const char *compatible); | ||
293 | extern struct device_node *of_get_child_by_name(const struct device_node *node, | 295 | extern struct device_node *of_get_child_by_name(const struct device_node *node, |
294 | const char *name); | 296 | const char *name); |
295 | 297 | ||
@@ -632,6 +634,12 @@ static inline bool of_have_populated_dt(void) | |||
632 | return false; | 634 | return false; |
633 | } | 635 | } |
634 | 636 | ||
637 | static inline struct device_node *of_get_compatible_child(const struct device_node *parent, | ||
638 | const char *compatible) | ||
639 | { | ||
640 | return NULL; | ||
641 | } | ||
642 | |||
635 | static inline struct device_node *of_get_child_by_name( | 643 | static inline struct device_node *of_get_child_by_name( |
636 | const struct device_node *node, | 644 | const struct device_node *node, |
637 | const char *name) | 645 | const char *name) |