diff options
author | Frank Rowand <frank.rowand@sony.com> | 2017-10-17 19:36:31 -0400 |
---|---|---|
committer | Rob Herring <robh@kernel.org> | 2017-10-17 21:47:37 -0400 |
commit | e0a58f3e08d4b7fa8e2a4075c522f1a98c9e4cab (patch) | |
tree | 451e9c437fe1cfd801532eb356932fa39ad29ca1 | |
parent | 3912b7917ab78d75b32bec8d297ac3c46b1b2a44 (diff) |
of: overlay: remove a dependency on device node full_name
The "%pOF" printf format was recently added to print the
full name of a device tree node, with the intent of changing
the node full_name field to contain only the node name instead
of the full path of the node.
dup_and_fixup_symbol_prop() duplicates a property from the
"/__symbols__" node of an overlay device tree. The value
of each duplicated property must be fixed up to include
the full path of a node in the live device tree. The
current code uses the node's full_name for that purpose.
Update the code to use the "%pOF" printf format to
determine the node's full path.
Signed-off-by: Frank Rowand <frank.rowand@sony.com>
Signed-off-by: Rob Herring <robh@kernel.org>
-rw-r--r-- | drivers/of/base.c | 2 | ||||
-rw-r--r-- | drivers/of/of_private.h | 2 | ||||
-rw-r--r-- | drivers/of/overlay.c | 90 |
3 files changed, 59 insertions, 35 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index b98f3adffbb0..3de07e6e82a0 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -658,7 +658,7 @@ struct device_node *of_get_child_by_name(const struct device_node *node, | |||
658 | } | 658 | } |
659 | EXPORT_SYMBOL(of_get_child_by_name); | 659 | EXPORT_SYMBOL(of_get_child_by_name); |
660 | 660 | ||
661 | static struct device_node *__of_find_node_by_path(struct device_node *parent, | 661 | struct device_node *__of_find_node_by_path(struct device_node *parent, |
662 | const char *path) | 662 | const char *path) |
663 | { | 663 | { |
664 | struct device_node *child; | 664 | struct device_node *child; |
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index 248730567dbe..92a9a3687446 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h | |||
@@ -110,6 +110,8 @@ extern void *__unflatten_device_tree(const void *blob, | |||
110 | struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); | 110 | struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); |
111 | __printf(2, 3) struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...); | 111 | __printf(2, 3) struct device_node *__of_node_dup(const struct device_node *np, const char *fmt, ...); |
112 | 112 | ||
113 | struct device_node *__of_find_node_by_path(struct device_node *parent, | ||
114 | const char *path); | ||
113 | struct device_node *__of_find_node_by_full_path(struct device_node *node, | 115 | struct device_node *__of_find_node_by_full_path(struct device_node *node, |
114 | const char *path); | 116 | const char *path); |
115 | 117 | ||
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c index 602218e07ec3..0e9aefc1ff15 100644 --- a/drivers/of/overlay.c +++ b/drivers/of/overlay.c | |||
@@ -37,6 +37,7 @@ struct fragment { | |||
37 | /** | 37 | /** |
38 | * struct overlay_changeset | 38 | * struct overlay_changeset |
39 | * @ovcs_list: list on which we are located | 39 | * @ovcs_list: list on which we are located |
40 | * @overlay_tree: expanded device tree that contains the fragment nodes | ||
40 | * @count: count of fragment structures | 41 | * @count: count of fragment structures |
41 | * @fragments: fragment nodes in the overlay expanded device tree | 42 | * @fragments: fragment nodes in the overlay expanded device tree |
42 | * @symbols_fragment: last element of @fragments[] is the __symbols__ node | 43 | * @symbols_fragment: last element of @fragments[] is the __symbols__ node |
@@ -45,6 +46,7 @@ struct fragment { | |||
45 | struct overlay_changeset { | 46 | struct overlay_changeset { |
46 | int id; | 47 | int id; |
47 | struct list_head ovcs_list; | 48 | struct list_head ovcs_list; |
49 | struct device_node *overlay_tree; | ||
48 | int count; | 50 | int count; |
49 | struct fragment *fragments; | 51 | struct fragment *fragments; |
50 | bool symbols_fragment; | 52 | bool symbols_fragment; |
@@ -145,12 +147,13 @@ static int overlay_notify(struct overlay_changeset *ovcs, | |||
145 | } | 147 | } |
146 | 148 | ||
147 | /* | 149 | /* |
148 | * The properties in the "/__symbols__" node are "symbols". | 150 | * The values of properties in the "/__symbols__" node are paths in |
151 | * the ovcs->overlay_tree. When duplicating the properties, the paths | ||
152 | * need to be adjusted to be the correct path for the live device tree. | ||
149 | * | 153 | * |
150 | * The value of properties in the "/__symbols__" node is the path of a | 154 | * The paths refer to a node in the subtree of a fragment node's "__overlay__" |
151 | * node in the subtree of a fragment node's "__overlay__" node, for | 155 | * node, for example "/fragment@0/__overlay__/symbol_path_tail", |
152 | * example "/fragment@0/__overlay__/symbol_path_tail". Symbol_path_tail | 156 | * where symbol_path_tail can be a single node or it may be a multi-node path. |
153 | * can be a single node or it may be a multi-node path. | ||
154 | * | 157 | * |
155 | * The duplicated property value will be modified by replacing the | 158 | * The duplicated property value will be modified by replacing the |
156 | * "/fragment_name/__overlay/" portion of the value with the target | 159 | * "/fragment_name/__overlay/" portion of the value with the target |
@@ -160,59 +163,76 @@ static struct property *dup_and_fixup_symbol_prop( | |||
160 | struct overlay_changeset *ovcs, const struct property *prop) | 163 | struct overlay_changeset *ovcs, const struct property *prop) |
161 | { | 164 | { |
162 | struct fragment *fragment; | 165 | struct fragment *fragment; |
163 | struct property *new; | 166 | struct property *new_prop; |
164 | const char *overlay_name; | 167 | struct device_node *fragment_node; |
165 | char *symbol_path_tail; | 168 | struct device_node *overlay_node; |
166 | char *symbol_path; | 169 | const char *path; |
170 | const char *path_tail; | ||
167 | const char *target_path; | 171 | const char *target_path; |
168 | int k; | 172 | int k; |
169 | int symbol_path_tail_len; | ||
170 | int overlay_name_len; | 173 | int overlay_name_len; |
174 | int path_len; | ||
175 | int path_tail_len; | ||
171 | int target_path_len; | 176 | int target_path_len; |
172 | 177 | ||
173 | if (!prop->value) | 178 | if (!prop->value) |
174 | return NULL; | 179 | return NULL; |
175 | symbol_path = prop->value; | 180 | if (strnlen(prop->value, prop->length) >= prop->length) |
181 | return NULL; | ||
182 | path = prop->value; | ||
183 | path_len = strlen(path); | ||
176 | 184 | ||
177 | new = kzalloc(sizeof(*new), GFP_KERNEL); | 185 | if (path_len < 1) |
178 | if (!new) | ||
179 | return NULL; | 186 | return NULL; |
187 | fragment_node = __of_find_node_by_path(ovcs->overlay_tree, path + 1); | ||
188 | overlay_node = __of_find_node_by_path(fragment_node, "__overlay__/"); | ||
189 | of_node_put(fragment_node); | ||
190 | of_node_put(overlay_node); | ||
180 | 191 | ||
181 | for (k = 0; k < ovcs->count; k++) { | 192 | for (k = 0; k < ovcs->count; k++) { |
182 | fragment = &ovcs->fragments[k]; | 193 | fragment = &ovcs->fragments[k]; |
183 | overlay_name = fragment->overlay->full_name; | 194 | if (fragment->overlay == overlay_node) |
184 | overlay_name_len = strlen(overlay_name); | ||
185 | if (!strncasecmp(symbol_path, overlay_name, overlay_name_len)) | ||
186 | break; | 195 | break; |
187 | } | 196 | } |
188 | |||
189 | if (k >= ovcs->count) | 197 | if (k >= ovcs->count) |
190 | goto err_free; | 198 | return NULL; |
199 | |||
200 | overlay_name_len = snprintf(NULL, 0, "%pOF", fragment->overlay); | ||
191 | 201 | ||
192 | target_path = fragment->target->full_name; | 202 | if (overlay_name_len > path_len) |
203 | return NULL; | ||
204 | path_tail = path + overlay_name_len; | ||
205 | path_tail_len = strlen(path_tail); | ||
206 | |||
207 | target_path = kasprintf(GFP_KERNEL, "%pOF", fragment->target); | ||
208 | if (!target_path) | ||
209 | return NULL; | ||
193 | target_path_len = strlen(target_path); | 210 | target_path_len = strlen(target_path); |
194 | 211 | ||
195 | symbol_path_tail = symbol_path + overlay_name_len; | 212 | new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); |
196 | symbol_path_tail_len = strlen(symbol_path_tail); | 213 | if (!new_prop) |
214 | goto err_free_target_path; | ||
197 | 215 | ||
198 | new->name = kstrdup(prop->name, GFP_KERNEL); | 216 | new_prop->name = kstrdup(prop->name, GFP_KERNEL); |
199 | new->length = target_path_len + symbol_path_tail_len + 1; | 217 | new_prop->length = target_path_len + path_tail_len + 1; |
200 | new->value = kzalloc(new->length, GFP_KERNEL); | 218 | new_prop->value = kzalloc(new_prop->length, GFP_KERNEL); |
219 | if (!new_prop->name || !new_prop->value) | ||
220 | goto err_free_new_prop; | ||
201 | 221 | ||
202 | if (!new->name || !new->value) | 222 | strcpy(new_prop->value, target_path); |
203 | goto err_free; | 223 | strcpy(new_prop->value + target_path_len, path_tail); |
204 | 224 | ||
205 | strcpy(new->value, target_path); | 225 | of_property_set_flag(new_prop, OF_DYNAMIC); |
206 | strcpy(new->value + target_path_len, symbol_path_tail); | ||
207 | 226 | ||
208 | of_property_set_flag(new, OF_DYNAMIC); | 227 | return new_prop; |
209 | 228 | ||
210 | return new; | 229 | err_free_new_prop: |
230 | kfree(new_prop->name); | ||
231 | kfree(new_prop->value); | ||
232 | kfree(new_prop); | ||
233 | err_free_target_path: | ||
234 | kfree(target_path); | ||
211 | 235 | ||
212 | err_free: | ||
213 | kfree(new->name); | ||
214 | kfree(new->value); | ||
215 | kfree(new); | ||
216 | return NULL; | 236 | return NULL; |
217 | } | 237 | } |
218 | 238 | ||
@@ -519,6 +539,8 @@ static int init_overlay_changeset(struct overlay_changeset *ovcs, | |||
519 | if (!of_node_is_root(tree)) | 539 | if (!of_node_is_root(tree)) |
520 | pr_debug("%s() tree is not root\n", __func__); | 540 | pr_debug("%s() tree is not root\n", __func__); |
521 | 541 | ||
542 | ovcs->overlay_tree = tree; | ||
543 | |||
522 | INIT_LIST_HEAD(&ovcs->ovcs_list); | 544 | INIT_LIST_HEAD(&ovcs->ovcs_list); |
523 | 545 | ||
524 | of_changeset_init(&ovcs->cset); | 546 | of_changeset_init(&ovcs->cset); |