aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorOliver O'Halloran <oohall@gmail.com>2017-04-06 14:01:57 +1000
committerStewart Smith <stewart@linux.vnet.ibm.com>2017-04-07 14:51:34 +1000
commit510e2b066b172a4b46e18315ddac30721b5a7526 (patch)
treeca54208f3e3b3e85db3bb79461c9101e47e4e40b
parent47a4831befa13e8fa4da0529a233415e5a43ac5f (diff)
downloadskiboot-510e2b066b172a4b46e18315ddac30721b5a7526.zip
skiboot-510e2b066b172a4b46e18315ddac30721b5a7526.tar.gz
skiboot-510e2b066b172a4b46e18315ddac30721b5a7526.tar.bz2
device: add dt_find_by_name_addr
Adds two helper functions that allow device nodes to be found via their name and unit address. One will take an integer address and format it to a hex string while the other looks up the unit based a user supplied string. This is handy in a few places inside the HDAT parser. Signed-off-by: Oliver O'Halloran <oohall@gmail.com> Reviewed-by: Vasant Hegde <hegdevasant@linux.vnet.ibm.com> Signed-off-by: Stewart Smith <stewart@linux.vnet.ibm.com>
-rw-r--r--core/device.c50
-rw-r--r--core/test/run-device.c1
-rw-r--r--include/device.h5
3 files changed, 56 insertions, 0 deletions
diff --git a/core/device.c b/core/device.c
index 76c2f84..f3ee63f 100644
--- a/core/device.c
+++ b/core/device.c
@@ -21,6 +21,7 @@
#include <libfdt/libfdt_internal.h>
#include <ccan/str/str.h>
#include <ccan/endian/endian.h>
+#include <inttypes.h>
/* Used to give unique handles. */
u32 last_phandle = 0;
@@ -155,6 +156,55 @@ struct dt_node *dt_new(struct dt_node *parent, const char *name)
return new;
}
+/*
+ * low level variant, we export this because there are "weird" address
+ * formats, such as LPC/ISA bus addresses which have a letter to identify
+ * which bus space the address is inside of.
+ */
+struct dt_node *__dt_find_by_name_addr(struct dt_node *parent, const char *name,
+ const char *addr)
+{
+ struct dt_node *node;
+
+ if (list_empty(&parent->children))
+ return NULL;
+
+ dt_for_each_child(parent, node) {
+ const char *unit = get_unitname(node);
+ int len;
+
+ if (!unit)
+ continue;
+
+ /* match the name */
+ len = (int) (unit - node->name) - 1;
+ if (strncmp(node->name, name, len))
+ continue;
+
+ /* match the unit */
+ if (strcmp(unit, addr) == 0)
+ return node;
+ }
+
+ dt_for_each_child(parent, node) {
+ struct dt_node *ret = __dt_find_by_name_addr(node, name, addr);
+
+ if (ret)
+ return ret;
+ }
+
+ return NULL;
+}
+
+struct dt_node *dt_find_by_name_addr(struct dt_node *parent, const char *name,
+ uint64_t addr)
+{
+ char addr_str[16 + 1]; /* max size of a 64bit int */
+ snprintf(addr_str, sizeof(addr_str), "%" PRIx64, addr);
+
+ return __dt_find_by_name_addr(parent, name, addr_str);
+}
+
struct dt_node *dt_new_addr(struct dt_node *parent, const char *name,
uint64_t addr)
{
diff --git a/core/test/run-device.c b/core/test/run-device.c
index e91e5a5..5939afc 100644
--- a/core/test/run-device.c
+++ b/core/test/run-device.c
@@ -150,6 +150,7 @@ int main(void)
assert(!list_top(&addr1->properties, struct dt_property, list));
check_path(addr1, "/addrs/addr@1337");
assert(dt_find_by_name(root, "addr@1337") == addr1);
+ assert(dt_find_by_name_addr(root, "addr", 0x1337) == addr1);
assert(dt_find_by_path(root, "/addrs/addr@1337") == addr1);
addr2 = dt_new_2addr(addrs, "2addr", 0xdead, 0xbeef);
diff --git a/include/device.h b/include/device.h
index 1ad403f..5155daa 100644
--- a/include/device.h
+++ b/include/device.h
@@ -247,4 +247,9 @@ u64 dt_translate_address(const struct dt_node *node, unsigned int index,
*/
int dt_cmp_subnodes(const struct dt_node *a, const struct dt_node *b);
+struct dt_node *__dt_find_by_name_addr(struct dt_node *parent, const char *name,
+ const char *addr);
+struct dt_node *dt_find_by_name_addr(struct dt_node *parent, const char *name,
+ uint64_t addr);
+
#endif /* __DEVICE_H */