Re: [PATCH] Patch to improve device tree structure

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

 




On Sun, Nov 23, 2014 at 5:22 PM, Gaurav Minocha
<gaurav.minocha.os@xxxxxxxxx> wrote:
> On Tue, Nov 18, 2014 at 7:10 AM, Grant Likely <grant.likely@xxxxxxxxxx> wrote:
>> On Sun, 16 Nov 2014 20:52:56 -0800
>> , Gaurav Minocha <gaurav.minocha.os@xxxxxxxxx>
>>  wrote:
>>> This patch improves the implementation of device tree structure.
>>>
>>> Traditional child and sibling linked list in device tree structure
>>> is removed and is replaced by list_head (i.e. circular doubly linked
>>>  list) already available in Linux kernel.
>>>
>>> Signed-off-by: Gaurav Minocha <gaurav.minocha.os@xxxxxxxxx>
>>
>> Hi Gaurav,
>>
>> So, after you've done this work, I need to you rebase it (and of course
>> it is non-trivial) onto linux-next. I've already got a patch queued up
>> which gets rid of the of_allnodes/allnext list which will have conflicts
>> with this patch.
>>
>
> I am using http://git.kernel.org/pub/scm/linux/kernel/git/glikely/linux.git
> There is no branch linux-next in it. Also, I believe http://git.secretlab.ca/
> is not up yet. Please correct.
>

My bad! I can see your commits present in the next branch. I will send you a
revised patch soon. Thanks!

