| xj | b04a402 | 2021-11-25 15:01:52 +0800 | [diff] [blame] | 1 | // SPDX-License-Identifier: GPL-2.0 | 
|  | 2 | /* | 
|  | 3 | * Functions for working with device tree overlays | 
|  | 4 | * | 
|  | 5 | * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com> | 
|  | 6 | * Copyright (C) 2012 Texas Instruments Inc. | 
|  | 7 | */ | 
|  | 8 |  | 
|  | 9 | #define pr_fmt(fmt)	"OF: overlay: " fmt | 
|  | 10 |  | 
|  | 11 | #include <linux/kernel.h> | 
|  | 12 | #include <linux/module.h> | 
|  | 13 | #include <linux/of.h> | 
|  | 14 | #include <linux/of_device.h> | 
|  | 15 | #include <linux/of_fdt.h> | 
|  | 16 | #include <linux/string.h> | 
|  | 17 | #include <linux/ctype.h> | 
|  | 18 | #include <linux/errno.h> | 
|  | 19 | #include <linux/slab.h> | 
|  | 20 | #include <linux/libfdt.h> | 
|  | 21 | #include <linux/err.h> | 
|  | 22 | #include <linux/idr.h> | 
|  | 23 |  | 
|  | 24 | #include "of_private.h" | 
|  | 25 |  | 
|  | 26 | /** | 
|  | 27 | * struct target - info about current target node as recursing through overlay | 
|  | 28 | * @np:			node where current level of overlay will be applied | 
|  | 29 | * @in_livetree:	@np is a node in the live devicetree | 
|  | 30 | * | 
|  | 31 | * Used in the algorithm to create the portion of a changeset that describes | 
|  | 32 | * an overlay fragment, which is a devicetree subtree.  Initially @np is a node | 
|  | 33 | * in the live devicetree where the overlay subtree is targeted to be grafted | 
|  | 34 | * into.  When recursing to the next level of the overlay subtree, the target | 
|  | 35 | * also recurses to the next level of the live devicetree, as long as overlay | 
|  | 36 | * subtree node also exists in the live devicetree.  When a node in the overlay | 
|  | 37 | * subtree does not exist at the same level in the live devicetree, target->np | 
|  | 38 | * points to a newly allocated node, and all subsequent targets in the subtree | 
|  | 39 | * will be newly allocated nodes. | 
|  | 40 | */ | 
|  | 41 | struct target { | 
|  | 42 | struct device_node *np; | 
|  | 43 | bool in_livetree; | 
|  | 44 | }; | 
|  | 45 |  | 
|  | 46 | /** | 
|  | 47 | * struct fragment - info about fragment nodes in overlay expanded device tree | 
|  | 48 | * @target:	target of the overlay operation | 
|  | 49 | * @overlay:	pointer to the __overlay__ node | 
|  | 50 | */ | 
|  | 51 | struct fragment { | 
|  | 52 | struct device_node *target; | 
|  | 53 | struct device_node *overlay; | 
|  | 54 | }; | 
|  | 55 |  | 
|  | 56 | /** | 
|  | 57 | * struct overlay_changeset | 
|  | 58 | * @id:			changeset identifier | 
|  | 59 | * @ovcs_list:		list on which we are located | 
|  | 60 | * @fdt:		FDT that was unflattened to create @overlay_tree | 
|  | 61 | * @overlay_tree:	expanded device tree that contains the fragment nodes | 
|  | 62 | * @count:		count of fragment structures | 
|  | 63 | * @fragments:		fragment nodes in the overlay expanded device tree | 
|  | 64 | * @symbols_fragment:	last element of @fragments[] is the  __symbols__ node | 
|  | 65 | * @cset:		changeset to apply fragments to live device tree | 
|  | 66 | */ | 
|  | 67 | struct overlay_changeset { | 
|  | 68 | int id; | 
|  | 69 | struct list_head ovcs_list; | 
|  | 70 | const void *fdt; | 
|  | 71 | struct device_node *overlay_tree; | 
|  | 72 | int count; | 
|  | 73 | struct fragment *fragments; | 
|  | 74 | bool symbols_fragment; | 
|  | 75 | struct of_changeset cset; | 
|  | 76 | }; | 
|  | 77 |  | 
|  | 78 | /* flags are sticky - once set, do not reset */ | 
|  | 79 | static int devicetree_state_flags; | 
|  | 80 | #define DTSF_APPLY_FAIL		0x01 | 
|  | 81 | #define DTSF_REVERT_FAIL	0x02 | 
|  | 82 |  | 
|  | 83 | /* | 
|  | 84 | * If a changeset apply or revert encounters an error, an attempt will | 
|  | 85 | * be made to undo partial changes, but may fail.  If the undo fails | 
|  | 86 | * we do not know the state of the devicetree. | 
|  | 87 | */ | 
|  | 88 | static int devicetree_corrupt(void) | 
|  | 89 | { | 
|  | 90 | return devicetree_state_flags & | 
|  | 91 | (DTSF_APPLY_FAIL | DTSF_REVERT_FAIL); | 
|  | 92 | } | 
|  | 93 |  | 
|  | 94 | static int build_changeset_next_level(struct overlay_changeset *ovcs, | 
|  | 95 | struct target *target, const struct device_node *overlay_node); | 
|  | 96 |  | 
|  | 97 | /* | 
|  | 98 | * of_resolve_phandles() finds the largest phandle in the live tree. | 
|  | 99 | * of_overlay_apply() may add a larger phandle to the live tree. | 
|  | 100 | * Do not allow race between two overlays being applied simultaneously: | 
|  | 101 | *    mutex_lock(&of_overlay_phandle_mutex) | 
|  | 102 | *    of_resolve_phandles() | 
|  | 103 | *    of_overlay_apply() | 
|  | 104 | *    mutex_unlock(&of_overlay_phandle_mutex) | 
|  | 105 | */ | 
|  | 106 | static DEFINE_MUTEX(of_overlay_phandle_mutex); | 
|  | 107 |  | 
|  | 108 | void of_overlay_mutex_lock(void) | 
|  | 109 | { | 
|  | 110 | mutex_lock(&of_overlay_phandle_mutex); | 
|  | 111 | } | 
|  | 112 |  | 
|  | 113 | void of_overlay_mutex_unlock(void) | 
|  | 114 | { | 
|  | 115 | mutex_unlock(&of_overlay_phandle_mutex); | 
|  | 116 | } | 
|  | 117 |  | 
|  | 118 |  | 
|  | 119 | static LIST_HEAD(ovcs_list); | 
|  | 120 | static DEFINE_IDR(ovcs_idr); | 
|  | 121 |  | 
|  | 122 | static BLOCKING_NOTIFIER_HEAD(overlay_notify_chain); | 
|  | 123 |  | 
|  | 124 | /** | 
|  | 125 | * of_overlay_notifier_register() - Register notifier for overlay operations | 
|  | 126 | * @nb:		Notifier block to register | 
|  | 127 | * | 
|  | 128 | * Register for notification on overlay operations on device tree nodes. The | 
|  | 129 | * reported actions definied by @of_reconfig_change. The notifier callback | 
|  | 130 | * furthermore receives a pointer to the affected device tree node. | 
|  | 131 | * | 
|  | 132 | * Note that a notifier callback is not supposed to store pointers to a device | 
|  | 133 | * tree node or its content beyond @OF_OVERLAY_POST_REMOVE corresponding to the | 
|  | 134 | * respective node it received. | 
|  | 135 | */ | 
|  | 136 | int of_overlay_notifier_register(struct notifier_block *nb) | 
|  | 137 | { | 
|  | 138 | return blocking_notifier_chain_register(&overlay_notify_chain, nb); | 
|  | 139 | } | 
|  | 140 | EXPORT_SYMBOL_GPL(of_overlay_notifier_register); | 
|  | 141 |  | 
|  | 142 | /** | 
|  | 143 | * of_overlay_notifier_register() - Unregister notifier for overlay operations | 
|  | 144 | * @nb:		Notifier block to unregister | 
|  | 145 | */ | 
|  | 146 | int of_overlay_notifier_unregister(struct notifier_block *nb) | 
|  | 147 | { | 
|  | 148 | return blocking_notifier_chain_unregister(&overlay_notify_chain, nb); | 
|  | 149 | } | 
|  | 150 | EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister); | 
|  | 151 |  | 
|  | 152 | static char *of_overlay_action_name[] = { | 
|  | 153 | "pre-apply", | 
|  | 154 | "post-apply", | 
|  | 155 | "pre-remove", | 
|  | 156 | "post-remove", | 
|  | 157 | }; | 
|  | 158 |  | 
|  | 159 | static int overlay_notify(struct overlay_changeset *ovcs, | 
|  | 160 | enum of_overlay_notify_action action) | 
|  | 161 | { | 
|  | 162 | struct of_overlay_notify_data nd; | 
|  | 163 | int i, ret; | 
|  | 164 |  | 
|  | 165 | for (i = 0; i < ovcs->count; i++) { | 
|  | 166 | struct fragment *fragment = &ovcs->fragments[i]; | 
|  | 167 |  | 
|  | 168 | nd.target = fragment->target; | 
|  | 169 | nd.overlay = fragment->overlay; | 
|  | 170 |  | 
|  | 171 | ret = blocking_notifier_call_chain(&overlay_notify_chain, | 
|  | 172 | action, &nd); | 
|  | 173 | if (ret == NOTIFY_OK || ret == NOTIFY_STOP) | 
|  | 174 | return 0; | 
|  | 175 | if (ret) { | 
|  | 176 | ret = notifier_to_errno(ret); | 
|  | 177 | pr_err("overlay changeset %s notifier error %d, target: %pOF\n", | 
|  | 178 | of_overlay_action_name[action], ret, nd.target); | 
|  | 179 | return ret; | 
|  | 180 | } | 
|  | 181 | } | 
|  | 182 |  | 
|  | 183 | return 0; | 
|  | 184 | } | 
|  | 185 |  | 
|  | 186 | /* | 
|  | 187 | * The values of properties in the "/__symbols__" node are paths in | 
|  | 188 | * the ovcs->overlay_tree.  When duplicating the properties, the paths | 
|  | 189 | * need to be adjusted to be the correct path for the live device tree. | 
|  | 190 | * | 
|  | 191 | * The paths refer to a node in the subtree of a fragment node's "__overlay__" | 
|  | 192 | * node, for example "/fragment@0/__overlay__/symbol_path_tail", | 
|  | 193 | * where symbol_path_tail can be a single node or it may be a multi-node path. | 
|  | 194 | * | 
|  | 195 | * The duplicated property value will be modified by replacing the | 
|  | 196 | * "/fragment_name/__overlay/" portion of the value  with the target | 
|  | 197 | * path from the fragment node. | 
|  | 198 | */ | 
|  | 199 | static struct property *dup_and_fixup_symbol_prop( | 
|  | 200 | struct overlay_changeset *ovcs, const struct property *prop) | 
|  | 201 | { | 
|  | 202 | struct fragment *fragment; | 
|  | 203 | struct property *new_prop; | 
|  | 204 | struct device_node *fragment_node; | 
|  | 205 | struct device_node *overlay_node; | 
|  | 206 | const char *path; | 
|  | 207 | const char *path_tail; | 
|  | 208 | const char *target_path; | 
|  | 209 | int k; | 
|  | 210 | int overlay_name_len; | 
|  | 211 | int path_len; | 
|  | 212 | int path_tail_len; | 
|  | 213 | int target_path_len; | 
|  | 214 |  | 
|  | 215 | if (!prop->value) | 
|  | 216 | return NULL; | 
|  | 217 | if (strnlen(prop->value, prop->length) >= prop->length) | 
|  | 218 | return NULL; | 
|  | 219 | path = prop->value; | 
|  | 220 | path_len = strlen(path); | 
|  | 221 |  | 
|  | 222 | if (path_len < 1) | 
|  | 223 | return NULL; | 
|  | 224 | fragment_node = __of_find_node_by_path(ovcs->overlay_tree, path + 1); | 
|  | 225 | overlay_node = __of_find_node_by_path(fragment_node, "__overlay__/"); | 
|  | 226 | of_node_put(fragment_node); | 
|  | 227 | of_node_put(overlay_node); | 
|  | 228 |  | 
|  | 229 | for (k = 0; k < ovcs->count; k++) { | 
|  | 230 | fragment = &ovcs->fragments[k]; | 
|  | 231 | if (fragment->overlay == overlay_node) | 
|  | 232 | break; | 
|  | 233 | } | 
|  | 234 | if (k >= ovcs->count) | 
|  | 235 | return NULL; | 
|  | 236 |  | 
|  | 237 | overlay_name_len = snprintf(NULL, 0, "%pOF", fragment->overlay); | 
|  | 238 |  | 
|  | 239 | if (overlay_name_len > path_len) | 
|  | 240 | return NULL; | 
|  | 241 | path_tail = path + overlay_name_len; | 
|  | 242 | path_tail_len = strlen(path_tail); | 
|  | 243 |  | 
|  | 244 | target_path = kasprintf(GFP_KERNEL, "%pOF", fragment->target); | 
|  | 245 | if (!target_path) | 
|  | 246 | return NULL; | 
|  | 247 | target_path_len = strlen(target_path); | 
|  | 248 |  | 
|  | 249 | new_prop = kzalloc(sizeof(*new_prop), GFP_KERNEL); | 
|  | 250 | if (!new_prop) | 
|  | 251 | goto err_free_target_path; | 
|  | 252 |  | 
|  | 253 | new_prop->name = kstrdup(prop->name, GFP_KERNEL); | 
|  | 254 | new_prop->length = target_path_len + path_tail_len + 1; | 
|  | 255 | new_prop->value = kzalloc(new_prop->length, GFP_KERNEL); | 
|  | 256 | if (!new_prop->name || !new_prop->value) | 
|  | 257 | goto err_free_new_prop; | 
|  | 258 |  | 
|  | 259 | strcpy(new_prop->value, target_path); | 
|  | 260 | strcpy(new_prop->value + target_path_len, path_tail); | 
|  | 261 |  | 
|  | 262 | of_property_set_flag(new_prop, OF_DYNAMIC); | 
|  | 263 |  | 
|  | 264 | return new_prop; | 
|  | 265 |  | 
|  | 266 | err_free_new_prop: | 
|  | 267 | kfree(new_prop->name); | 
|  | 268 | kfree(new_prop->value); | 
|  | 269 | kfree(new_prop); | 
|  | 270 | err_free_target_path: | 
|  | 271 | kfree(target_path); | 
|  | 272 |  | 
|  | 273 | return NULL; | 
|  | 274 | } | 
|  | 275 |  | 
|  | 276 | /** | 
|  | 277 | * add_changeset_property() - add @overlay_prop to overlay changeset | 
|  | 278 | * @ovcs:		overlay changeset | 
|  | 279 | * @target:		where @overlay_prop will be placed | 
|  | 280 | * @overlay_prop:	property to add or update, from overlay tree | 
|  | 281 | * @is_symbols_prop:	1 if @overlay_prop is from node "/__symbols__" | 
|  | 282 | * | 
|  | 283 | * If @overlay_prop does not already exist in live devicetree, add changeset | 
|  | 284 | * entry to add @overlay_prop in @target, else add changeset entry to update | 
|  | 285 | * value of @overlay_prop. | 
|  | 286 | * | 
|  | 287 | * @target may be either in the live devicetree or in a new subtree that | 
|  | 288 | * is contained in the changeset. | 
|  | 289 | * | 
|  | 290 | * Some special properties are not added or updated (no error returned): | 
|  | 291 | * "name", "phandle", "linux,phandle". | 
|  | 292 | * | 
|  | 293 | * Properties "#address-cells" and "#size-cells" are not updated if they | 
|  | 294 | * are already in the live tree, but if present in the live tree, the values | 
|  | 295 | * in the overlay must match the values in the live tree. | 
|  | 296 | * | 
|  | 297 | * Update of property in symbols node is not allowed. | 
|  | 298 | * | 
|  | 299 | * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if | 
|  | 300 | * invalid @overlay. | 
|  | 301 | */ | 
|  | 302 | static int add_changeset_property(struct overlay_changeset *ovcs, | 
|  | 303 | struct target *target, struct property *overlay_prop, | 
|  | 304 | bool is_symbols_prop) | 
|  | 305 | { | 
|  | 306 | struct property *new_prop = NULL, *prop; | 
|  | 307 | int ret = 0; | 
|  | 308 |  | 
|  | 309 | if (target->in_livetree) | 
|  | 310 | if (!of_prop_cmp(overlay_prop->name, "name") || | 
|  | 311 | !of_prop_cmp(overlay_prop->name, "phandle") || | 
|  | 312 | !of_prop_cmp(overlay_prop->name, "linux,phandle")) | 
|  | 313 | return 0; | 
|  | 314 |  | 
|  | 315 | if (target->in_livetree) | 
|  | 316 | prop = of_find_property(target->np, overlay_prop->name, NULL); | 
|  | 317 | else | 
|  | 318 | prop = NULL; | 
|  | 319 |  | 
|  | 320 | if (prop) { | 
|  | 321 | if (!of_prop_cmp(prop->name, "#address-cells")) { | 
|  | 322 | if (!of_prop_val_eq(prop, overlay_prop)) { | 
|  | 323 | pr_err("ERROR: changing value of #address-cells is not allowed in %pOF\n", | 
|  | 324 | target->np); | 
|  | 325 | ret = -EINVAL; | 
|  | 326 | } | 
|  | 327 | return ret; | 
|  | 328 |  | 
|  | 329 | } else if (!of_prop_cmp(prop->name, "#size-cells")) { | 
|  | 330 | if (!of_prop_val_eq(prop, overlay_prop)) { | 
|  | 331 | pr_err("ERROR: changing value of #size-cells is not allowed in %pOF\n", | 
|  | 332 | target->np); | 
|  | 333 | ret = -EINVAL; | 
|  | 334 | } | 
|  | 335 | return ret; | 
|  | 336 | } | 
|  | 337 | } | 
|  | 338 |  | 
|  | 339 | if (is_symbols_prop) { | 
|  | 340 | if (prop) | 
|  | 341 | return -EINVAL; | 
|  | 342 | new_prop = dup_and_fixup_symbol_prop(ovcs, overlay_prop); | 
|  | 343 | } else { | 
|  | 344 | new_prop = __of_prop_dup(overlay_prop, GFP_KERNEL); | 
|  | 345 | } | 
|  | 346 |  | 
|  | 347 | if (!new_prop) | 
|  | 348 | return -ENOMEM; | 
|  | 349 |  | 
|  | 350 | if (!prop) { | 
|  | 351 | if (!target->in_livetree) { | 
|  | 352 | new_prop->next = target->np->deadprops; | 
|  | 353 | target->np->deadprops = new_prop; | 
|  | 354 | } | 
|  | 355 | ret = of_changeset_add_property(&ovcs->cset, target->np, | 
|  | 356 | new_prop); | 
|  | 357 | } else { | 
|  | 358 | ret = of_changeset_update_property(&ovcs->cset, target->np, | 
|  | 359 | new_prop); | 
|  | 360 | } | 
|  | 361 |  | 
|  | 362 | if (!of_node_check_flag(target->np, OF_OVERLAY)) | 
|  | 363 | pr_err("WARNING: memory leak will occur if overlay removed, property: %pOF/%s\n", | 
|  | 364 | target->np, new_prop->name); | 
|  | 365 |  | 
|  | 366 | if (ret) { | 
|  | 367 | kfree(new_prop->name); | 
|  | 368 | kfree(new_prop->value); | 
|  | 369 | kfree(new_prop); | 
|  | 370 | } | 
|  | 371 | return ret; | 
|  | 372 | } | 
|  | 373 |  | 
|  | 374 | /** | 
|  | 375 | * add_changeset_node() - add @node (and children) to overlay changeset | 
|  | 376 | * @ovcs:	overlay changeset | 
|  | 377 | * @target:	where @node will be placed in live tree or changeset | 
|  | 378 | * @node:	node from within overlay device tree fragment | 
|  | 379 | * | 
|  | 380 | * If @node does not already exist in @target, add changeset entry | 
|  | 381 | * to add @node in @target. | 
|  | 382 | * | 
|  | 383 | * If @node already exists in @target, and the existing node has | 
|  | 384 | * a phandle, the overlay node is not allowed to have a phandle. | 
|  | 385 | * | 
|  | 386 | * If @node has child nodes, add the children recursively via | 
|  | 387 | * build_changeset_next_level(). | 
|  | 388 | * | 
|  | 389 | * NOTE_1: A live devicetree created from a flattened device tree (FDT) will | 
|  | 390 | *       not contain the full path in node->full_name.  Thus an overlay | 
|  | 391 | *       created from an FDT also will not contain the full path in | 
|  | 392 | *       node->full_name.  However, a live devicetree created from Open | 
|  | 393 | *       Firmware may have the full path in node->full_name. | 
|  | 394 | * | 
|  | 395 | *       add_changeset_node() follows the FDT convention and does not include | 
|  | 396 | *       the full path in node->full_name.  Even though it expects the overlay | 
|  | 397 | *       to not contain the full path, it uses kbasename() to remove the | 
|  | 398 | *       full path should it exist.  It also uses kbasename() in comparisons | 
|  | 399 | *       to nodes in the live devicetree so that it can apply an overlay to | 
|  | 400 | *       a live devicetree created from Open Firmware. | 
|  | 401 | * | 
|  | 402 | * NOTE_2: Multiple mods of created nodes not supported. | 
|  | 403 | *       If more than one fragment contains a node that does not already exist | 
|  | 404 | *       in the live tree, then for each fragment of_changeset_attach_node() | 
|  | 405 | *       will add a changeset entry to add the node.  When the changeset is | 
|  | 406 | *       applied, __of_attach_node() will attach the node twice (once for | 
|  | 407 | *       each fragment).  At this point the device tree will be corrupted. | 
|  | 408 | * | 
|  | 409 | *       TODO: add integrity check to ensure that multiple fragments do not | 
|  | 410 | *             create the same node. | 
|  | 411 | * | 
|  | 412 | * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if | 
|  | 413 | * invalid @overlay. | 
|  | 414 | */ | 
|  | 415 | static int add_changeset_node(struct overlay_changeset *ovcs, | 
|  | 416 | struct target *target, struct device_node *node) | 
|  | 417 | { | 
|  | 418 | const char *node_kbasename; | 
|  | 419 | const __be32 *phandle; | 
|  | 420 | struct device_node *tchild; | 
|  | 421 | struct target target_child; | 
|  | 422 | int ret = 0, size; | 
|  | 423 |  | 
|  | 424 | node_kbasename = kbasename(node->full_name); | 
|  | 425 |  | 
|  | 426 | for_each_child_of_node(target->np, tchild) | 
|  | 427 | if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name))) | 
|  | 428 | break; | 
|  | 429 |  | 
|  | 430 | if (!tchild) { | 
|  | 431 | tchild = __of_node_dup(NULL, node_kbasename); | 
|  | 432 | if (!tchild) | 
|  | 433 | return -ENOMEM; | 
|  | 434 |  | 
|  | 435 | tchild->parent = target->np; | 
|  | 436 | tchild->name = __of_get_property(node, "name", NULL); | 
|  | 437 | tchild->type = __of_get_property(node, "device_type", NULL); | 
|  | 438 |  | 
|  | 439 | if (!tchild->name) | 
|  | 440 | tchild->name = "<NULL>"; | 
|  | 441 | if (!tchild->type) | 
|  | 442 | tchild->type = "<NULL>"; | 
|  | 443 |  | 
|  | 444 | /* ignore obsolete "linux,phandle" */ | 
|  | 445 | phandle = __of_get_property(node, "phandle", &size); | 
|  | 446 | if (phandle && (size == 4)) | 
|  | 447 | tchild->phandle = be32_to_cpup(phandle); | 
|  | 448 |  | 
|  | 449 | of_node_set_flag(tchild, OF_OVERLAY); | 
|  | 450 |  | 
|  | 451 | ret = of_changeset_attach_node(&ovcs->cset, tchild); | 
|  | 452 | if (ret) | 
|  | 453 | return ret; | 
|  | 454 |  | 
|  | 455 | target_child.np = tchild; | 
|  | 456 | target_child.in_livetree = false; | 
|  | 457 |  | 
|  | 458 | ret = build_changeset_next_level(ovcs, &target_child, node); | 
|  | 459 | of_node_put(tchild); | 
|  | 460 | return ret; | 
|  | 461 | } | 
|  | 462 |  | 
|  | 463 | if (node->phandle && tchild->phandle) { | 
|  | 464 | ret = -EINVAL; | 
|  | 465 | } else { | 
|  | 466 | target_child.np = tchild; | 
|  | 467 | target_child.in_livetree = target->in_livetree; | 
|  | 468 | ret = build_changeset_next_level(ovcs, &target_child, node); | 
|  | 469 | } | 
|  | 470 | of_node_put(tchild); | 
|  | 471 |  | 
|  | 472 | return ret; | 
|  | 473 | } | 
|  | 474 |  | 
|  | 475 | /** | 
|  | 476 | * build_changeset_next_level() - add level of overlay changeset | 
|  | 477 | * @ovcs:		overlay changeset | 
|  | 478 | * @target:		where to place @overlay_node in live tree | 
|  | 479 | * @overlay_node:	node from within an overlay device tree fragment | 
|  | 480 | * | 
|  | 481 | * Add the properties (if any) and nodes (if any) from @overlay_node to the | 
|  | 482 | * @ovcs->cset changeset.  If an added node has child nodes, they will | 
|  | 483 | * be added recursively. | 
|  | 484 | * | 
|  | 485 | * Do not allow symbols node to have any children. | 
|  | 486 | * | 
|  | 487 | * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if | 
|  | 488 | * invalid @overlay_node. | 
|  | 489 | */ | 
|  | 490 | static int build_changeset_next_level(struct overlay_changeset *ovcs, | 
|  | 491 | struct target *target, const struct device_node *overlay_node) | 
|  | 492 | { | 
|  | 493 | struct device_node *child; | 
|  | 494 | struct property *prop; | 
|  | 495 | int ret; | 
|  | 496 |  | 
|  | 497 | for_each_property_of_node(overlay_node, prop) { | 
|  | 498 | ret = add_changeset_property(ovcs, target, prop, 0); | 
|  | 499 | if (ret) { | 
|  | 500 | pr_debug("Failed to apply prop @%pOF/%s, err=%d\n", | 
|  | 501 | target->np, prop->name, ret); | 
|  | 502 | return ret; | 
|  | 503 | } | 
|  | 504 | } | 
|  | 505 |  | 
|  | 506 | for_each_child_of_node(overlay_node, child) { | 
|  | 507 | ret = add_changeset_node(ovcs, target, child); | 
|  | 508 | if (ret) { | 
|  | 509 | pr_debug("Failed to apply node @%pOF/%pOFn, err=%d\n", | 
|  | 510 | target->np, child, ret); | 
|  | 511 | of_node_put(child); | 
|  | 512 | return ret; | 
|  | 513 | } | 
|  | 514 | } | 
|  | 515 |  | 
|  | 516 | return 0; | 
|  | 517 | } | 
|  | 518 |  | 
|  | 519 | /* | 
|  | 520 | * Add the properties from __overlay__ node to the @ovcs->cset changeset. | 
|  | 521 | */ | 
|  | 522 | static int build_changeset_symbols_node(struct overlay_changeset *ovcs, | 
|  | 523 | struct target *target, | 
|  | 524 | const struct device_node *overlay_symbols_node) | 
|  | 525 | { | 
|  | 526 | struct property *prop; | 
|  | 527 | int ret; | 
|  | 528 |  | 
|  | 529 | for_each_property_of_node(overlay_symbols_node, prop) { | 
|  | 530 | ret = add_changeset_property(ovcs, target, prop, 1); | 
|  | 531 | if (ret) { | 
|  | 532 | pr_debug("Failed to apply prop @%pOF/%s, err=%d\n", | 
|  | 533 | target->np, prop->name, ret); | 
|  | 534 | return ret; | 
|  | 535 | } | 
|  | 536 | } | 
|  | 537 |  | 
|  | 538 | return 0; | 
|  | 539 | } | 
|  | 540 |  | 
|  | 541 | /** | 
|  | 542 | * build_changeset() - populate overlay changeset in @ovcs from @ovcs->fragments | 
|  | 543 | * @ovcs:	Overlay changeset | 
|  | 544 | * | 
|  | 545 | * Create changeset @ovcs->cset to contain the nodes and properties of the | 
|  | 546 | * overlay device tree fragments in @ovcs->fragments[].  If an error occurs, | 
|  | 547 | * any portions of the changeset that were successfully created will remain | 
|  | 548 | * in @ovcs->cset. | 
|  | 549 | * | 
|  | 550 | * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if | 
|  | 551 | * invalid overlay in @ovcs->fragments[]. | 
|  | 552 | */ | 
|  | 553 | static int build_changeset(struct overlay_changeset *ovcs) | 
|  | 554 | { | 
|  | 555 | struct fragment *fragment; | 
|  | 556 | struct target target; | 
|  | 557 | int fragments_count, i, ret; | 
|  | 558 |  | 
|  | 559 | /* | 
|  | 560 | * if there is a symbols fragment in ovcs->fragments[i] it is | 
|  | 561 | * the final element in the array | 
|  | 562 | */ | 
|  | 563 | if (ovcs->symbols_fragment) | 
|  | 564 | fragments_count = ovcs->count - 1; | 
|  | 565 | else | 
|  | 566 | fragments_count = ovcs->count; | 
|  | 567 |  | 
|  | 568 | for (i = 0; i < fragments_count; i++) { | 
|  | 569 | fragment = &ovcs->fragments[i]; | 
|  | 570 |  | 
|  | 571 | target.np = fragment->target; | 
|  | 572 | target.in_livetree = true; | 
|  | 573 | ret = build_changeset_next_level(ovcs, &target, | 
|  | 574 | fragment->overlay); | 
|  | 575 | if (ret) { | 
|  | 576 | pr_debug("apply failed '%pOF'\n", fragment->target); | 
|  | 577 | return ret; | 
|  | 578 | } | 
|  | 579 | } | 
|  | 580 |  | 
|  | 581 | if (ovcs->symbols_fragment) { | 
|  | 582 | fragment = &ovcs->fragments[ovcs->count - 1]; | 
|  | 583 |  | 
|  | 584 | target.np = fragment->target; | 
|  | 585 | target.in_livetree = true; | 
|  | 586 | ret = build_changeset_symbols_node(ovcs, &target, | 
|  | 587 | fragment->overlay); | 
|  | 588 | if (ret) { | 
|  | 589 | pr_debug("apply failed '%pOF'\n", fragment->target); | 
|  | 590 | return ret; | 
|  | 591 | } | 
|  | 592 | } | 
|  | 593 |  | 
|  | 594 | return 0; | 
|  | 595 | } | 
|  | 596 |  | 
|  | 597 | /* | 
|  | 598 | * Find the target node using a number of different strategies | 
|  | 599 | * in order of preference: | 
|  | 600 | * | 
|  | 601 | * 1) "target" property containing the phandle of the target | 
|  | 602 | * 2) "target-path" property containing the path of the target | 
|  | 603 | */ | 
|  | 604 | static struct device_node *find_target(struct device_node *info_node) | 
|  | 605 | { | 
|  | 606 | struct device_node *node; | 
|  | 607 | const char *path; | 
|  | 608 | u32 val; | 
|  | 609 | int ret; | 
|  | 610 |  | 
|  | 611 | ret = of_property_read_u32(info_node, "target", &val); | 
|  | 612 | if (!ret) { | 
|  | 613 | node = of_find_node_by_phandle(val); | 
|  | 614 | if (!node) | 
|  | 615 | pr_err("find target, node: %pOF, phandle 0x%x not found\n", | 
|  | 616 | info_node, val); | 
|  | 617 | return node; | 
|  | 618 | } | 
|  | 619 |  | 
|  | 620 | ret = of_property_read_string(info_node, "target-path", &path); | 
|  | 621 | if (!ret) { | 
|  | 622 | node =  of_find_node_by_path(path); | 
|  | 623 | if (!node) | 
|  | 624 | pr_err("find target, node: %pOF, path '%s' not found\n", | 
|  | 625 | info_node, path); | 
|  | 626 | return node; | 
|  | 627 | } | 
|  | 628 |  | 
|  | 629 | pr_err("find target, node: %pOF, no target property\n", info_node); | 
|  | 630 |  | 
|  | 631 | return NULL; | 
|  | 632 | } | 
|  | 633 |  | 
|  | 634 | /** | 
|  | 635 | * init_overlay_changeset() - initialize overlay changeset from overlay tree | 
|  | 636 | * @ovcs:	Overlay changeset to build | 
|  | 637 | * @fdt:	the FDT that was unflattened to create @tree | 
|  | 638 | * @tree:	Contains all the overlay fragments and overlay fixup nodes | 
|  | 639 | * | 
|  | 640 | * Initialize @ovcs.  Populate @ovcs->fragments with node information from | 
|  | 641 | * the top level of @tree.  The relevant top level nodes are the fragment | 
|  | 642 | * nodes and the __symbols__ node.  Any other top level node will be ignored. | 
|  | 643 | * | 
|  | 644 | * Returns 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error | 
|  | 645 | * detected in @tree, or -ENOSPC if idr_alloc() error. | 
|  | 646 | */ | 
|  | 647 | static int init_overlay_changeset(struct overlay_changeset *ovcs, | 
|  | 648 | const void *fdt, struct device_node *tree) | 
|  | 649 | { | 
|  | 650 | struct device_node *node, *overlay_node; | 
|  | 651 | struct fragment *fragment; | 
|  | 652 | struct fragment *fragments; | 
|  | 653 | int cnt, id, ret; | 
|  | 654 |  | 
|  | 655 | /* | 
|  | 656 | * Warn for some issues.  Can not return -EINVAL for these until | 
|  | 657 | * of_unittest_apply_overlay() is fixed to pass these checks. | 
|  | 658 | */ | 
|  | 659 | if (!of_node_check_flag(tree, OF_DYNAMIC)) | 
|  | 660 | pr_debug("%s() tree is not dynamic\n", __func__); | 
|  | 661 |  | 
|  | 662 | if (!of_node_check_flag(tree, OF_DETACHED)) | 
|  | 663 | pr_debug("%s() tree is not detached\n", __func__); | 
|  | 664 |  | 
|  | 665 | if (!of_node_is_root(tree)) | 
|  | 666 | pr_debug("%s() tree is not root\n", __func__); | 
|  | 667 |  | 
|  | 668 | ovcs->overlay_tree = tree; | 
|  | 669 | ovcs->fdt = fdt; | 
|  | 670 |  | 
|  | 671 | INIT_LIST_HEAD(&ovcs->ovcs_list); | 
|  | 672 |  | 
|  | 673 | of_changeset_init(&ovcs->cset); | 
|  | 674 |  | 
|  | 675 | id = idr_alloc(&ovcs_idr, ovcs, 1, 0, GFP_KERNEL); | 
|  | 676 | if (id <= 0) | 
|  | 677 | return id; | 
|  | 678 |  | 
|  | 679 | cnt = 0; | 
|  | 680 |  | 
|  | 681 | /* fragment nodes */ | 
|  | 682 | for_each_child_of_node(tree, node) { | 
|  | 683 | overlay_node = of_get_child_by_name(node, "__overlay__"); | 
|  | 684 | if (overlay_node) { | 
|  | 685 | cnt++; | 
|  | 686 | of_node_put(overlay_node); | 
|  | 687 | } | 
|  | 688 | } | 
|  | 689 |  | 
|  | 690 | node = of_get_child_by_name(tree, "__symbols__"); | 
|  | 691 | if (node) { | 
|  | 692 | cnt++; | 
|  | 693 | of_node_put(node); | 
|  | 694 | } | 
|  | 695 |  | 
|  | 696 | fragments = kcalloc(cnt, sizeof(*fragments), GFP_KERNEL); | 
|  | 697 | if (!fragments) { | 
|  | 698 | ret = -ENOMEM; | 
|  | 699 | goto err_free_idr; | 
|  | 700 | } | 
|  | 701 |  | 
|  | 702 | cnt = 0; | 
|  | 703 | for_each_child_of_node(tree, node) { | 
|  | 704 | overlay_node = of_get_child_by_name(node, "__overlay__"); | 
|  | 705 | if (!overlay_node) | 
|  | 706 | continue; | 
|  | 707 |  | 
|  | 708 | fragment = &fragments[cnt]; | 
|  | 709 | fragment->overlay = overlay_node; | 
|  | 710 | fragment->target = find_target(node); | 
|  | 711 | if (!fragment->target) { | 
|  | 712 | of_node_put(fragment->overlay); | 
|  | 713 | ret = -EINVAL; | 
|  | 714 | goto err_free_fragments; | 
|  | 715 | } | 
|  | 716 |  | 
|  | 717 | cnt++; | 
|  | 718 | } | 
|  | 719 |  | 
|  | 720 | /* | 
|  | 721 | * if there is a symbols fragment in ovcs->fragments[i] it is | 
|  | 722 | * the final element in the array | 
|  | 723 | */ | 
|  | 724 | node = of_get_child_by_name(tree, "__symbols__"); | 
|  | 725 | if (node) { | 
|  | 726 | ovcs->symbols_fragment = 1; | 
|  | 727 | fragment = &fragments[cnt]; | 
|  | 728 | fragment->overlay = node; | 
|  | 729 | fragment->target = of_find_node_by_path("/__symbols__"); | 
|  | 730 |  | 
|  | 731 | if (!fragment->target) { | 
|  | 732 | pr_err("symbols in overlay, but not in live tree\n"); | 
|  | 733 | ret = -EINVAL; | 
|  | 734 | goto err_free_fragments; | 
|  | 735 | } | 
|  | 736 |  | 
|  | 737 | cnt++; | 
|  | 738 | } | 
|  | 739 |  | 
|  | 740 | if (!cnt) { | 
|  | 741 | pr_err("no fragments or symbols in overlay\n"); | 
|  | 742 | ret = -EINVAL; | 
|  | 743 | goto err_free_fragments; | 
|  | 744 | } | 
|  | 745 |  | 
|  | 746 | ovcs->id = id; | 
|  | 747 | ovcs->count = cnt; | 
|  | 748 | ovcs->fragments = fragments; | 
|  | 749 |  | 
|  | 750 | return 0; | 
|  | 751 |  | 
|  | 752 | err_free_fragments: | 
|  | 753 | kfree(fragments); | 
|  | 754 | err_free_idr: | 
|  | 755 | idr_remove(&ovcs_idr, id); | 
|  | 756 |  | 
|  | 757 | pr_err("%s() failed, ret = %d\n", __func__, ret); | 
|  | 758 |  | 
|  | 759 | return ret; | 
|  | 760 | } | 
|  | 761 |  | 
|  | 762 | static void free_overlay_changeset(struct overlay_changeset *ovcs) | 
|  | 763 | { | 
|  | 764 | int i; | 
|  | 765 |  | 
|  | 766 | if (ovcs->cset.entries.next) | 
|  | 767 | of_changeset_destroy(&ovcs->cset); | 
|  | 768 |  | 
|  | 769 | if (ovcs->id) | 
|  | 770 | idr_remove(&ovcs_idr, ovcs->id); | 
|  | 771 |  | 
|  | 772 | for (i = 0; i < ovcs->count; i++) { | 
|  | 773 | of_node_put(ovcs->fragments[i].target); | 
|  | 774 | of_node_put(ovcs->fragments[i].overlay); | 
|  | 775 | } | 
|  | 776 | kfree(ovcs->fragments); | 
|  | 777 | /* | 
|  | 778 | * There should be no live pointers into ovcs->overlay_tree and | 
|  | 779 | * ovcs->fdt due to the policy that overlay notifiers are not allowed | 
|  | 780 | * to retain pointers into the overlay devicetree. | 
|  | 781 | */ | 
|  | 782 | kfree(ovcs->overlay_tree); | 
|  | 783 | kfree(ovcs->fdt); | 
|  | 784 | kfree(ovcs); | 
|  | 785 | } | 
|  | 786 |  | 
|  | 787 | /* | 
|  | 788 | * internal documentation | 
|  | 789 | * | 
|  | 790 | * of_overlay_apply() - Create and apply an overlay changeset | 
|  | 791 | * @fdt:	the FDT that was unflattened to create @tree | 
|  | 792 | * @tree:	Expanded overlay device tree | 
|  | 793 | * @ovcs_id:	Pointer to overlay changeset id | 
|  | 794 | * | 
|  | 795 | * Creates and applies an overlay changeset. | 
|  | 796 | * | 
|  | 797 | * If an error occurs in a pre-apply notifier, then no changes are made | 
|  | 798 | * to the device tree. | 
|  | 799 | * | 
|  | 800 |  | 
|  | 801 | * A non-zero return value will not have created the changeset if error is from: | 
|  | 802 | *   - parameter checks | 
|  | 803 | *   - building the changeset | 
|  | 804 | *   - overlay changeset pre-apply notifier | 
|  | 805 | * | 
|  | 806 | * If an error is returned by an overlay changeset pre-apply notifier | 
|  | 807 | * then no further overlay changeset pre-apply notifier will be called. | 
|  | 808 | * | 
|  | 809 | * A non-zero return value will have created the changeset if error is from: | 
|  | 810 | *   - overlay changeset entry notifier | 
|  | 811 | *   - overlay changeset post-apply notifier | 
|  | 812 | * | 
|  | 813 | * If an error is returned by an overlay changeset post-apply notifier | 
|  | 814 | * then no further overlay changeset post-apply notifier will be called. | 
|  | 815 | * | 
|  | 816 | * If more than one notifier returns an error, then the last notifier | 
|  | 817 | * error to occur is returned. | 
|  | 818 | * | 
|  | 819 | * If an error occurred while applying the overlay changeset, then an | 
|  | 820 | * attempt is made to revert any changes that were made to the | 
|  | 821 | * device tree.  If there were any errors during the revert attempt | 
|  | 822 | * then the state of the device tree can not be determined, and any | 
|  | 823 | * following attempt to apply or remove an overlay changeset will be | 
|  | 824 | * refused. | 
|  | 825 | * | 
|  | 826 | * Returns 0 on success, or a negative error number.  Overlay changeset | 
|  | 827 | * id is returned to *ovcs_id. | 
|  | 828 | */ | 
|  | 829 |  | 
|  | 830 | static int of_overlay_apply(const void *fdt, struct device_node *tree, | 
|  | 831 | int *ovcs_id) | 
|  | 832 | { | 
|  | 833 | struct overlay_changeset *ovcs; | 
|  | 834 | int ret = 0, ret_revert, ret_tmp; | 
|  | 835 |  | 
|  | 836 | /* | 
|  | 837 | * As of this point, fdt and tree belong to the overlay changeset. | 
|  | 838 | * overlay changeset code is responsible for freeing them. | 
|  | 839 | */ | 
|  | 840 |  | 
|  | 841 | if (devicetree_corrupt()) { | 
|  | 842 | pr_err("devicetree state suspect, refuse to apply overlay\n"); | 
|  | 843 | kfree(fdt); | 
|  | 844 | kfree(tree); | 
|  | 845 | ret = -EBUSY; | 
|  | 846 | goto out; | 
|  | 847 | } | 
|  | 848 |  | 
|  | 849 | ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL); | 
|  | 850 | if (!ovcs) { | 
|  | 851 | kfree(fdt); | 
|  | 852 | kfree(tree); | 
|  | 853 | ret = -ENOMEM; | 
|  | 854 | goto out; | 
|  | 855 | } | 
|  | 856 |  | 
|  | 857 | of_overlay_mutex_lock(); | 
|  | 858 | mutex_lock(&of_mutex); | 
|  | 859 |  | 
|  | 860 | ret = of_resolve_phandles(tree); | 
|  | 861 | if (ret) | 
|  | 862 | goto err_free_tree; | 
|  | 863 |  | 
|  | 864 | ret = init_overlay_changeset(ovcs, fdt, tree); | 
|  | 865 | if (ret) | 
|  | 866 | goto err_free_tree; | 
|  | 867 |  | 
|  | 868 | /* | 
|  | 869 | * after overlay_notify(), ovcs->overlay_tree related pointers may have | 
|  | 870 | * leaked to drivers, so can not kfree() tree, aka ovcs->overlay_tree; | 
|  | 871 | * and can not free fdt, aka ovcs->fdt | 
|  | 872 | */ | 
|  | 873 | ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY); | 
|  | 874 | if (ret) { | 
|  | 875 | pr_err("overlay changeset pre-apply notify error %d\n", ret); | 
|  | 876 | goto err_free_overlay_changeset; | 
|  | 877 | } | 
|  | 878 |  | 
|  | 879 | ret = build_changeset(ovcs); | 
|  | 880 | if (ret) | 
|  | 881 | goto err_free_overlay_changeset; | 
|  | 882 |  | 
|  | 883 | ret_revert = 0; | 
|  | 884 | ret = __of_changeset_apply_entries(&ovcs->cset, &ret_revert); | 
|  | 885 | if (ret) { | 
|  | 886 | if (ret_revert) { | 
|  | 887 | pr_debug("overlay changeset revert error %d\n", | 
|  | 888 | ret_revert); | 
|  | 889 | devicetree_state_flags |= DTSF_APPLY_FAIL; | 
|  | 890 | } | 
|  | 891 | goto err_free_overlay_changeset; | 
|  | 892 | } | 
|  | 893 |  | 
|  | 894 | of_populate_phandle_cache(); | 
|  | 895 |  | 
|  | 896 | ret = __of_changeset_apply_notify(&ovcs->cset); | 
|  | 897 | if (ret) | 
|  | 898 | pr_err("overlay changeset entry notify error %d\n", ret); | 
|  | 899 | /* notify failure is not fatal, continue */ | 
|  | 900 |  | 
|  | 901 | list_add_tail(&ovcs->ovcs_list, &ovcs_list); | 
|  | 902 | *ovcs_id = ovcs->id; | 
|  | 903 |  | 
|  | 904 | ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_APPLY); | 
|  | 905 | if (ret_tmp) { | 
|  | 906 | pr_err("overlay changeset post-apply notify error %d\n", | 
|  | 907 | ret_tmp); | 
|  | 908 | if (!ret) | 
|  | 909 | ret = ret_tmp; | 
|  | 910 | } | 
|  | 911 |  | 
|  | 912 | goto out_unlock; | 
|  | 913 |  | 
|  | 914 | err_free_tree: | 
|  | 915 | kfree(fdt); | 
|  | 916 | kfree(tree); | 
|  | 917 |  | 
|  | 918 | err_free_overlay_changeset: | 
|  | 919 | free_overlay_changeset(ovcs); | 
|  | 920 |  | 
|  | 921 | out_unlock: | 
|  | 922 | mutex_unlock(&of_mutex); | 
|  | 923 | of_overlay_mutex_unlock(); | 
|  | 924 |  | 
|  | 925 | out: | 
|  | 926 | pr_debug("%s() err=%d\n", __func__, ret); | 
|  | 927 |  | 
|  | 928 | return ret; | 
|  | 929 | } | 
|  | 930 |  | 
|  | 931 | int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size, | 
|  | 932 | int *ovcs_id) | 
|  | 933 | { | 
|  | 934 | const void *new_fdt; | 
|  | 935 | int ret; | 
|  | 936 | u32 size; | 
|  | 937 | struct device_node *overlay_root; | 
|  | 938 |  | 
|  | 939 | *ovcs_id = 0; | 
|  | 940 | ret = 0; | 
|  | 941 |  | 
|  | 942 | if (overlay_fdt_size < sizeof(struct fdt_header) || | 
|  | 943 | fdt_check_header(overlay_fdt)) { | 
|  | 944 | pr_err("Invalid overlay_fdt header\n"); | 
|  | 945 | return -EINVAL; | 
|  | 946 | } | 
|  | 947 |  | 
|  | 948 | size = fdt_totalsize(overlay_fdt); | 
|  | 949 | if (overlay_fdt_size < size) | 
|  | 950 | return -EINVAL; | 
|  | 951 |  | 
|  | 952 | /* | 
|  | 953 | * Must create permanent copy of FDT because of_fdt_unflatten_tree() | 
|  | 954 | * will create pointers to the passed in FDT in the unflattened tree. | 
|  | 955 | */ | 
|  | 956 | new_fdt = kmemdup(overlay_fdt, size, GFP_KERNEL); | 
|  | 957 | if (!new_fdt) | 
|  | 958 | return -ENOMEM; | 
|  | 959 |  | 
|  | 960 | of_fdt_unflatten_tree(new_fdt, NULL, &overlay_root); | 
|  | 961 | if (!overlay_root) { | 
|  | 962 | pr_err("unable to unflatten overlay_fdt\n"); | 
|  | 963 | ret = -EINVAL; | 
|  | 964 | goto out_free_new_fdt; | 
|  | 965 | } | 
|  | 966 |  | 
|  | 967 | ret = of_overlay_apply(new_fdt, overlay_root, ovcs_id); | 
|  | 968 | if (ret < 0) { | 
|  | 969 | /* | 
|  | 970 | * new_fdt and overlay_root now belong to the overlay | 
|  | 971 | * changeset. | 
|  | 972 | * overlay changeset code is responsible for freeing them. | 
|  | 973 | */ | 
|  | 974 | goto out; | 
|  | 975 | } | 
|  | 976 |  | 
|  | 977 | return 0; | 
|  | 978 |  | 
|  | 979 |  | 
|  | 980 | out_free_new_fdt: | 
|  | 981 | kfree(new_fdt); | 
|  | 982 |  | 
|  | 983 | out: | 
|  | 984 | return ret; | 
|  | 985 | } | 
|  | 986 | EXPORT_SYMBOL_GPL(of_overlay_fdt_apply); | 
|  | 987 |  | 
|  | 988 | /* | 
|  | 989 | * Find @np in @tree. | 
|  | 990 | * | 
|  | 991 | * Returns 1 if @np is @tree or is contained in @tree, else 0 | 
|  | 992 | */ | 
|  | 993 | static int find_node(struct device_node *tree, struct device_node *np) | 
|  | 994 | { | 
|  | 995 | struct device_node *child; | 
|  | 996 |  | 
|  | 997 | if (tree == np) | 
|  | 998 | return 1; | 
|  | 999 |  | 
|  | 1000 | for_each_child_of_node(tree, child) { | 
|  | 1001 | if (find_node(child, np)) { | 
|  | 1002 | of_node_put(child); | 
|  | 1003 | return 1; | 
|  | 1004 | } | 
|  | 1005 | } | 
|  | 1006 |  | 
|  | 1007 | return 0; | 
|  | 1008 | } | 
|  | 1009 |  | 
|  | 1010 | /* | 
|  | 1011 | * Is @remove_ce_node a child of, a parent of, or the same as any | 
|  | 1012 | * node in an overlay changeset more topmost than @remove_ovcs? | 
|  | 1013 | * | 
|  | 1014 | * Returns 1 if found, else 0 | 
|  | 1015 | */ | 
|  | 1016 | static int node_overlaps_later_cs(struct overlay_changeset *remove_ovcs, | 
|  | 1017 | struct device_node *remove_ce_node) | 
|  | 1018 | { | 
|  | 1019 | struct overlay_changeset *ovcs; | 
|  | 1020 | struct of_changeset_entry *ce; | 
|  | 1021 |  | 
|  | 1022 | list_for_each_entry_reverse(ovcs, &ovcs_list, ovcs_list) { | 
|  | 1023 | if (ovcs == remove_ovcs) | 
|  | 1024 | break; | 
|  | 1025 |  | 
|  | 1026 | list_for_each_entry(ce, &ovcs->cset.entries, node) { | 
|  | 1027 | if (find_node(ce->np, remove_ce_node)) { | 
|  | 1028 | pr_err("%s: #%d overlaps with #%d @%pOF\n", | 
|  | 1029 | __func__, remove_ovcs->id, ovcs->id, | 
|  | 1030 | remove_ce_node); | 
|  | 1031 | return 1; | 
|  | 1032 | } | 
|  | 1033 | if (find_node(remove_ce_node, ce->np)) { | 
|  | 1034 | pr_err("%s: #%d overlaps with #%d @%pOF\n", | 
|  | 1035 | __func__, remove_ovcs->id, ovcs->id, | 
|  | 1036 | remove_ce_node); | 
|  | 1037 | return 1; | 
|  | 1038 | } | 
|  | 1039 | } | 
|  | 1040 | } | 
|  | 1041 |  | 
|  | 1042 | return 0; | 
|  | 1043 | } | 
|  | 1044 |  | 
|  | 1045 | /* | 
|  | 1046 | * We can safely remove the overlay only if it's the top-most one. | 
|  | 1047 | * Newly applied overlays are inserted at the tail of the overlay list, | 
|  | 1048 | * so a top most overlay is the one that is closest to the tail. | 
|  | 1049 | * | 
|  | 1050 | * The topmost check is done by exploiting this property. For each | 
|  | 1051 | * affected device node in the log list we check if this overlay is | 
|  | 1052 | * the one closest to the tail. If another overlay has affected this | 
|  | 1053 | * device node and is closest to the tail, then removal is not permited. | 
|  | 1054 | */ | 
|  | 1055 | static int overlay_removal_is_ok(struct overlay_changeset *remove_ovcs) | 
|  | 1056 | { | 
|  | 1057 | struct of_changeset_entry *remove_ce; | 
|  | 1058 |  | 
|  | 1059 | list_for_each_entry(remove_ce, &remove_ovcs->cset.entries, node) { | 
|  | 1060 | if (node_overlaps_later_cs(remove_ovcs, remove_ce->np)) { | 
|  | 1061 | pr_err("overlay #%d is not topmost\n", remove_ovcs->id); | 
|  | 1062 | return 0; | 
|  | 1063 | } | 
|  | 1064 | } | 
|  | 1065 |  | 
|  | 1066 | return 1; | 
|  | 1067 | } | 
|  | 1068 |  | 
|  | 1069 | /** | 
|  | 1070 | * of_overlay_remove() - Revert and free an overlay changeset | 
|  | 1071 | * @ovcs_id:	Pointer to overlay changeset id | 
|  | 1072 | * | 
|  | 1073 | * Removes an overlay if it is permissible.  @ovcs_id was previously returned | 
|  | 1074 | * by of_overlay_fdt_apply(). | 
|  | 1075 | * | 
|  | 1076 | * If an error occurred while attempting to revert the overlay changeset, | 
|  | 1077 | * then an attempt is made to re-apply any changeset entry that was | 
|  | 1078 | * reverted.  If an error occurs on re-apply then the state of the device | 
|  | 1079 | * tree can not be determined, and any following attempt to apply or remove | 
|  | 1080 | * an overlay changeset will be refused. | 
|  | 1081 | * | 
|  | 1082 | * A non-zero return value will not revert the changeset if error is from: | 
|  | 1083 | *   - parameter checks | 
|  | 1084 | *   - overlay changeset pre-remove notifier | 
|  | 1085 | *   - overlay changeset entry revert | 
|  | 1086 | * | 
|  | 1087 | * If an error is returned by an overlay changeset pre-remove notifier | 
|  | 1088 | * then no further overlay changeset pre-remove notifier will be called. | 
|  | 1089 | * | 
|  | 1090 | * If more than one notifier returns an error, then the last notifier | 
|  | 1091 | * error to occur is returned. | 
|  | 1092 | * | 
|  | 1093 | * A non-zero return value will revert the changeset if error is from: | 
|  | 1094 | *   - overlay changeset entry notifier | 
|  | 1095 | *   - overlay changeset post-remove notifier | 
|  | 1096 | * | 
|  | 1097 | * If an error is returned by an overlay changeset post-remove notifier | 
|  | 1098 | * then no further overlay changeset post-remove notifier will be called. | 
|  | 1099 | * | 
|  | 1100 | * Returns 0 on success, or a negative error number.  *ovcs_id is set to | 
|  | 1101 | * zero after reverting the changeset, even if a subsequent error occurs. | 
|  | 1102 | */ | 
|  | 1103 | int of_overlay_remove(int *ovcs_id) | 
|  | 1104 | { | 
|  | 1105 | struct overlay_changeset *ovcs; | 
|  | 1106 | int ret, ret_apply, ret_tmp; | 
|  | 1107 |  | 
|  | 1108 | ret = 0; | 
|  | 1109 |  | 
|  | 1110 | if (devicetree_corrupt()) { | 
|  | 1111 | pr_err("suspect devicetree state, refuse to remove overlay\n"); | 
|  | 1112 | ret = -EBUSY; | 
|  | 1113 | goto out; | 
|  | 1114 | } | 
|  | 1115 |  | 
|  | 1116 | mutex_lock(&of_mutex); | 
|  | 1117 |  | 
|  | 1118 | ovcs = idr_find(&ovcs_idr, *ovcs_id); | 
|  | 1119 | if (!ovcs) { | 
|  | 1120 | ret = -ENODEV; | 
|  | 1121 | pr_err("remove: Could not find overlay #%d\n", *ovcs_id); | 
|  | 1122 | goto out_unlock; | 
|  | 1123 | } | 
|  | 1124 |  | 
|  | 1125 | if (!overlay_removal_is_ok(ovcs)) { | 
|  | 1126 | ret = -EBUSY; | 
|  | 1127 | goto out_unlock; | 
|  | 1128 | } | 
|  | 1129 |  | 
|  | 1130 | ret = overlay_notify(ovcs, OF_OVERLAY_PRE_REMOVE); | 
|  | 1131 | if (ret) { | 
|  | 1132 | pr_err("overlay changeset pre-remove notify error %d\n", ret); | 
|  | 1133 | goto out_unlock; | 
|  | 1134 | } | 
|  | 1135 |  | 
|  | 1136 | list_del(&ovcs->ovcs_list); | 
|  | 1137 |  | 
|  | 1138 | /* | 
|  | 1139 | * Disable phandle cache.  Avoids race condition that would arise | 
|  | 1140 | * from removing cache entry when the associated node is deleted. | 
|  | 1141 | */ | 
|  | 1142 | of_free_phandle_cache(); | 
|  | 1143 |  | 
|  | 1144 | ret_apply = 0; | 
|  | 1145 | ret = __of_changeset_revert_entries(&ovcs->cset, &ret_apply); | 
|  | 1146 |  | 
|  | 1147 | of_populate_phandle_cache(); | 
|  | 1148 |  | 
|  | 1149 | if (ret) { | 
|  | 1150 | if (ret_apply) | 
|  | 1151 | devicetree_state_flags |= DTSF_REVERT_FAIL; | 
|  | 1152 | goto out_unlock; | 
|  | 1153 | } | 
|  | 1154 |  | 
|  | 1155 | ret = __of_changeset_revert_notify(&ovcs->cset); | 
|  | 1156 | if (ret) | 
|  | 1157 | pr_err("overlay changeset entry notify error %d\n", ret); | 
|  | 1158 | /* notify failure is not fatal, continue */ | 
|  | 1159 |  | 
|  | 1160 | *ovcs_id = 0; | 
|  | 1161 |  | 
|  | 1162 | ret_tmp = overlay_notify(ovcs, OF_OVERLAY_POST_REMOVE); | 
|  | 1163 | if (ret_tmp) { | 
|  | 1164 | pr_err("overlay changeset post-remove notify error %d\n", | 
|  | 1165 | ret_tmp); | 
|  | 1166 | if (!ret) | 
|  | 1167 | ret = ret_tmp; | 
|  | 1168 | } | 
|  | 1169 |  | 
|  | 1170 | free_overlay_changeset(ovcs); | 
|  | 1171 |  | 
|  | 1172 | out_unlock: | 
|  | 1173 | mutex_unlock(&of_mutex); | 
|  | 1174 |  | 
|  | 1175 | out: | 
|  | 1176 | pr_debug("%s() err=%d\n", __func__, ret); | 
|  | 1177 |  | 
|  | 1178 | return ret; | 
|  | 1179 | } | 
|  | 1180 | EXPORT_SYMBOL_GPL(of_overlay_remove); | 
|  | 1181 |  | 
|  | 1182 | /** | 
|  | 1183 | * of_overlay_remove_all() - Reverts and frees all overlay changesets | 
|  | 1184 | * | 
|  | 1185 | * Removes all overlays from the system in the correct order. | 
|  | 1186 | * | 
|  | 1187 | * Returns 0 on success, or a negative error number | 
|  | 1188 | */ | 
|  | 1189 | int of_overlay_remove_all(void) | 
|  | 1190 | { | 
|  | 1191 | struct overlay_changeset *ovcs, *ovcs_n; | 
|  | 1192 | int ret; | 
|  | 1193 |  | 
|  | 1194 | /* the tail of list is guaranteed to be safe to remove */ | 
|  | 1195 | list_for_each_entry_safe_reverse(ovcs, ovcs_n, &ovcs_list, ovcs_list) { | 
|  | 1196 | ret = of_overlay_remove(&ovcs->id); | 
|  | 1197 | if (ret) | 
|  | 1198 | return ret; | 
|  | 1199 | } | 
|  | 1200 |  | 
|  | 1201 | return 0; | 
|  | 1202 | } | 
|  | 1203 | EXPORT_SYMBOL_GPL(of_overlay_remove_all); |