|
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [PATCH 2/2] fdt: make fdt handling reusable across arch
This refactors reusable code from Arm's bootfdt.c and device-tree.h that is
general fdt handling code. The Kconfig parameter CORE_DEVICE_TREE is
introduced for when the ability of parsing DTB files is needed by a capability
such as hyperlaunch.
Signed-off-by: Daniel P. Smith <dpsmith@xxxxxxxxxxxxxxxxxxxx>
---
MAINTAINERS | 2 +
xen/arch/arm/bootfdt.c | 141 +------------------------------
xen/common/Kconfig | 4 +
xen/common/Makefile | 3 +-
xen/common/fdt.c | 153 ++++++++++++++++++++++++++++++++++
xen/include/xen/device_tree.h | 50 +----------
xen/include/xen/fdt.h | 79 ++++++++++++++++++
7 files changed, 242 insertions(+), 190 deletions(-)
create mode 100644 xen/common/fdt.c
create mode 100644 xen/include/xen/fdt.h
diff --git a/MAINTAINERS b/MAINTAINERS
index 694412a961..b7fc3ed805 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -303,7 +303,9 @@ F: xen/common/libfdt/
F: xen/common/device_tree.c
F: xen/include/xen/libfdt/
F: xen/include/xen/device_tree.h
+F: include/xen/fdt.h
F: xen/drivers/passthrough/device_tree.c
+F: common/fdt.c
ECLAIR
R: Simone Ballarin <simone.ballarin@xxxxxxxxxxx>
diff --git a/xen/arch/arm/bootfdt.c b/xen/arch/arm/bootfdt.c
index 2673ad17a1..cdf4f17789 100644
--- a/xen/arch/arm/bootfdt.c
+++ b/xen/arch/arm/bootfdt.c
@@ -12,79 +12,11 @@
#include <xen/device_tree.h>
#include <xen/lib.h>
#include <xen/libfdt/libfdt-xen.h>
+#include <xen/fdt.h>
#include <xen/sort.h>
#include <xsm/xsm.h>
#include <asm/setup.h>
-static bool __init device_tree_node_matches(const void *fdt, int node,
- const char *match)
-{
- const char *name;
- size_t match_len;
-
- name = fdt_get_name(fdt, node, NULL);
- match_len = strlen(match);
-
- /* Match both "match" and "match@..." patterns but not
- "match-foo". */
- return strncmp(name, match, match_len) == 0
- && (name[match_len] == '@' || name[match_len] == '\0');
-}
-
-static bool __init device_tree_node_compatible(const void *fdt, int node,
- const char *match)
-{
- int len, l;
- const void *prop;
-
- prop = fdt_getprop(fdt, node, "compatible", &len);
- if ( prop == NULL )
- return false;
-
- while ( len > 0 ) {
- if ( !dt_compat_cmp(prop, match) )
- return true;
- l = strlen(prop) + 1;
- prop += l;
- len -= l;
- }
-
- return false;
-}
-
-void __init device_tree_get_reg(const __be32 **cell, uint32_t address_cells,
- uint32_t size_cells, paddr_t *start,
- paddr_t *size)
-{
- uint64_t dt_start, dt_size;
-
- /*
- * dt_next_cell will return uint64_t whereas paddr_t may not be 64-bit.
- * Thus, there is an implicit cast from uint64_t to paddr_t.
- */
- dt_start = dt_next_cell(address_cells, cell);
- dt_size = dt_next_cell(size_cells, cell);
-
- if ( dt_start != (paddr_t)dt_start )
- {
- printk("Physical address greater than max width supported\n");
- WARN();
- }
-
- if ( dt_size != (paddr_t)dt_size )
- {
- printk("Physical size greater than max width supported\n");
- WARN();
- }
-
- /*
- * Xen will truncate the address/size if it is greater than the maximum
- * supported width and it will give an appropriate warning.
- */
- *start = dt_start;
- *size = dt_size;
-}
-
static int __init device_tree_get_meminfo(const void *fdt, int node,
const char *prop_name,
u32 address_cells, u32 size_cells,
@@ -135,77 +67,6 @@ static int __init device_tree_get_meminfo(const void *fdt,
int node,
return 0;
}
-u32 __init device_tree_get_u32(const void *fdt, int node,
- const char *prop_name, u32 dflt)
-{
- const struct fdt_property *prop;
-
- prop = fdt_get_property(fdt, node, prop_name, NULL);
- if ( !prop || prop->len < sizeof(u32) )
- return dflt;
-
- return fdt32_to_cpu(*(uint32_t*)prop->data);
-}
-
-/**
- * device_tree_for_each_node - iterate over all device tree sub-nodes
- * @fdt: flat device tree.
- * @node: parent node to start the search from
- * @func: function to call for each sub-node.
- * @data: data to pass to @func.
- *
- * Any nodes nested at DEVICE_TREE_MAX_DEPTH or deeper are ignored.
- *
- * Returns 0 if all nodes were iterated over successfully. If @func
- * returns a value different from 0, that value is returned immediately.
- */
-int __init device_tree_for_each_node(const void *fdt, int node,
- device_tree_node_func func,
- void *data)
-{
- /*
- * We only care about relative depth increments, assume depth of
- * node is 0 for simplicity.
- */
- int depth = 0;
- const int first_node = node;
- u32 address_cells[DEVICE_TREE_MAX_DEPTH];
- u32 size_cells[DEVICE_TREE_MAX_DEPTH];
- int ret;
-
- do {
- const char *name = fdt_get_name(fdt, node, NULL);
- u32 as, ss;
-
- if ( depth >= DEVICE_TREE_MAX_DEPTH )
- {
- printk("Warning: device tree node `%s' is nested too deep\n",
- name);
- continue;
- }
-
- as = depth > 0 ? address_cells[depth-1] :
DT_ROOT_NODE_ADDR_CELLS_DEFAULT;
- ss = depth > 0 ? size_cells[depth-1] : DT_ROOT_NODE_SIZE_CELLS_DEFAULT;
-
- address_cells[depth] = device_tree_get_u32(fdt, node,
- "#address-cells", as);
- size_cells[depth] = device_tree_get_u32(fdt, node,
- "#size-cells", ss);
-
- /* skip the first node */
- if ( node != first_node )
- {
- ret = func(fdt, node, name, depth, as, ss, data);
- if ( ret != 0 )
- return ret;
- }
-
- node = fdt_next_node(fdt, node, &depth);
- } while ( node >= 0 && depth > 0 );
-
- return 0;
-}
-
static int __init process_memory_node(const void *fdt, int node,
const char *name, int depth,
u32 address_cells, u32 size_cells,
diff --git a/xen/common/Kconfig b/xen/common/Kconfig
index 0d248ab941..e2fdb3cbc3 100644
--- a/xen/common/Kconfig
+++ b/xen/common/Kconfig
@@ -38,8 +38,12 @@ config HAS_ALTERNATIVE
config HAS_COMPAT
bool
+config CORE_DEVICE_TREE
+ bool
+
config HAS_DEVICE_TREE
bool
+ select CORE_DEVICE_TREE
config HAS_EX_TABLE
bool
diff --git a/xen/common/Makefile b/xen/common/Makefile
index 46049eac35..fd3769e1c6 100644
--- a/xen/common/Makefile
+++ b/xen/common/Makefile
@@ -11,6 +11,7 @@ obj-y += domain.o
obj-y += event_2l.o
obj-y += event_channel.o
obj-y += event_fifo.o
+obj-$(CONFIG_CORE_DEVICE_TREE) += fdt.o
obj-$(CONFIG_CRASH_DEBUG) += gdbstub.o
obj-$(CONFIG_GRANT_TABLE) += grant_table.o
obj-y += guestcopy.o
@@ -75,7 +76,7 @@ obj-y += sched/
obj-$(CONFIG_UBSAN) += ubsan/
obj-$(CONFIG_NEEDS_LIBELF) += libelf/
-obj-$(CONFIG_HAS_DEVICE_TREE) += libfdt/
+obj-$(CONFIG_CORE_DEVICE_TREE) += libfdt/
CONF_FILE := $(if $(patsubst
/%,,$(KCONFIG_CONFIG)),$(objtree)/)$(KCONFIG_CONFIG)
$(obj)/config.gz: $(CONF_FILE)
diff --git a/xen/common/fdt.c b/xen/common/fdt.c
new file mode 100644
index 0000000000..8d7acaaa43
--- /dev/null
+++ b/xen/common/fdt.c
@@ -0,0 +1,153 @@
+/*
+ * Flattened Device Tree
+ *
+ * Copyright (C) 2012-2014 Citrix Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <xen/fdt.h>
+#include <xen/init.h>
+#include <xen/lib.h>
+#include <xen/libfdt/libfdt.h>
+#include <xen/types.h>
+
+bool __init device_tree_node_matches(
+ const void *fdt, int node, const char *match)
+{
+ const char *name;
+ size_t match_len;
+
+ name = fdt_get_name(fdt, node, NULL);
+ match_len = strlen(match);
+
+ /* Match both "match" and "match@..." patterns but not
+ "match-foo". */
+ return strncmp(name, match, match_len) == 0
+ && (name[match_len] == '@' || name[match_len] == '\0');
+}
+
+bool __init device_tree_node_compatible(
+ const void *fdt, int node, const char *match)
+{
+ int len, l;
+ const void *prop;
+
+ prop = fdt_getprop(fdt, node, "compatible", &len);
+ if ( prop == NULL )
+ return false;
+
+ while ( len > 0 ) {
+ if ( !dt_compat_cmp(prop, match) )
+ return true;
+ l = strlen(prop) + 1;
+ prop += l;
+ len -= l;
+ }
+
+ return false;
+}
+
+void __init device_tree_get_reg(
+ const __be32 **cell, uint32_t address_cells, uint32_t size_cells,
+ paddr_t *start, paddr_t *size)
+{
+ uint64_t dt_start, dt_size;
+
+ /*
+ * dt_next_cell will return uint64_t whereas paddr_t may not be 64-bit.
+ * Thus, there is an implicit cast from uint64_t to paddr_t.
+ */
+ dt_start = dt_next_cell(address_cells, cell);
+ dt_size = dt_next_cell(size_cells, cell);
+
+ if ( dt_start != (paddr_t)dt_start )
+ {
+ printk("Physical address greater than max width supported\n");
+ WARN();
+ }
+
+ if ( dt_size != (paddr_t)dt_size )
+ {
+ printk("Physical size greater than max width supported\n");
+ WARN();
+ }
+
+ /*
+ * Xen will truncate the address/size if it is greater than the maximum
+ * supported width and it will give an appropriate warning.
+ */
+ *start = dt_start;
+ *size = dt_size;
+}
+
+u32 __init device_tree_get_u32(
+ const void *fdt, int node, const char *prop_name, u32 dflt)
+{
+ const struct fdt_property *prop;
+
+ prop = fdt_get_property(fdt, node, prop_name, NULL);
+ if ( !prop || prop->len < sizeof(u32) )
+ return dflt;
+
+ return fdt32_to_cpu(*(uint32_t*)prop->data);
+}
+
+/**
+ * device_tree_for_each_node - iterate over all device tree sub-nodes
+ * @fdt: flat device tree.
+ * @node: parent node to start the search from
+ * @func: function to call for each sub-node.
+ * @data: data to pass to @func.
+ *
+ * Any nodes nested at DEVICE_TREE_MAX_DEPTH or deeper are ignored.
+ *
+ * Returns 0 if all nodes were iterated over successfully. If @func
+ * returns a value different from 0, that value is returned immediately.
+ */
+int __init device_tree_for_each_node(
+ const void *fdt, int node, device_tree_node_func func, void *data)
+{
+ /*
+ * We only care about relative depth increments, assume depth of
+ * node is 0 for simplicity.
+ */
+ int depth = 0;
+ const int first_node = node;
+ u32 address_cells[DEVICE_TREE_MAX_DEPTH];
+ u32 size_cells[DEVICE_TREE_MAX_DEPTH];
+ int ret;
+
+ do {
+ const char *name = fdt_get_name(fdt, node, NULL);
+ u32 as, ss;
+
+ if ( depth >= DEVICE_TREE_MAX_DEPTH )
+ {
+ printk("Warning: device tree node `%s' is nested too deep\n",
+ name);
+ continue;
+ }
+
+ as = depth > 0 ? address_cells[depth-1] :
DT_ROOT_NODE_ADDR_CELLS_DEFAULT;
+ ss = depth > 0 ? size_cells[depth-1] : DT_ROOT_NODE_SIZE_CELLS_DEFAULT;
+
+ address_cells[depth] = device_tree_get_u32(fdt, node,
+ "#address-cells", as);
+ size_cells[depth] = device_tree_get_u32(fdt, node,
+ "#size-cells", ss);
+
+ /* skip the first node */
+ if ( node != first_node )
+ {
+ ret = func(fdt, node, name, depth, as, ss, data);
+ if ( ret != 0 )
+ return ret;
+ }
+
+ node = fdt_next_node(fdt, node, &depth);
+ } while ( node >= 0 && depth > 0 );
+
+ return 0;
+}
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
index c2eada7489..f59aa54423 100644
--- a/xen/include/xen/device_tree.h
+++ b/xen/include/xen/device_tree.h
@@ -14,13 +14,12 @@
#include <asm/device.h>
#include <public/xen.h>
#include <public/device_tree_defs.h>
+#include <xen/fdt.h>
#include <xen/kernel.h>
#include <xen/string.h>
#include <xen/types.h>
#include <xen/list.h>
-#define DEVICE_TREE_MAX_DEPTH 16
-
/*
* Struct used for matching a device
*/
@@ -159,17 +158,8 @@ struct dt_raw_irq {
u32 specifier[DT_MAX_IRQ_SPEC];
};
-typedef int (*device_tree_node_func)(const void *fdt,
- int node, const char *name, int depth,
- u32 address_cells, u32 size_cells,
- void *data);
-
extern const void *device_tree_flattened;
-int device_tree_for_each_node(const void *fdt, int node,
- device_tree_node_func func,
- void *data);
-
/**
* dt_unflatten_host_device_tree - Unflatten the host device tree
*
@@ -214,14 +204,6 @@ extern const struct dt_device_node
*dt_interrupt_controller;
struct dt_device_node *
dt_find_interrupt_controller(const struct dt_device_match *matches);
-#define dt_prop_cmp(s1, s2) strcmp((s1), (s2))
-#define dt_node_cmp(s1, s2) strcasecmp((s1), (s2))
-#define dt_compat_cmp(s1, s2) strcasecmp((s1), (s2))
-
-/* Default #address and #size cells */
-#define DT_ROOT_NODE_ADDR_CELLS_DEFAULT 2
-#define DT_ROOT_NODE_SIZE_CELLS_DEFAULT 1
-
#define dt_for_each_property_node(dn, pp) \
for ( pp = (dn)->properties; (pp) != NULL; pp = (pp)->next )
@@ -231,16 +213,6 @@ dt_find_interrupt_controller(const struct dt_device_match
*matches);
#define dt_for_each_child_node(dt, dn) \
for ( dn = (dt)->child; (dn) != NULL; dn = (dn)->sibling )
-/* Helper to read a big number; size is in cells (not bytes) */
-static inline u64 dt_read_number(const __be32 *cell, int size)
-{
- u64 r = 0;
-
- while ( size-- )
- r = (r << 32) | be32_to_cpu(*(cell++));
- return r;
-}
-
/* Wrapper for dt_read_number() to return paddr_t (instead of uint64_t) */
static inline paddr_t dt_read_paddr(const __be32 *cell, int size)
{
@@ -268,26 +240,6 @@ static inline paddr_t dt_read_paddr(const __be32 *cell,
int size)
return r;
}
-/* Helper to convert a number of cells to bytes */
-static inline int dt_cells_to_size(int size)
-{
- return (size * sizeof (u32));
-}
-
-/* Helper to convert a number of bytes to cells, rounds down */
-static inline int dt_size_to_cells(int bytes)
-{
- return (bytes / sizeof(u32));
-}
-
-static inline u64 dt_next_cell(int s, const __be32 **cellp)
-{
- const __be32 *p = *cellp;
-
- *cellp = p + s;
- return dt_read_number(p, s);
-}
-
static inline const char *dt_node_full_name(const struct dt_device_node *np)
{
return (np && np->full_name) ? np->full_name : "<no-node>";
diff --git a/xen/include/xen/fdt.h b/xen/include/xen/fdt.h
new file mode 100644
index 0000000000..00f9f3792f
--- /dev/null
+++ b/xen/include/xen/fdt.h
@@ -0,0 +1,79 @@
+/*
+ * Flattened Device Tree
+ *
+ * Copyright (C) 2012 Citrix Systems, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#ifndef __XEN_FDT_H__
+#define __XEN_FDT_H__
+
+#include <xen/init.h>
+#include <xen/libfdt/libfdt.h>
+#include <xen/types.h>
+
+#define DEVICE_TREE_MAX_DEPTH 16
+
+/* Default #address and #size cells */
+#define DT_ROOT_NODE_ADDR_CELLS_DEFAULT 2
+#define DT_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+
+#define dt_prop_cmp(s1, s2) strcmp((s1), (s2))
+#define dt_node_cmp(s1, s2) strcasecmp((s1), (s2))
+#define dt_compat_cmp(s1, s2) strcasecmp((s1), (s2))
+
+/* Helper to read a big number; size is in cells (not bytes) */
+static inline u64 dt_read_number(const __be32 *cell, int size)
+{
+ u64 r = 0;
+
+ while ( size-- )
+ r = (r << 32) | be32_to_cpu(*(cell++));
+ return r;
+}
+
+/* Helper to convert a number of cells to bytes */
+static inline int dt_cells_to_size(int size)
+{
+ return (size * sizeof (u32));
+}
+
+/* Helper to convert a number of bytes to cells, rounds down */
+static inline int dt_size_to_cells(int bytes)
+{
+ return (bytes / sizeof(u32));
+}
+
+static inline u64 dt_next_cell(int s, const __be32 **cellp)
+{
+ const __be32 *p = *cellp;
+
+ *cellp = p + s;
+ return dt_read_number(p, s);
+}
+
+
+bool __init device_tree_node_matches(
+ const void *fdt, int node, const char *match);
+
+bool __init device_tree_node_compatible(
+ const void *fdt, int node, const char *match);
+
+void __init device_tree_get_reg(
+ const __be32 **cell, u32 address_cells, u32 size_cells, u64 *start,
+ u64 *size);
+
+u32 __init device_tree_get_u32(
+ const void *fdt, int node, const char *prop_name, u32 dflt);
+
+typedef int (*device_tree_node_func)(
+ const void *fdt, int node, const char *name, int depth, u32 address_cells,
+ u32 size_cells, void *data);
+
+int device_tree_for_each_node(
+ const void *fdt, int node, device_tree_node_func func, void *data);
+
+
+#endif /* __XEN_FDT_H__ */
--
2.20.1
|
![]() |
Lists.xenproject.org is hosted with RackSpace, monitoring our |