@@ -88,20 +88,23 @@ 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)
{
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;
@@ -573,6 +576,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;
@@ -584,6 +635,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
@@ -150,17 +150,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.
@@ -169,10 +224,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
Signed-off-by: Julien Grall <julien.grall@linaro.org> Changes in v2: - use dt_node_cmp and dt_compat_cmp in early device tree code --- xen/common/device_tree.c | 127 ++++++++++++++++++++++++++++++++++++++++- xen/include/xen/device_tree.h | 120 ++++++++++++++++++++++++++++++++++++++ 2 files changed, 245 insertions(+), 2 deletions(-)