[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH V3 15/41] xen/arm: Add helpers to use the device tree



Signed-off-by: Julien Grall <julien.grall@xxxxxxxxxx>

Changes in v3:
    - Allow to use "old" functions only in init code

Changes in v2:
    - Use dt_node_cmp and dt_compat_cmp in early device tree code
---
 xen/common/device_tree.c      |  162 ++++++++++++++++++++++++++++++++++++-----
 xen/include/xen/device_tree.h |  155 +++++++++++++++++++++++++++++++++++----
 2 files changed, 283 insertions(+), 34 deletions(-)

diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index 6d55a02..c731105 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -80,7 +80,8 @@ static void dt_printk(const char *fmt, ...)
 # define dt_dprintk(fmt, args...) do {} while ( 0 )
 #endif
 
-bool_t device_tree_node_matches(const void *fdt, int node, const char *match)
+bool_t __init device_tree_node_matches(const void *fdt, int node,
+                                       const char *match)
 {
     const char *name;
     size_t match_len;
@@ -94,7 +95,8 @@ bool_t device_tree_node_matches(const void *fdt, int node, 
const char *match)
         && (name[match_len] == '@' || name[match_len] == '\0');
 }
 
-bool_t device_tree_type_matches(const void *fdt, int node, const char *match)
+bool_t __init device_tree_type_matches(const void *fdt, int node,
+                                       const char *match)
 {
     const void *prop;
 
@@ -102,20 +104,24 @@ bool_t device_tree_type_matches(const void *fdt, int 
node, const char *match)
     if ( prop == NULL )
         return 0;
 
-    return !strcmp(prop, match);
+    return !dt_node_cmp(prop, match);
 }
 
-bool_t device_tree_node_compatible(const void *fdt, int node, const char 
*match)
+bool_t __init device_tree_node_compatible(const void *fdt, int node,
+                                          const char *match)
 {
     int len, l;
+    int mlen;
     const void *prop;
 
+    mlen = strlen(match);
+
     prop = fdt_getprop(fdt, node, "compatible", &len);
     if ( prop == NULL )
         return 0;
 
     while ( len > 0 ) {
-        if ( !strcmp(prop, match) )
+        if ( !dt_compat_cmp(prop, match, mlen) )
             return 1;
         l = strlen(prop) + 1;
         prop += l;
@@ -125,7 +131,7 @@ bool_t device_tree_node_compatible(const void *fdt, int 
node, const char *match)
     return 0;
 }
 
-static int device_tree_nr_reg_ranges(const struct fdt_property *prop,
+static __init int device_tree_nr_reg_ranges(const struct fdt_property *prop,
         u32 address_cells, u32 size_cells)
 {
     u32 reg_cells = address_cells + size_cells;
@@ -146,14 +152,14 @@ static void __init get_val(const u32 **cell, u32 cells, 
u64 *val)
     }
 }
 
-void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells,
-                         u64 *start, u64 *size)
+void __init device_tree_get_reg(const u32 **cell, u32 address_cells,
+                                u32 size_cells, u64 *start, u64 *size)
 {
     get_val(cell, address_cells, start);
     get_val(cell, size_cells, size);
 }
 
-static void set_val(u32 **cell, u32 cells, u64 val)
+static void __init set_val(u32 **cell, u32 cells, u64 val)
 {
     u32 c = cells;
 
@@ -165,15 +171,15 @@ static void set_val(u32 **cell, u32 cells, u64 val)
     (*cell) += cells;
 }
 
-void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells,
-                         u64 start, u64 size)
+void __init device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells,
+                                u64 start, u64 size)
 {
     set_val(cell, address_cells, start);
     set_val(cell, size_cells, size);
 }
 
