On Thu, Oct 4, 2018 at 11:14 PM <frowand.list@xxxxxxxxx> wrote: > > From: Frank Rowand <frank.rowand@xxxxxxxx> > Hi Frank, > The changeset entry 'update property' was used for new properties in > an overlay instead of 'add property'. > > The decision of whether to use 'update property' was based on whether > the property already exists in the subtree where the node is being > spliced into. At the top level of creating a changeset describing the > overlay, the target node is in the live devicetree, so checking whether > the property exists in the target node returns the correct result. > As soon as the changeset creation algorithm recurses into a new node, > the target is no longer in the live devicetree, but is instead in the > detached overlay tree, thus all properties are incorrectly found to > already exist in the target. When I applied an overlay (that added a few gpio controllers, etc), the node names for nodes added from the overlay end up NULL. It seems related to this patch and the next one. I haven't completely root caused this but if I back out to before this patch, the situation is fixed. root@arria10:~/unit_tests# ls /sys/bus/platform/drivers/altera_gpio/ bind ff200010.<NULL> ff200020.<NULL> ff200030.<NULL> uevent unbind root@arria10:~/unit_tests# ls /sys/bus/platform/drivers/altera_freeze_br/ bind ff200450.<NULL> uevent unbind Alan > > This fix will expose another devicetree bug that will be fixed > in the following patch in the series. > > When this patch is applied the errors reported by the devictree > unittest will change, and the unittest results will change from: > > ### dt-test ### end of unittest - 210 passed, 0 failed > > to > > ### dt-test ### end of unittest - 203 passed, 7 failed > > Signed-off-by: Frank Rowand <frank.rowand@xxxxxxxx> > --- > drivers/of/overlay.c | 112 ++++++++++++++++++++++++++++++++++----------------- > 1 file changed, 74 insertions(+), 38 deletions(-) > > diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c > index 32cfee68f2e3..0b0904f44bc7 100644 > --- a/drivers/of/overlay.c > +++ b/drivers/of/overlay.c > @@ -24,6 +24,26 @@ > #include "of_private.h" > > /** > + * struct target - info about current target node as recursing through overlay > + * @np: node where current level of overlay will be applied > + * @in_livetree: @np is a node in the live devicetree > + * > + * Used in the algorithm to create the portion of a changeset that describes > + * an overlay fragment, which is a devicetree subtree. Initially @np is a node > + * in the live devicetree where the overlay subtree is targeted to be grafted > + * into. When recursing to the next level of the overlay subtree, the target > + * also recurses to the next level of the live devicetree, as long as overlay > + * subtree node also exists in the live devicetree. When a node in the overlay > + * subtree does not exist at the same level in the live devicetree, target->np > + * points to a newly allocated node, and all subsequent targets in the subtree > + * will be newly allocated nodes. > + */ > +struct target { > + struct device_node *np; > + bool in_livetree; > +}; > + > +/** > * struct fragment - info about fragment nodes in overlay expanded device tree > * @target: target of the overlay operation > * @overlay: pointer to the __overlay__ node > @@ -72,8 +92,7 @@ static int devicetree_corrupt(void) > } > > static int build_changeset_next_level(struct overlay_changeset *ovcs, > - struct device_node *target_node, > - const struct device_node *overlay_node); > + struct target *target, const struct device_node *overlay_node); > > /* > * of_resolve_phandles() finds the largest phandle in the live tree. > @@ -257,14 +276,17 @@ static struct property *dup_and_fixup_symbol_prop( > /** > * add_changeset_property() - add @overlay_prop to overlay changeset > * @ovcs: overlay changeset > - * @target_node: where to place @overlay_prop in live tree > + * @target: where @overlay_prop will be placed > * @overlay_prop: property to add or update, from overlay tree > * @is_symbols_prop: 1 if @overlay_prop is from node "/__symbols__" > * > - * If @overlay_prop does not already exist in @target_node, add changeset entry > - * to add @overlay_prop in @target_node, else add changeset entry to update > + * If @overlay_prop does not already exist in live devicetree, add changeset > + * entry to add @overlay_prop in @target, else add changeset entry to update > * value of @overlay_prop. > * > + * @target may be either in the live devicetree or in a new subtree that > + * is contained in the changeset. > + * > * Some special properties are not updated (no error returned). > * > * Update of property in symbols node is not allowed. > @@ -273,20 +295,22 @@ static struct property *dup_and_fixup_symbol_prop( > * invalid @overlay. > */ > static int add_changeset_property(struct overlay_changeset *ovcs, > - struct device_node *target_node, > - struct property *overlay_prop, > + struct target *target, struct property *overlay_prop, > bool is_symbols_prop) > { > struct property *new_prop = NULL, *prop; > int ret = 0; > > - prop = of_find_property(target_node, overlay_prop->name, NULL); > - > if (!of_prop_cmp(overlay_prop->name, "name") || > !of_prop_cmp(overlay_prop->name, "phandle") || > !of_prop_cmp(overlay_prop->name, "linux,phandle")) > return 0; > > + if (target->in_livetree) > + prop = of_find_property(target->np, overlay_prop->name, NULL); > + else > + prop = NULL; > + > if (is_symbols_prop) { > if (prop) > return -EINVAL; > @@ -299,10 +323,10 @@ static int add_changeset_property(struct overlay_changeset *ovcs, > return -ENOMEM; > > if (!prop) > - ret = of_changeset_add_property(&ovcs->cset, target_node, > + ret = of_changeset_add_property(&ovcs->cset, target->np, > new_prop); > else > - ret = of_changeset_update_property(&ovcs->cset, target_node, > + ret = of_changeset_update_property(&ovcs->cset, target->np, > new_prop); > > if (ret) { > @@ -315,14 +339,14 @@ static int add_changeset_property(struct overlay_changeset *ovcs, > > /** > * add_changeset_node() - add @node (and children) to overlay changeset > - * @ovcs: overlay changeset > - * @target_node: where to place @node in live tree > - * @node: node from within overlay device tree fragment > + * @ovcs: overlay changeset > + * @target: where @overlay_prop will be placed in live tree or changeset > + * @node: node from within overlay device tree fragment > * > - * If @node does not already exist in @target_node, add changeset entry > - * to add @node in @target_node. > + * If @node does not already exist in @target, add changeset entry > + * to add @node in @target. > * > - * If @node already exists in @target_node, and the existing node has > + * If @node already exists in @target, and the existing node has > * a phandle, the overlay node is not allowed to have a phandle. > * > * If @node has child nodes, add the children recursively via > @@ -355,15 +379,16 @@ static int add_changeset_property(struct overlay_changeset *ovcs, > * invalid @overlay. > */ > static int add_changeset_node(struct overlay_changeset *ovcs, > - struct device_node *target_node, struct device_node *node) > + struct target *target, struct device_node *node) > { > const char *node_kbasename; > struct device_node *tchild; > + struct target target_child; > int ret = 0; > > node_kbasename = kbasename(node->full_name); > > - for_each_child_of_node(target_node, tchild) > + for_each_child_of_node(target->np, tchild) > if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name))) > break; > > @@ -372,22 +397,28 @@ static int add_changeset_node(struct overlay_changeset *ovcs, > if (!tchild) > return -ENOMEM; > > - tchild->parent = target_node; > + tchild->parent = target->np; > of_node_set_flag(tchild, OF_OVERLAY); > > ret = of_changeset_attach_node(&ovcs->cset, tchild); > if (ret) > return ret; > > - ret = build_changeset_next_level(ovcs, tchild, node); > + target_child.np = tchild; > + target_child.in_livetree = false; > + > + ret = build_changeset_next_level(ovcs, &target_child, node); > of_node_put(tchild); > return ret; > } > > - if (node->phandle && tchild->phandle) > + if (node->phandle && tchild->phandle) { > ret = -EINVAL; > - else > - ret = build_changeset_next_level(ovcs, tchild, node); > + } else { > + target_child.np = tchild; > + target_child.in_livetree = target->in_livetree; > + ret = build_changeset_next_level(ovcs, &target_child, node); > + } > of_node_put(tchild); > > return ret; > @@ -396,7 +427,7 @@ static int add_changeset_node(struct overlay_changeset *ovcs, > /** > * build_changeset_next_level() - add level of overlay changeset > * @ovcs: overlay changeset > - * @target_node: where to place @overlay_node in live tree > + * @target: where to place @overlay_node in live tree > * @overlay_node: node from within an overlay device tree fragment > * > * Add the properties (if any) and nodes (if any) from @overlay_node to the > @@ -409,27 +440,26 @@ static int add_changeset_node(struct overlay_changeset *ovcs, > * invalid @overlay_node. > */ > static int build_changeset_next_level(struct overlay_changeset *ovcs, > - struct device_node *target_node, > - const struct device_node *overlay_node) > + struct target *target, const struct device_node *overlay_node) > { > struct device_node *child; > struct property *prop; > int ret; > > for_each_property_of_node(overlay_node, prop) { > - ret = add_changeset_property(ovcs, target_node, prop, 0); > + ret = add_changeset_property(ovcs, target, prop, 0); > if (ret) { > pr_debug("Failed to apply prop @%pOF/%s, err=%d\n", > - target_node, prop->name, ret); > + target->np, prop->name, ret); > return ret; > } > } > > for_each_child_of_node(overlay_node, child) { > - ret = add_changeset_node(ovcs, target_node, child); > + ret = add_changeset_node(ovcs, target, child); > if (ret) { > pr_debug("Failed to apply node @%pOF/%s, err=%d\n", > - target_node, child->name, ret); > + target->np, child->name, ret); > of_node_put(child); > return ret; > } > @@ -442,17 +472,17 @@ static int build_changeset_next_level(struct overlay_changeset *ovcs, > * Add the properties from __overlay__ node to the @ovcs->cset changeset. > */ > static int build_changeset_symbols_node(struct overlay_changeset *ovcs, > - struct device_node *target_node, > + struct target *target, > const struct device_node *overlay_symbols_node) > { > struct property *prop; > int ret; > > for_each_property_of_node(overlay_symbols_node, prop) { > - ret = add_changeset_property(ovcs, target_node, prop, 1); > + ret = add_changeset_property(ovcs, target, prop, 1); > if (ret) { > pr_debug("Failed to apply prop @%pOF/%s, err=%d\n", > - target_node, prop->name, ret); > + target->np, prop->name, ret); > return ret; > } > } > @@ -475,6 +505,7 @@ static int build_changeset_symbols_node(struct overlay_changeset *ovcs, > static int build_changeset(struct overlay_changeset *ovcs) > { > struct fragment *fragment; > + struct target target; > int fragments_count, i, ret; > > /* > @@ -489,7 +520,9 @@ static int build_changeset(struct overlay_changeset *ovcs) > for (i = 0; i < fragments_count; i++) { > fragment = &ovcs->fragments[i]; > > - ret = build_changeset_next_level(ovcs, fragment->target, > + target.np = fragment->target; > + target.in_livetree = true; > + ret = build_changeset_next_level(ovcs, &target, > fragment->overlay); > if (ret) { > pr_debug("apply failed '%pOF'\n", fragment->target); > @@ -499,7 +532,10 @@ static int build_changeset(struct overlay_changeset *ovcs) > > if (ovcs->symbols_fragment) { > fragment = &ovcs->fragments[ovcs->count - 1]; > - ret = build_changeset_symbols_node(ovcs, fragment->target, > + > + target.np = fragment->target; > + target.in_livetree = true; > + ret = build_changeset_symbols_node(ovcs, &target, > fragment->overlay); > if (ret) { > pr_debug("apply failed '%pOF'\n", fragment->target); > @@ -517,7 +553,7 @@ static int build_changeset(struct overlay_changeset *ovcs) > * 1) "target" property containing the phandle of the target > * 2) "target-path" property containing the path of the target > */ > -static struct device_node *find_target_node(struct device_node *info_node) > +static struct device_node *find_target(struct device_node *info_node) > { > struct device_node *node; > const char *path; > @@ -623,7 +659,7 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs, > > fragment = &fragments[cnt]; > fragment->overlay = overlay_node; > - fragment->target = find_target_node(node); > + fragment->target = find_target(node); > if (!fragment->target) { > of_node_put(fragment->overlay); > ret = -EINVAL; > -- > Frank Rowand <frank.rowand@xxxxxxxx> >