diff mbox

[RFC,08/29] xen/arm: Add helpers to use the device tree

Message ID cfa7e0edf584f30c5eb9244553f3f470e68714e7.1367188423.git.julien.grall@linaro.org
State Changes Requested, archived
Headers show

Commit Message

Julien Grall April 28, 2013, 11:01 p.m. UTC
Signed-off-by: Julien Grall <julien.grall@linaro.org>
---
 xen/common/device_tree.c      |  120 +++++++++++++++++++++++++++++++++++++++++
 xen/include/xen/device_tree.h |  120 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 240 insertions(+)

Comments

Ian Campbell April 29, 2013, 3:23 p.m. UTC | #1
On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:

Are these also from Linux?

> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> ---
>  xen/common/device_tree.c      |  120 +++++++++++++++++++++++++++++++++++++++++
>  xen/include/xen/device_tree.h |  120 +++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 240 insertions(+)
> 
> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
> index 05285b7..dd4b813 100644
> --- a/xen/common/device_tree.c
> +++ b/xen/common/device_tree.c
> @@ -573,6 +573,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 )

We have functions which do this already, don't we? Also things like
dt_node_cmp, dt_read_number etc have analogues in the current code.

If these are from Linux I'm inclined to believe they will be better than
our own. For 4.4 we should look at removing our variants.

Or maybe if I keep reading the series I will find them going away
already?

Ian
Julien Grall April 29, 2013, 3:40 p.m. UTC | #2
On 04/29/2013 04:23 PM, Ian Campbell wrote:

> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:
> 
> Are these also from Linux?
> 
>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
>> ---
>>  xen/common/device_tree.c      |  120 +++++++++++++++++++++++++++++++++++++++++
>>  xen/include/xen/device_tree.h |  120 +++++++++++++++++++++++++++++++++++++++++
>>  2 files changed, 240 insertions(+)
>>
>> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
>> index 05285b7..dd4b813 100644
>> --- a/xen/common/device_tree.c
>> +++ b/xen/common/device_tree.c
>> @@ -573,6 +573,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 )
> 
> We have functions which do this already, don't we? Also things like
> dt_node_cmp, dt_read_number etc have analogues in the current code.
> 
> If these are from Linux I'm inclined to believe they will be better than
> our own. For 4.4 we should look at removing our variants.
> 
> Or maybe if I keep reading the series I will find them going away
> already?


In fact it's exactly the same, except the current function deals with
flat device tree and the new one deals with the hierarchical device tree.

I'm afraid we can't remove this duplicate code, we still need it for
early scan of the device tree to retrieve memory, cpus, and modules
informations.

Once all the xen code moved to the new device tree API. This function
will be static.
Ian Campbell April 29, 2013, 4:55 p.m. UTC | #3
On Mon, 2013-04-29 at 16:40 +0100, Julien Grall wrote:
> On 04/29/2013 04:23 PM, Ian Campbell wrote:
> 
> > On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:
> > 
> > Are these also from Linux?
> > 
> >> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> >> ---
> >>  xen/common/device_tree.c      |  120 +++++++++++++++++++++++++++++++++++++++++
> >>  xen/include/xen/device_tree.h |  120 +++++++++++++++++++++++++++++++++++++++++
> >>  2 files changed, 240 insertions(+)
> >>
> >> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
> >> index 05285b7..dd4b813 100644
> >> --- a/xen/common/device_tree.c
> >> +++ b/xen/common/device_tree.c
> >> @@ -573,6 +573,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 )
> > 
> > We have functions which do this already, don't we? Also things like
> > dt_node_cmp, dt_read_number etc have analogues in the current code.
> > 
> > If these are from Linux I'm inclined to believe they will be better than
> > our own. For 4.4 we should look at removing our variants.
> > 
> > Or maybe if I keep reading the series I will find them going away
> > already?
> 
> 
> In fact it's exactly the same, except the current function deals with
> flat device tree and the new one deals with the hierarchical device tree.
> 
> I'm afraid we can't remove this duplicate code, we still need it for
> early scan of the device tree to retrieve memory, cpus, and modules
> informations.

We can't use dt_compat_cmp in the early code?

