aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFrank Rowand <frank.rowand@sony.com>2017-07-19 12:25:22 -0400
committerRob Herring <robh@kernel.org>2017-07-20 10:40:05 -0400
commitd1651b03c2df75db8eda3fbcd3a07adb337ee8b0 (patch)
tree56a8aab2aaac0b3c63383ec984167442fd4ecdfb
parentc1cd1e01fece0c139a7946c14b788f887d8b658a (diff)
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>
-rw-r--r--drivers/of/overlay.c116
1 files changed, 107 insertions, 9 deletions
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
index fbe1980accb6..8ecfee31ab6d 100644
--- a/drivers/of/overlay.c
+++ b/drivers/of/overlay.c
@@ -35,6 +35,7 @@
35struct of_overlay_info { 35struct of_overlay_info {
36 struct device_node *target; 36 struct device_node *target;
37 struct device_node *overlay; 37 struct device_node *overlay;
38 bool is_symbols_node;
38}; 39};
39 40
40/** 41/**
@@ -55,7 +56,8 @@ struct of_overlay {
55}; 56};
56 57
57static int of_overlay_apply_one(struct of_overlay *ov, 58static int of_overlay_apply_one(struct of_overlay *ov,
58 struct device_node *target, const struct device_node *overlay); 59 struct device_node *target, const struct device_node *overlay,
60 bool is_symbols_node);
59 61
60static BLOCKING_NOTIFIER_HEAD(of_overlay_chain); 62static BLOCKING_NOTIFIER_HEAD(of_overlay_chain);
61 63
@@ -92,10 +94,74 @@ static int of_overlay_notify(struct of_overlay *ov,
92 return 0; 94 return 0;
93} 95}
94 96
97static struct property *dup_and_fixup_symbol_prop(struct of_overlay *ov,
98 const struct property *prop)
99{
100 struct of_overlay_info *ovinfo;
101 struct property *new;
102 const char *overlay_name;
103 char *label_path;
104 char *symbol_path;
105 const char *target_path;
106 int k;
107 int label_path_len;
108 int overlay_name_len;
109 int target_path_len;
110
111 if (!prop->value)
112 return NULL;
113 symbol_path = prop->value;
114
115 new = kzalloc(sizeof(*new), GFP_KERNEL);
116 if (!new)
117 return NULL;
118
119 for (k = 0; k < ov->count; k++) {
120 ovinfo = &ov->ovinfo_tab[k];
121 overlay_name = ovinfo->overlay->full_name;
122 overlay_name_len = strlen(overlay_name);
123 if (!strncasecmp(symbol_path, overlay_name, overlay_name_len))
124 break;
125 }
126
127 if (k >= ov->count)
128 goto err_free;
129
130 target_path = ovinfo->target->full_name;
131 target_path_len = strlen(target_path);
132
133 label_path = symbol_path + overlay_name_len;
134 label_path_len = strlen(label_path);
135
136 new->name = kstrdup(prop->name, GFP_KERNEL);
137 new->length = target_path_len + label_path_len + 1;
138 new->value = kzalloc(new->length, GFP_KERNEL);
139
140 if (!new->name || !new->value)
141 goto err_free;
142
143 strcpy(new->value, target_path);
144 strcpy(new->value + target_path_len, label_path);
145
146 /* mark the property as dynamic */
147 of_property_set_flag(new, OF_DYNAMIC);
148
149 return new;
150
151 err_free:
152 kfree(new->name);
153 kfree(new->value);
154 kfree(new);
155 return NULL;
156
157
158}
159
95static int of_overlay_apply_single_property(struct of_overlay *ov, 160static int of_overlay_apply_single_property(struct of_overlay *ov,
96 struct device_node *target, struct property *prop) 161 struct device_node *target, struct property *prop,
162 bool is_symbols_node)
97{ 163{
98 struct property *propn, *tprop; 164 struct property *propn = NULL, *tprop;
99 165
100 /* NOTE: Multiple changes of single properties not supported */ 166 /* NOTE: Multiple changes of single properties not supported */
101 tprop = of_find_property(target, prop->name, NULL); 167 tprop = of_find_property(target, prop->name, NULL);
@@ -106,7 +172,15 @@ static int of_overlay_apply_single_property(struct of_overlay *ov,
106 of_prop_cmp(prop->name, "linux,phandle") == 0) 172 of_prop_cmp(prop->name, "linux,phandle") == 0)
107 return 0; 173 return 0;
108 174
109 propn = __of_prop_dup(prop, GFP_KERNEL); 175 if (is_symbols_node) {
176 /* changing a property in __symbols__ node not allowed */
177 if (tprop)
178 return -EINVAL;
179 propn = dup_and_fixup_symbol_prop(ov, prop);
180 } else {
181 propn = __of_prop_dup(prop, GFP_KERNEL);
182 }
183
110 if (propn == NULL) 184 if (propn == NULL)
111 return -ENOMEM; 185 return -ENOMEM;
112 186
@@ -140,7 +214,7 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
140 return -EINVAL; 214 return -EINVAL;
141 215
142 /* apply overlay recursively */ 216 /* apply overlay recursively */
143 ret = of_overlay_apply_one(ov, tchild, child); 217 ret = of_overlay_apply_one(ov, tchild, child, 0);
144 of_node_put(tchild); 218 of_node_put(tchild);
145 } else { 219 } else {
146 /* create empty tree as a target */ 220 /* create empty tree as a target */
@@ -155,7 +229,7 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
155 if (ret) 229 if (ret)
156 return ret; 230 return ret;
157 231
158 ret = of_overlay_apply_one(ov, tchild, child); 232 ret = of_overlay_apply_one(ov, tchild, child, 0);
159 if (ret) 233 if (ret)
160 return ret; 234 return ret;
161 } 235 }
@@ -171,14 +245,16 @@ static int of_overlay_apply_single_device_node(struct of_overlay *ov,
171 * by using the changeset. 245 * by using the changeset.
172 */ 246 */
173static int of_overlay_apply_one(struct of_overlay *ov, 247static int of_overlay_apply_one(struct of_overlay *ov,
174 struct device_node *target, const struct device_node *overlay) 248 struct device_node *target, const struct device_node *overlay,
249 bool is_symbols_node)
175{ 250{
176 struct device_node *child; 251 struct device_node *child;
177 struct property *prop; 252 struct property *prop;
178 int ret; 253 int ret;
179 254
180 for_each_property_of_node(overlay, prop) { 255 for_each_property_of_node(overlay, prop) {
181 ret = of_overlay_apply_single_property(ov, target, prop); 256 ret = of_overlay_apply_single_property(ov, target, prop,
257 is_symbols_node);
182 if (ret) { 258 if (ret) {
183 pr_err("Failed to apply prop @%pOF/%s\n", 259 pr_err("Failed to apply prop @%pOF/%s\n",
184 target, prop->name); 260 target, prop->name);
@@ -186,6 +262,10 @@ static int of_overlay_apply_one(struct of_overlay *ov,
186 } 262 }
187 } 263 }
188 264
265 /* do not allow symbols node to have any children */
266 if (is_symbols_node)
267 return 0;
268
189 for_each_child_of_node(overlay, child) { 269 for_each_child_of_node(overlay, child) {
190 ret = of_overlay_apply_single_device_node(ov, target, child); 270 ret = of_overlay_apply_single_device_node(ov, target, child);
191 if (ret != 0) { 271 if (ret != 0) {
@@ -216,7 +296,8 @@ static int of_overlay_apply(struct of_overlay *ov)
216 for (i = 0; i < ov->count; i++) { 296 for (i = 0; i < ov->count; i++) {
217 struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i]; 297 struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
218 298
219 err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay); 299 err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay,
300 ovinfo->is_symbols_node);
220 if (err != 0) { 301 if (err != 0) {
221 pr_err("apply failed '%pOF'\n", ovinfo->target); 302 pr_err("apply failed '%pOF'\n", ovinfo->target);
222 return err; 303 return err;
@@ -314,6 +395,9 @@ static int of_build_overlay_info(struct of_overlay *ov,
314 for_each_child_of_node(tree, node) 395 for_each_child_of_node(tree, node)
315 cnt++; 396 cnt++;
316 397
398 if (of_get_child_by_name(tree, "__symbols__"))
399 cnt++;
400
317 ovinfo = kcalloc(cnt, sizeof(*ovinfo), GFP_KERNEL); 401 ovinfo = kcalloc(cnt, sizeof(*ovinfo), GFP_KERNEL);
318 if (ovinfo == NULL) 402 if (ovinfo == NULL)
319 return -ENOMEM; 403 return -ENOMEM;
@@ -325,6 +409,20 @@ static int of_build_overlay_info(struct of_overlay *ov,
325 cnt++; 409 cnt++;
326 } 410 }
327 411
412 node = of_get_child_by_name(tree, "__symbols__");
413 if (node) {
414 ovinfo[cnt].overlay = node;
415 ovinfo[cnt].target = of_find_node_by_path("/__symbols__");
416 ovinfo[cnt].is_symbols_node = 1;
417
418 if (!ovinfo[cnt].target) {
419 pr_err("no symbols in root of device tree.\n");
420 return -EINVAL;
421 }
422
423 cnt++;
424 }
425
328 /* if nothing filled, return error */ 426 /* if nothing filled, return error */
329 if (cnt == 0) { 427 if (cnt == 0) {
330 kfree(ovinfo); 428 kfree(ovinfo);