of: overlay: add overlay symbols to live device tree
Add overlay __symbols__ properties to live tree when an overlay is added to the live tree so that the symbols are available to subsequent overlays. Expected test result is new __symbols__ entries for labels from the overlay after this commit. Before this commit: Console error message near end of unittest: ### dt-test ### FAIL of_unittest_overlay_high_level():2296 Adding overlay 'overlay_bad_symbol' failed ### dt-test ### end of unittest - 190 passed, 1 failed The new unittest "fails" because the expected result of loading the new overlay is an error instead of success. $ # node hvac-medium-2 exists because the overlay loaded $ # since the duplicate symbol was not detected $ cd /proc/device-tree/testcase-data-2/substation@100/ $ ls compatible hvac-medium-2 motor-8 reg hvac-large-1 linux,phandle name status hvac-medium-1 motor-1 phandle $ cd /proc/device-tree/__symbols__/ $ ls electric_1 lights_1 name rides_1 spin_ctrl_2 hvac_1 lights_2 retail_1 spin_ctrl_1 After this commit: Previous console error message no longer occurs, but expected error occurs: OF: overlay: Failed to apply prop @/__symbols__/hvac_1 OF: overlay: apply failed '/__symbols__' ### dt-test ### end of unittest - 191 passed, 0 failed $ # node hvac-medium-2 does not exist because the overlay $ # properly failed to load due to the duplicate symbol $ cd /proc/device-tree/testcase-data-2/substation@100/ $ ls compatible hvac-medium-1 motor-1 name reg hvac-large-1 linux,phandle motor-8 phandle status $ cd /proc/device-tree/__symbols__/ $ ls electric_1 lights_1 retail_1 ride_200_right spin_ctrl_2 hvac_1 lights_2 ride_200 rides_1 hvac_2 name ride_200_left spin_ctrl_1 $ cat ride_200; echo /testcase-data-2/fairway-1/ride@200 $ cat ride_200_left ; echo /testcase-data-2/fairway-1/ride@200/track@10 $ cat ride_200_right ; echo /testcase-data-2/fairway-1/ride@200/track@20 Signed-off-by: Frank Rowand <frank.rowand@sony.com> Signed-off-by: Rob Herring <robh@kernel.org>
This commit is contained in:
parent
c1cd1e01fe
commit
d1651b03c2
|
@ -35,6 +35,7 @@
|
|||
struct of_overlay_info {
|
||||
struct device_node *target;
|
||||
struct device_node *overlay;
|
||||
bool is_symbols_node;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -55,7 +56,8 @@ struct of_overlay {
|
|||
};
|
||||
|
||||
static int of_overlay_apply_one(struct of_overlay *ov,
|
||||
struct device_node *target, const struct device_node *overlay);
|
||||
struct device_node *target, const struct device_node *overlay,
|
||||
bool is_symbols_node);
|
||||
|
||||
static BLOCKING_NOTIFIER_HEAD(of_overlay_chain);
|
||||
|
||||
|
@ -92,10 +94,74 @@ static int of_overlay_notify(struct of_overlay *ov,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int of_overlay_apply_single_property(struct of_overlay *ov,
|
||||
struct device_node *target, struct property *prop)
|
||||
static struct property *dup_and_fixup_symbol_prop(struct of_overlay *ov,
|
||||
const struct property *prop)
|
||||
{
|
||||
struct property *propn, *tprop;
|
||||
struct of_overlay_info *ovinfo;
|
||||
struct property *new;
|
||||
const char *overlay_name;
|
||||
char *label_path;
|
||||
char *symbol_path;
|
||||
const char *target_path;
|
||||
int k;
|
||||
int label_path_len;
|
||||
int overlay_name_len;
|
||||
int target_path_len;
|
||||
|
||||
if (!prop->value)
|
||||
return NULL;
|
||||
symbol_path = prop->value;
|
||||
|
||||
new = kzalloc(sizeof(*new), GFP_KERNEL);
|
||||
if (!new)
|
||||
return NULL;
|
||||
|
||||
for (k = 0; k < ov->count; k++) {
|
||||
ovinfo = &ov->ovinfo_tab[k];
|
||||
overlay_name = ovinfo->overlay->full_name;
|
||||
overlay_name_len = strlen(overlay_name);
|
||||
if (!strncasecmp(symbol_path, overlay_name, overlay_name_len))
|
||||
break;
|
||||
}
|
||||
|
||||
if (k >= ov->count)
|
||||
goto err_free;
|
||||
|
||||
target_path = ovinfo->target->full_name;
|
||||
target_path_len = strlen(target_path);
|
||||
|
||||
label_path = symbol_path + overlay_name_len;
|
||||
label_path_len = strlen(label_path);
|
||||
|
||||
new->name = kstrdup(prop->name, GFP_KERNEL);
|
||||
new->length = target_path_len + label_path_len + 1;
|
||||
new->value = kzalloc(new->length, GFP_KERNEL);
|
||||
|
||||
if (!new->name || !new->value)
|
||||
goto err_free;
|
||||
|
||||
strcpy(new->value, target_path);
|
||||
strcpy(new->value + target_path_len, label_path);
|
||||
|
||||
/* mark the property as dynamic */
|
||||
of_property_set_flag(new, OF_DYNAMIC);
|
||||
|
||||
return new;
|
||||
|
||||
err_free:
|
||||
kfree(new->name);
|
||||
kfree(new->value);
|
||||
kfree(new);
|
||||
return NULL;
|
||||
|
||||
|
||||
}
|
||||
|
||||
static int of_overlay_apply_single_property(struct of_overlay *ov,
|
||||
struct device_node *target, struct property *prop,
|
||||
bool is_symbols_node)
|
||||
{
|
||||
struct property *propn = NULL, *tprop;
|
||||
|
||||
/* NOTE: Multiple changes of single properties not supported */
|
||||
tprop = of_find_property(target, prop->name, NULL);
|
||||
|
@ -106,7 +172,15 @@ static int of_overlay_apply_single_property(struct of_overlay *ov,
|
|||
of_prop_cmp(prop->name, "linux,phandle") == 0)
|
||||
return 0;
|
||||
|
||||
propn = __of_prop_dup(prop, GFP_KERNEL);
|
||||
if (is_symbols_node) {
|
||||
/* changing a property in __symbols__ node not allowed */
|
||||
if (tprop)
|
||||
return -EINVAL;
|
||||
propn = dup_and_fixup_symbol_prop(ov, prop);
|
||||
} else {
|
||||
propn = __of_prop_dup(prop, GFP_KERNEL);
|
||||
}
|
||||
|
||||
if (propn == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
|
@ -140,7 +214,7 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
|
|||
return -EINVAL;
|
||||
|
||||
/* apply overlay recursively */
|
||||
ret = of_overlay_apply_one(ov, tchild, child);
|
||||
ret = of_overlay_apply_one(ov, tchild, child, 0);
|
||||
of_node_put(tchild);
|
||||
} else {
|
||||
/* create empty tree as a target */
|
||||
|
@ -155,7 +229,7 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
|
|||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = of_overlay_apply_one(ov, tchild, child);
|
||||
ret = of_overlay_apply_one(ov, tchild, child, 0);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
@ -171,14 +245,16 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
|
|||
* by using the changeset.
|
||||
*/
|
||||
static int of_overlay_apply_one(struct of_overlay *ov,
|
||||
struct device_node *target, const struct device_node *overlay)
|
||||
struct device_node *target, const struct device_node *overlay,
|
||||
bool is_symbols_node)
|
||||
{
|
||||
struct device_node *child;
|
||||
struct property *prop;
|
||||
int ret;
|
||||
|
||||
for_each_property_of_node(overlay, prop) {
|
||||
ret = of_overlay_apply_single_property(ov, target, prop);
|
||||
ret = of_overlay_apply_single_property(ov, target, prop,
|
||||
is_symbols_node);
|
||||
if (ret) {
|
||||
pr_err("Failed to apply prop @%pOF/%s\n",
|
||||
target, prop->name);
|
||||
|
@ -186,6 +262,10 @@ static int of_overlay_apply_one(struct of_overlay *ov,
|
|||
}
|
||||
}
|
||||
|
||||
/* do not allow symbols node to have any children */
|
||||
if (is_symbols_node)
|
||||
return 0;
|
||||
|
||||
for_each_child_of_node(overlay, child) {
|
||||
ret = of_overlay_apply_single_device_node(ov, target, child);
|
||||
if (ret != 0) {
|
||||
|
@ -216,7 +296,8 @@ static int of_overlay_apply(struct of_overlay *ov)
|
|||
for (i = 0; i < ov->count; i++) {
|
||||
struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
|
||||
|
||||
err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay);
|
||||
err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay,
|
||||
ovinfo->is_symbols_node);
|
||||
if (err != 0) {
|
||||
pr_err("apply failed '%pOF'\n", ovinfo->target);
|
||||
return err;
|
||||
|
@ -314,6 +395,9 @@ static int of_build_overlay_info(struct of_overlay *ov,
|
|||
for_each_child_of_node(tree, node)
|
||||
cnt++;
|
||||
|
||||
if (of_get_child_by_name(tree, "__symbols__"))
|
||||
cnt++;
|
||||
|
||||
ovinfo = kcalloc(cnt, sizeof(*ovinfo), GFP_KERNEL);
|
||||
if (ovinfo == NULL)
|
||||
return -ENOMEM;
|
||||
|
@ -325,6 +409,20 @@ static int of_build_overlay_info(struct of_overlay *ov,
|
|||
cnt++;
|
||||
}
|
||||
|
||||
node = of_get_child_by_name(tree, "__symbols__");
|
||||
if (node) {
|
||||
ovinfo[cnt].overlay = node;
|
||||
ovinfo[cnt].target = of_find_node_by_path("/__symbols__");
|
||||
ovinfo[cnt].is_symbols_node = 1;
|
||||
|
||||
if (!ovinfo[cnt].target) {
|
||||
pr_err("no symbols in root of device tree.\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
cnt++;
|
||||
}
|
||||
|
||||
/* if nothing filled, return error */
|
||||
if (cnt == 0) {
|
||||
kfree(ovinfo);
|
||||
|
|
Loading…
Reference in New Issue