> 
> Once all the xen code moved to the new device tree API. This function
> will be static.
>
Julien Grall April 29, 2013, 6:23 p.m. UTC | #4
On 04/29/2013 05:55 PM, Ian Campbell wrote:

> On Mon, 2013-04-29 at 16:40 +0100, Julien Grall wrote:
>> On 04/29/2013 04:23 PM, Ian Campbell wrote:
>>
>>> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:
>>>
>>> Are these also from Linux?
>>>
>>>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
>>>> ---
>>>>  xen/common/device_tree.c      |  120 +++++++++++++++++++++++++++++++++++++++++
>>>>  xen/include/xen/device_tree.h |  120 +++++++++++++++++++++++++++++++++++++++++
>>>>  2 files changed, 240 insertions(+)
>>>>
>>>> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
>>>> index 05285b7..dd4b813 100644
>>>> --- a/xen/common/device_tree.c
>>>> +++ b/xen/common/device_tree.c
>>>> @@ -573,6 +573,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 )
>>>
>>> We have functions which do this already, don't we? Also things like
>>> dt_node_cmp, dt_read_number etc have analogues in the current code.
>>>
>>> If these are from Linux I'm inclined to believe they will be better than
>>> our own. For 4.4 we should look at removing our variants.
>>>
>>> Or maybe if I keep reading the series I will find them going away
>>> already?
>>
>>
>> In fact it's exactly the same, except the current function deals with
>> flat device tree and the new one deals with the hierarchical device tree.
>>
>> I'm afraid we can't remove this duplicate code, we still need it for
>> early scan of the device tree to retrieve memory, cpus, and modules
>> informations.
> 
> We can't use dt_compat_cmp in the early code?

Oh right, I though you were talking about dt_device_is_compatible and
device_tree_node_compatible.
Ian Campbell April 30, 2013, 9:22 a.m. UTC | #5
On Mon, 2013-04-29 at 19:23 +0100, Julien Grall wrote:
> On 04/29/2013 05:55 PM, Ian Campbell wrote:
> 
> > On Mon, 2013-04-29 at 16:40 +0100, Julien Grall wrote:
> >> On 04/29/2013 04:23 PM, Ian Campbell wrote:
> >>
> >>> On Mon, 2013-04-29 at 00:01 +0100, Julien Grall wrote:
> >>>
> >>> Are these also from Linux?
> >>>
> >>>> Signed-off-by: Julien Grall <julien.grall@linaro.org>
> >>>> ---
> >>>>  xen/common/device_tree.c      |  120 +++++++++++++++++++++++++++++++++++++++++
> >>>>  xen/include/xen/device_tree.h |  120 +++++++++++++++++++++++++++++++++++++++++
> >>>>  2 files changed, 240 insertions(+)
> >>>>
> >>>> diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
> >>>> index 05285b7..dd4b813 100644
> >>>> --- a/xen/common/device_tree.c
> >>>> +++ b/xen/common/device_tree.c
> >>>> @@ -573,6 +573,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 )
> >>>
> >>> We have functions which do this already, don't we? Also things like
> >>> dt_node_cmp, dt_read_number etc have analogues in the current code.
> >>>
> >>> If these are from Linux I'm inclined to believe they will be better than
> >>> our own. For 4.4 we should look at removing our variants.
> >>>
> >>> Or maybe if I keep reading the series I will find them going away
> >>> already?
> >>
> >>
> >> In fact it's exactly the same, except the current function deals with
> >> flat device tree and the new one deals with the hierarchical device tree.
> >>
> >> I'm afraid we can't remove this duplicate code, we still need it for
> >> early scan of the device tree to retrieve memory, cpus, and modules
> >> informations.
> > 
> > We can't use dt_compat_cmp in the early code?
> 
> Oh right, I though you were talking about dt_device_is_compatible and
> device_tree_node_compatible.

Sorry I wasn't very clear there...

Ian.
diff mbox

Patch

diff --git a/xen/common/device_tree.c b/xen/common/device_tree.c
index 05285b7..dd4b813 100644
--- a/xen/common/device_tree.c
+++ b/xen/common/device_tree.c
@@ -573,6 +573,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 +632,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 850a9bd..9637652 100644
--- a/xen/include/xen/device_tree.h
+++ b/xen/include/xen/device_tree.h
@@ -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