>> I'll make comments below where still relevant.
>>
>>> ---
>>>  drivers/of/base.c     |  36 ++++++++++----
>>>  drivers/of/dynamic.c  |  18 ++-----
>>>  drivers/of/fdt.c      |   7 ++-
>>>  drivers/of/selftest.c | 130 +++++++++++++++++++++++---------------------------
>>>  include/linux/of.h    |   4 +-
>>>  5 files changed, 97 insertions(+), 98 deletions(-)
>>>
>>> diff --git a/drivers/of/base.c b/drivers/of/base.c
>>> index 2305dc0..7acaeca 100644
>>> --- a/drivers/of/base.c
>>> +++ b/drivers/of/base.c
>>> @@ -603,16 +603,25 @@ EXPORT_SYMBOL(of_get_next_parent);
>>>  static struct device_node *__of_get_next_child(const struct device_node *node,
>>>                                               struct device_node *prev)
>>>  {
>>> -     struct device_node *next;
>>> +     struct device_node *next = NULL, *np;
>>> +     struct list_head *pos;
>>> +     int found = 0;
>>>
>>>       if (!node)
>>>               return NULL;
>>>
>>> -     next = prev ? prev->sibling : node->child;
>>> -     for (; next; next = next->sibling)
>>> -             if (of_node_get(next))
>>> -                     break;
>>> +     // move through the children list, and find the next node
>>> +     list_for_each(pos, &node->children) {
>>> +             np = list_entry(pos, struct device_node, siblings);
>>> +             if ((!prev || (found == 1)) && of_node_get(np)) {
>>> +                             next = np;
>>> +                             break;
>>> +             }
>>> +             if (prev && strcmp(np->full_name, prev->full_name) == 0)
>>> +                     found = 1;
>>
>> What is this 'found' stuff about? Why is this in the loop?
>
> I think with your suggestions below, it will definitely change.
>
> Considering the fact that it is a doubly linked list. First, I try to locate
> the pre node in the list. If found, then only I call of_node_get() on the next
> node, and if successful I break. I used found in the loop so that I do not
> have to manually check the next node is head or not.
>
> I can follow another approach, by directly getting the next entry and
> failing it if it is the head node.
>
>>
>>> +     }
>>>       of_node_put(prev);
>>
>> Most of this code can be eliminated by using list_for_each_entry().
>> Actually, the use of a loop here in the original code is a little bit
>> goofy simply because it never actually loops. It always exits on the
>> first iteration, but it does conveniently calculate the next entry in
>> the list. The thing to do here is take inspiration from the
>> list_for_each_entry() implementation and do the following:
>>
>>         if (!prev) {
>>                 next = list_first_entry_or_null(&node->children, struct device_node, siblings);
>>         } else if (prev->siblings.next != &node->children)
>>                 next = list_next_entry(prev, siblings);
>>         } else {
>>                 next = NULL;
>>         }
>>
>>> +
>>>       return next;
>>>  }
>>>  #define __for_each_child_of_node(parent, child) \
>>> @@ -651,22 +660,29 @@ EXPORT_SYMBOL(of_get_next_child);
>>>  struct device_node *of_get_next_available_child(const struct device_node *node,
>>>       struct device_node *prev)
>>>  {
>>> -     struct device_node *next;
>>> +     struct device_node *next = NULL, *np;
>>> +     struct list_head *pos;
>>>       unsigned long flags;
>>> +     int found = 0;
>>>
>>>       if (!node)
>>>               return NULL;
>>>
>>>       raw_spin_lock_irqsave(&devtree_lock, flags);
>>> -     next = prev ? prev->sibling : node->child;
>>> -     for (; next; next = next->sibling) {
>>> -             if (!__of_device_is_available(next))
>>> +     list_for_each(pos, &node->children) {
>>
>> Use list_for_each_entry_continue(), but there will be a bit of fiddling
>> to make sure the first entry in the list is handled correctly. You can
>> handle this by using list_entry on the &node->children list, but be
>> careful to never actually dereference that pointer.
>>
>>> +             np = list_entry(pos, struct device_node, siblings);
>>> +             if (!__of_device_is_available(np))
>>>                       continue;
>>> -             if (of_node_get(next))
>>> +             if ((!prev || (found == 1)) && of_node_get(np)) {
>>> +                     next = np;
>>>                       break;
>>> +             }
>>> +             if (prev && strcmp(np->full_name, prev->full_name) == 0)
>>> +                     found = 1;
>>>       }
>>>       of_node_put(prev);
>>>       raw_spin_unlock_irqrestore(&devtree_lock, flags);
>>> +
>>>       return next;
>>>  }
>>>  EXPORT_SYMBOL(of_get_next_available_child);
>>> diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
>>> index f297891..3ffc726 100644
>>> --- a/drivers/of/dynamic.c
>>> +++ b/drivers/of/dynamic.c
>>> @@ -115,11 +115,12 @@ void __of_attach_node(struct device_node *np)
>>>               phandle = __of_get_property(np, "ibm,phandle", &sz);
>>>       np->phandle = (phandle && (sz >= 4)) ? be32_to_cpup(phandle) : 0;
>>>
>>> -     np->child = NULL;
>>> -     np->sibling = np->parent->child;
>>> +     INIT_LIST_HEAD(&np->siblings);
>>> +     INIT_LIST_HEAD(&np->children);
>>> +     list_add_tail(&(np->siblings), &(np->parent->children));
>>> +
>>>       np->allnext = np->parent->allnext;
>>>       np->parent->allnext = np;
>>> -     np->parent->child = np;
>>>       of_node_clear_flag(np, OF_DETACHED);
>>>  }
>>>
>>> @@ -165,16 +166,7 @@ void __of_detach_node(struct device_node *np)
>>>               prev->allnext = np->allnext;
>>>       }
>>>
>>> -     if (parent->child == np)
>>> -             parent->child = np->sibling;
>>> -     else {
>>> -             struct device_node *prevsib;
>>> -             for (prevsib = np->parent->child;
>>> -                  prevsib->sibling != np;
>>> -                  prevsib = prevsib->sibling)
>>> -                     ;
>>> -             prevsib->sibling = np->sibling;
>>> -     }
>>> +     list_del(&np->siblings);
>>>
>>>       of_node_set_flag(np, OF_DETACHED);
>>>  }
>>> diff --git a/drivers/of/fdt.c b/drivers/of/fdt.c
>>> index d1ffca8..4cf2356 100644
>>> --- a/drivers/of/fdt.c
>>> +++ b/drivers/of/fdt.c
>>> @@ -224,13 +224,12 @@ static void * unflatten_dt_node(void *blob,
>>>               prev_pp = &np->properties;
>>>               **allnextpp = np;
>>>               *allnextpp = &np->allnext;
>>> +             INIT_LIST_HEAD(&np->siblings);
>>> +             INIT_LIST_HEAD(&np->children);
>>>               if (dad != NULL) {
>>>                       np->parent = dad;
>>>                       /* we temporarily use the next field as `last_child'*/
>>> -                     if (dad->next == NULL)
>>> -                             dad->child = np;
>>> -                     else
>>> -                             dad->next->sibling = np;
>>> +                     list_add_tail(&(np->siblings), &(dad->children));
>>>                       dad->next = np;
>>>               }
>>>       }
>>> diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
>>> index 7800127..8ec8a22 100644
>>> --- a/drivers/of/selftest.c
>>> +++ b/drivers/of/selftest.c
>>> @@ -25,10 +25,11 @@ static struct selftest_results {
>>>       int failed;
>>>  } selftest_results;
>>>
>>> -#define NO_OF_NODES 3
>>> -static struct device_node *nodes[NO_OF_NODES];
>>> -static int last_node_index;
>>> +#define MAX_NODES 50
>>> +
>>> +static int no_of_nodes;
>>>  static bool selftest_live_tree;
>>> +static struct device_node* nodes[MAX_NODES];
>>
>> I think it's time to rework this structure. Instead of a static list,
>> the code should figure out how many entries it needs and then kzalloc()
>> the region.
>
> Ok.
>
>>
>>>
>>>  #define selftest(result, fmt, ...) { \
>>>       if (!(result)) { \
>>> @@ -417,7 +418,6 @@ static void __init of_selftest_changeset(void)
>>>       n1->parent = parent;
>>>       n2->parent = parent;
>>>       n21->parent = n2;
>>> -     n2->child = n21;
>>>       ppremove = of_find_property(parent, "prop-remove", NULL);
>>>       selftest(ppremove, "failed to find removal prop");
>>>
>>> @@ -713,44 +713,34 @@ static void update_node_properties(struct device_node *np,
>>>               child->parent = dup;
>>>  }
>>>
>>> -/**
>>> - *   attach_node_and_children - attaches nodes
>>> - *   and its children to live tree
>>> - *
>>> - *   @np:    Node to attach to live tree
>>> - */
>>> -static int attach_node_and_children(struct device_node *np)
>>> -{
>>> -     struct device_node *next, *root = np, *dup;
>>>
>>> -     /* skip root node */
>>> -     np = np->child;
>>> -     /* storing a copy in temporary node */
>>> -     dup = np;
>>> +static void populate_node_list(struct device_node *np)
>>> +{
>>> +     struct list_head *pos;
>>>
>>> -     while (dup) {
>>> -             if (WARN_ON(last_node_index >= NO_OF_NODES))
>>> -                     return -EINVAL;
>>> -             nodes[last_node_index++] = dup;
>>> -             dup = dup->sibling;
>>> +     list_for_each(pos, &np->children) {
>>> +             nodes[no_of_nodes] = list_entry(pos, struct device_node, siblings);
>>> +             populate_node_list(nodes[no_of_nodes++]);
>>>       }
>>> -     dup = NULL;
>>> +}
>>>
>>> -     while (np) {
>>> -             next = np->allnext;
>>> -             dup = of_find_node_by_path(np->full_name);
>>> +static void attach_node_and_children(struct device_node *np)
>>> +{
>>> +     struct device_node *root = np, *dup, *temp;
>>> +     int i;
>>> +
>>> +     populate_node_list(np);
>>> +
>>> +     for (i = 0; i < no_of_nodes && nodes[i]; i++) {
>>> +             temp = nodes[i];
>>> +             if (temp->parent == root)
>>> +                     temp->parent = of_allnodes;
>>> +             dup = of_find_node_by_path(temp->full_name);
>>>               if (dup)
>>> -                     update_node_properties(np, dup);
>>> -             else {
>>> -                     np->child = NULL;
>>> -                     if (np->parent == root)
>>> -                             np->parent = of_allnodes;
>>> -                     of_attach_node(np);
>>> -             }
>>> -             np = next;
>>> +                     update_node_properties(temp, dup);
>>> +             else
>>> +                     of_attach_node(temp);
>>>       }
>>> -
>>> -     return 0;
>>>  }
>>>
>>>  /**
>>> @@ -764,7 +754,8 @@ static int __init selftest_data_add(void)
>>>       extern uint8_t __dtb_testcases_begin[];
>>>       extern uint8_t __dtb_testcases_end[];
>>>       const int size = __dtb_testcases_end - __dtb_testcases_begin;
>>> -     int rc;
>>> +     struct list_head *pos;
>>> +     int rc, i = 0;
>>>
>>>       if (!size) {
>>>               pr_warn("%s: No testcase data to attach; not running tests\n",
>>> @@ -796,65 +787,66 @@ static int __init selftest_data_add(void)
>>>               /* enabling flag for removing nodes */
>>>               selftest_live_tree = true;
>>>               of_allnodes = selftest_data_node;
>>> +             populate_node_list(selftest_data_node);
>>> +
>>> +             // attach the root node
>>> +             __of_attach_node_sysfs(selftest_data_node);
>>> +
>>> +             while (i < no_of_nodes && nodes[i])
>>> +                     __of_attach_node_sysfs(nodes[i++]);
>>>
>>> -             for_each_of_allnodes(np)
>>> -                     __of_attach_node_sysfs(np);
>>>               of_aliases = of_find_node_by_path("/aliases");
>>>               of_chosen = of_find_node_by_path("/chosen");
>>>               return 0;
>>>       }
>>>
>>> +     list_for_each(pos, &selftest_data_node->children) {
>>> +             np = list_entry(pos, struct device_node, siblings);
>>> +             np->parent = of_allnodes;
>>> +     }
>>> +
>>> +
>>>       /* attach the sub-tree to live tree */
>>> -     return attach_node_and_children(selftest_data_node);
>>> -}
>>> +     attach_node_and_children(selftest_data_node);
>>>
>>> -/**
>>> - *   detach_node_and_children - detaches node
>>> - *   and its children from live tree
>>> - *
>>> - *   @np:    Node to detach from live tree
>>> - */
>>> -static void detach_node_and_children(struct device_node *np)
>>> -{
>>> -     while (np->child)
>>> -             detach_node_and_children(np->child);
>>> -     of_detach_node(np);
>>> +     return 0;
>>>  }
>>>
>>> -/**
>>> - *   selftest_data_remove - removes the selftest data
>>> - *   nodes from the live tree
>>> - */
>>>  static void selftest_data_remove(void)
>>>  {
>>> -     struct device_node *np;
>>>       struct property *prop;
>>> +     struct device_node *np, *temp;
>>> +     int i = no_of_nodes;
>>>
>>>       if (selftest_live_tree) {
>>>               of_node_put(of_aliases);
>>>               of_node_put(of_chosen);
>>>               of_aliases = NULL;
>>>               of_chosen = NULL;
>>> -             for_each_child_of_node(of_allnodes, np)
>>> -                     detach_node_and_children(np);
>>> +             while (i >= 0) {
>>> +                     temp = nodes[i--];
>>> +                     if (temp)
>>> +                             of_detach_node(temp);
>>> +             }
>>>               __of_detach_node_sysfs(of_allnodes);
>>>               of_allnodes = NULL;
>>>               return;
>>>       }
>>>
>>> -     while (last_node_index >= 0) {
>>> -             if (nodes[last_node_index]) {
>>> -                     np = of_find_node_by_path(nodes[last_node_index]->full_name);
>>> -                     if (strcmp(np->full_name, "/aliases") != 0) {
>>> -                             detach_node_and_children(np);
>>> -                     } else {
>>> -                             for_each_property_of_node(np, prop) {
>>> -                                     if (strcmp(prop->name, "testcase-alias") == 0)
>>> +     while (i >= 0) {
>>> +             temp = nodes[i--];
>>> +             if (temp) {
>>> +                     if (strcmp(temp->full_name, "/aliases") == 0) {
>>> +                             for_each_property_of_node(temp, prop) {
>>> +                                     if (strcmp(prop->name, "testcase-alias") == 0) {
>>> +                                             np = of_find_node_by_path(temp->full_name);
>>>                                               of_remove_property(np, prop);
>>> +                                     }
>>>                               }
>>>                       }
>>> +                     else
>>> +                             of_detach_node(temp);
>>>               }
>>> -             last_node_index--;
>>>       }
>>>  }
>>>
>>> @@ -865,6 +857,7 @@ static int __init of_selftest(void)
>>>
>>>       /* adding data for selftest */
>>>       res = selftest_data_add();
>>> +
>>>       if (res)
>>>               return res;
>>>
>>> @@ -891,7 +884,6 @@ static int __init of_selftest(void)
>>>
>>>       /* removing selftest data from live tree */
>>>       selftest_data_remove();
>>> -
>>>       /* Double check linkage after removing testcase data */
>>>       of_selftest_check_tree_linkage();
>>>
>>> diff --git a/include/linux/of.h b/include/linux/of.h
>>> index 6545e7a..84c708c 100644
>>> --- a/include/linux/of.h
>>> +++ b/include/linux/of.h
>>> @@ -53,10 +53,10 @@ struct device_node {
>>>       struct  property *properties;
>>>       struct  property *deadprops;    /* removed properties */
>>>       struct  device_node *parent;
>>> -     struct  device_node *child;
>>> -     struct  device_node *sibling;
>>>       struct  device_node *next;      /* next device of same type */
>>>       struct  device_node *allnext;   /* next in list of all nodes */
>>> +     struct  list_head children;
>>> +     struct  list_head siblings;
>>>       struct  kobject kobj;
>>>       unsigned long _flags;
>>>       void    *data;
>>> --
>>> 1.9.1
>>>
>>
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html




[Index of Archives]     [Device Tree Compilter]     [Device Tree Spec]     [Linux Driver Backports]     [Video for Linux]     [Linux USB Devel]     [Linux PCI Devel]     [Linux Audio Users]     [Linux Kernel]     [Linux SCSI]     [XFree86]     [Yosemite Backpacking]
  Powered by Linux