-u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name,
-                        u32 dflt)
+u32 __init device_tree_get_u32(const void *fdt, int node, const char 
*prop_name,
+                               u32 dflt)
 {
     const struct fdt_property *prop;
 
@@ -195,8 +201,8 @@ u32 device_tree_get_u32(const void *fdt, int node, const 
char *prop_name,
  * Returns 0 if all nodes were iterated over successfully.  If @func
  * returns a value different from 0, that value is returned immediately.
  */
-int device_tree_for_each_node(const void *fdt,
-                              device_tree_node_func func, void *data)
+int __init device_tree_for_each_node(const void *fdt,
+                                     device_tree_node_func func, void *data)
 {
     int node;
     int depth;
@@ -262,8 +268,8 @@ static int _find_compatible_node(const void *fdt,
     return 0;
 }
 
-int find_compatible_node(const char *compatible, int *node, int *depth,
-                u32 *address_cells, u32 *size_cells)
+int __init find_compatible_node(const char *compatible, int *node, int *depth,
+                                u32 *address_cells, u32 *size_cells)
 {
     int ret;
     struct find_compat c;
@@ -335,7 +341,7 @@ static int dump_node(const void *fdt, int node, const char 
*name, int depth,
  * device_tree_dump - print a text representation of a device tree
  * @fdt: flat device tree to print
  */
-void device_tree_dump(const void *fdt)
+void __init device_tree_dump(const void *fdt)
 {
     device_tree_for_each_node(fdt, dump_node, NULL);
 }
@@ -587,6 +593,54 @@ const void *dt_get_property(const struct dt_device_node 
*np,
     return pp ? pp->value : NULL;
 }
 
+bool_t dt_device_is_compatible(const struct dt_device_node *device,
+                               const char *compat)
+{
+    const char* cp;
+    u32 cplen, l;
+
+    cp = dt_get_property(device, "compatible", &cplen);
+    if ( cp == NULL )
+        return 0;
+    while ( cplen > 0 )
+    {
+        if ( dt_compat_cmp(cp, compat, strlen(compat)) == 0 )
+            return 1;
+        l = strlen(cp) + 1;
+        cp += l;
+        cplen -= l;
+    }
+
+    return 0;
+}
+
+bool_t dt_machine_is_compatible(const char *compat)
+{
+    const struct dt_device_node *root;
+    bool_t rc = 0;
+
+    root = dt_find_node_by_path("/");
+    if ( root )
+    {
+        rc = dt_device_is_compatible(root, compat);
+    }
+    return rc;
+}
+
+struct dt_device_node *dt_find_node_by_name(struct dt_device_node *from,
+                                            const char *name)
+{
+    struct dt_device_node *np;
+    struct dt_device_node *dt;
+
+    dt = from ? from->allnext : dt_host;
+    for_each_device_node(dt, np)
+        if ( np->name && (dt_node_cmp(np->name, name) == 0) )
+            break;
+
+    return np;
+}
+
 struct dt_device_node *dt_find_node_by_path(const char *path)
 {
     struct dt_device_node *np;
@@ -598,6 +652,78 @@ struct dt_device_node *dt_find_node_by_path(const char 
*path)
     return np;
 }
 
+struct dt_device_node *dt_find_node_by_alias(const char *alias)
+{
+    const struct dt_alias_prop *app;
+
+    list_for_each_entry( app, &aliases_lookup, link )
+    {
+        if ( !strcmp(app->alias, alias) )
+            return app->np;
+    }
+
+    return NULL;
+}
+
+const struct dt_device_node *dt_get_parent(const struct dt_device_node *node)
+{
+    if ( !node )
+        return NULL;
+
+    return node->parent;
+}
+
+struct dt_device_node *
+dt_find_compatible_node(struct dt_device_node *from,
+                        const char *type,
+                        const char *compatible)
+{
+    struct dt_device_node *np;
+    struct dt_device_node *dt;
+
+    dt = from ? from->allnext : dt_host;
+    for_each_device_node(dt, np)
+    {
+        if ( type
+             && !(np->type && (dt_node_cmp(np->type, type) == 0)) )
+            continue;
+        if ( dt_device_is_compatible(np, compatible) )
+            break;
+    }
+
+    return np;
+}
+
+int dt_n_addr_cells(const struct dt_device_node *np)
+{
+    const __be32 *ip;
+
+    do {
+        if ( np->parent )
+            np = np->parent;
+        ip = dt_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 DT_ROOT_NODE_ADDR_CELLS_DEFAULT;
+}
+
+int dt_n_size_cells(const struct dt_device_node *np)
+{
+    const __be32 *ip;
+
+    do {
+        if ( np->parent )
+            np = np->parent;
+        ip = dt_get_property(np, "#size-cells", NULL);
+        if ( ip )
+            return be32_to_cpup(ip);
+    } while ( np->parent );
+    /* No #address-cells property for the root node */
+    return DT_ROOT_NODE_SIZE_CELLS_DEFAULT;
+}
+
 /**
  * unflatten_dt_node - Alloc and populate a device_node from the flat tree
  * @fdt: The parent device tree blob
diff --git a/xen/include/xen/device_tree.h b/xen/include/xen/device_tree.h
index 015b808..7a6adc7 100644
--- a/xen/include/xen/device_tree.h
+++ b/xen/include/xen/device_tree.h
@@ -107,22 +107,25 @@ typedef int (*device_tree_node_func)(const void *fdt,
 extern struct dt_early_info early_info;
 extern void *device_tree_flattened;
 
-size_t device_tree_early_init(const void *fdt);
-
-void device_tree_get_reg(const u32 **cell, u32 address_cells, u32 size_cells,
-                         u64 *start, u64 *size);
-void device_tree_set_reg(u32 **cell, u32 address_cells, u32 size_cells,
-                         u64 start, u64 size);
-u32 device_tree_get_u32(const void *fdt, int node, const char *prop_name,
-                       u32 dflt);
-bool_t device_tree_node_matches(const void *fdt, int node, const char *match);
-bool_t device_tree_node_compatible(const void *fdt, int node, const char 
*match);
-int find_compatible_node(const char *compatible, int *node, int *depth,
-                u32 *address_cells, u32 *size_cells);
-int device_tree_for_each_node(const void *fdt,
-                              device_tree_node_func func, void *data);
-const char *device_tree_bootargs(const void *fdt);
-void device_tree_dump(const void *fdt);
+size_t __init device_tree_early_init(const void *fdt);
+
+void __init device_tree_get_reg(const u32 **cell, u32 address_cells,
+                                u32 size_cells,
+                                u64 *start, u64 *size);
+void __init device_tree_set_reg(u32 **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);
+bool_t __init device_tree_node_matches(const void *fdt, int node,
+                                       const char *match);
+bool_t __init device_tree_node_compatible(const void *fdt, int node,
+                                          const char *match);
+int __init find_compatible_node(const char *compatible, int *node, int *depth,
+                                u32 *address_cells, u32 *size_cells);
+int __init device_tree_for_each_node(const void *fdt,
+                                     device_tree_node_func func, void *data);
+const char __init *device_tree_bootargs(const void *fdt);
+void __init device_tree_dump(const void *fdt);
 
 /**
  * dt_unflatten_host_device_tree - Unflatten the host device tree
@@ -141,17 +144,72 @@ extern struct dt_device_node *dt_host;
 #define dt_node_cmp(s1, s2) strcmp((s1), (s2))
 #define dt_compat_cmp(s1, s2, l) strnicmp((s1), (s2), l)
 
+/* Default #address and #size cells */
+#define DT_ROOT_NODE_ADDR_CELLS_DEFAULT 1
+#define DT_ROOT_NODE_SIZE_CELLS_DEFAULT 1
+
 #define for_each_property_of_node(dn, pp)                   \
     for ( pp = dn->properties; pp != NULL; pp = pp->next )
 
 #define for_each_device_node(dt, dn)                         \
     for ( dn = dt; dn != NULL; dn = dn->allnext )
 
+/* 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;
+}
+
 static inline const char *dt_node_full_name(const struct dt_device_node *np)
 {
     return (np && np->full_name) ? np->full_name : "<no-node>";
 }
 
+static inline const char *dt_node_name(const struct dt_device_node *np)
+{
+    return (np && np->name) ? np->name : "<no-node>";
+}
+
+static inline bool_t
+dt_device_type_is_equal(const struct dt_device_node *device,
+                        const char *type)
+{
+    return !dt_node_cmp(device->type, type);
+}
+
+static inline void dt_device_set_used_by(struct dt_device_node *device,
+                                         domid_t used_by)
+{
+    /* TODO: children must inherit to the used_by thing */
+    device->used_by = used_by;
+}
+
+static inline domid_t dt_device_used_by(const struct dt_device_node *device)
+{
+    return device->used_by;
+}
+
+/**
+ * dt_find_compatible_node - Find a node based on type and one of the
+ *                           tokens in its "compatible" property
+ * @from: The node to start searching from or NULL, the node
+ *          you pass will not be searched, only the next one
+ *          will; typically, you pass what the previous call
+ *          returned.
+ * @type: The type string to match "device_type" or NULL to ignore
+ * @compatible: The string to match to one of the tokens in the device
+ *          "compatible" list.
+ *
+ * Returns a node pointer.
+ */
+struct dt_device_node *dt_find_compatible_node(struct dt_device_node *from,
+                                               const char *type,
+                                               const char *compatible);
+
 /**
  * Find a property with a given name for a given node
  * and return the value.
@@ -160,10 +218,75 @@ const void *dt_get_property(const struct dt_device_node 
*np,
                             const char *name, u32 *lenp);
 
 /**
+ * Checks if the given "compat" string matches one of the strings in
+ * the device's "compatible" property
+ */
+bool_t dt_device_is_compatible(const struct dt_device_node *device,
+                               const char *compat);
+
+/**
+ * dt_machine_is_compatible - Test root of device tree for a given compatible 
value
+ * @compat: compatible string to look for in root node's compatible property.
+ *
+ * Returns true if the root node has the given value in its
+ * compatible property.
+ */
+bool_t dt_machine_is_compatible(const char *compat);
+
+/**
+ * dt_find_node_by_name - Find a node by its "name" property
+ * @from: The node to start searching from or NULL, the node
+ * you pass will not be searched, only the next one
+ *  will; typically, you pass what the previous call
+ *  returned. of_node_put() will be called on it
+ * @name: The name string to match against
+ *
+ * Returns a node pointer with refcount incremented, use
+ * of_node_put() on it when done.
+ */
+struct dt_device_node *dt_find_node_by_name(struct dt_device_node *node,
+                                            const char *name);
+
+/**
+ * df_find_node_by_alias - Find a node matching an alias
+ * @alias: The alias to match
+ *
+ * Returns a node pointer.
+ */
+struct dt_device_node *dt_find_node_by_alias(const char *alias);
+
+/**
  * dt_find_node_by_path - Find a node matching a full DT path
  * @path: The full path to match
  *
  * Returns a node pointer.
  */
 struct dt_device_node *dt_find_node_by_path(const char *path);
+
+/**
+ * dt_get_parent - Get a node's parent if any
+ * @node: Node to get parent
+ *
+ * Returns a node pointer.
+ */
+const struct dt_device_node *dt_get_parent(const struct dt_device_node *node);
+
+/**
+ * dt_n_size_cells - Helper to retrieve the number of cell for the size
+ * @np: node to get the value
+ *
+ * This function retrieves for a give device-tree node the number of
+ * cell for the size field.
+ */
+int dt_n_size_cells(const struct dt_device_node *np);
+
+/**
+ * dt_n_addr_cells - Helper to retrieve the number of cell for the address
+ * @np: node to get the value
+ *
+ * This function retrieves for a give device-tree node the number of
+ * cell for the address field.
+ */
+int dt_n_addr_cells(const struct dt_device_node *np);
+
 #endif
-- 
1.7.10.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.