of: overlay: minor restructuring
[linux-block.git] / drivers / of / overlay.c
CommitLineData
7518b589
PA
1/*
2 * Functions for working with device tree overlays
3 *
4 * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
5 * Copyright (C) 2012 Texas Instruments Inc.
6 *
7 * This program is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU General Public License
9 * version 2 as published by the Free Software Foundation.
10 */
606ad42a
RH
11
12#define pr_fmt(fmt) "OF: overlay: " fmt
13
7518b589
PA
14#include <linux/kernel.h>
15#include <linux/module.h>
16#include <linux/of.h>
17#include <linux/of_device.h>
18#include <linux/string.h>
19#include <linux/ctype.h>
20#include <linux/errno.h>
7518b589
PA
21#include <linux/slab.h>
22#include <linux/err.h>
0d1886df 23#include <linux/idr.h>
7518b589
PA
24
25#include "of_private.h"
26
27/**
0290c4ca 28 * struct fragment - info about fragment nodes in overlay expanded device tree
7518b589 29 * @target: target of the overlay operation
0290c4ca 30 * @overlay: pointer to the __overlay__ node
7518b589 31 */
0290c4ca 32struct fragment {
7518b589
PA
33 struct device_node *target;
34 struct device_node *overlay;
d1651b03 35 bool is_symbols_node;
7518b589
PA
36};
37
38/**
0290c4ca
FR
39 * struct overlay_changeset
40 * @ovcs_list: list on which we are located
41 * @count: count of @fragments structures
42 * @fragments: info about fragment nodes in overlay expanded device tree
43 * @cset: changeset to apply fragments to live device tree
7518b589 44 */
0290c4ca 45struct overlay_changeset {
7518b589 46 int id;
0290c4ca 47 struct list_head ovcs_list;
7518b589 48 int count;
0290c4ca 49 struct fragment *fragments;
7518b589
PA
50 struct of_changeset cset;
51};
52
0290c4ca
FR
53static int build_changeset_next_level(struct overlay_changeset *ovcs,
54 struct device_node *target_node,
55 const struct device_node *overlay_node,
d1651b03 56 bool is_symbols_node);
7518b589 57
61b4de4e
FR
58static LIST_HEAD(ovcs_list);
59static DEFINE_IDR(ovcs_idr);
60
0290c4ca 61static BLOCKING_NOTIFIER_HEAD(overlay_notify_chain);
39a842e2
AT
62
63int of_overlay_notifier_register(struct notifier_block *nb)
64{
0290c4ca 65 return blocking_notifier_chain_register(&overlay_notify_chain, nb);
39a842e2
AT
66}
67EXPORT_SYMBOL_GPL(of_overlay_notifier_register);
68
69int of_overlay_notifier_unregister(struct notifier_block *nb)
70{
0290c4ca 71 return blocking_notifier_chain_unregister(&overlay_notify_chain, nb);
39a842e2
AT
72}
73EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister);
74
0290c4ca
FR
75static int overlay_notify(struct overlay_changeset *ovcs,
76 enum of_overlay_notify_action action)
39a842e2
AT
77{
78 struct of_overlay_notify_data nd;
79 int i, ret;
80
0290c4ca
FR
81 for (i = 0; i < ovcs->count; i++) {
82 struct fragment *fragment = &ovcs->fragments[i];
39a842e2 83
0290c4ca
FR
84 nd.target = fragment->target;
85 nd.overlay = fragment->overlay;
39a842e2 86
0290c4ca 87 ret = blocking_notifier_call_chain(&overlay_notify_chain,
39a842e2
AT
88 action, &nd);
89 if (ret)
90 return notifier_to_errno(ret);
91 }
92
93 return 0;
94}
95
42b2e94f
FR
96/*
97 * The properties in the "/__symbols__" node are "symbols".
98 *
99 * The value of properties in the "/__symbols__" node is the path of a
100 * node in the subtree of a fragment node's "__overlay__" node, for
101 * example "/fragment@0/__overlay__/symbol_path_tail". Symbol_path_tail
102 * can be a single node or it may be a multi-node path.
103 *
104 * The duplicated property value will be modified by replacing the
105 * "/fragment_name/__overlay/" portion of the value with the target
106 * path from the fragment node.
107 */
0290c4ca
FR
108static struct property *dup_and_fixup_symbol_prop(
109 struct overlay_changeset *ovcs, const struct property *prop)
d1651b03 110{
0290c4ca 111 struct fragment *fragment;
d1651b03
FR
112 struct property *new;
113 const char *overlay_name;
42b2e94f 114 char *symbol_path_tail;
d1651b03
FR
115 char *symbol_path;
116 const char *target_path;
117 int k;
42b2e94f 118 int symbol_path_tail_len;
d1651b03
FR
119 int overlay_name_len;
120 int target_path_len;
121
122 if (!prop->value)
123 return NULL;
124 symbol_path = prop->value;
125
126 new = kzalloc(sizeof(*new), GFP_KERNEL);
127 if (!new)
128 return NULL;
129
0290c4ca
FR
130 for (k = 0; k < ovcs->count; k++) {
131 fragment = &ovcs->fragments[k];
132 overlay_name = fragment->overlay->full_name;
d1651b03
FR
133 overlay_name_len = strlen(overlay_name);
134 if (!strncasecmp(symbol_path, overlay_name, overlay_name_len))
135 break;
136 }
137
0290c4ca 138 if (k >= ovcs->count)
d1651b03
FR
139 goto err_free;
140
0290c4ca 141 target_path = fragment->target->full_name;
d1651b03
FR
142 target_path_len = strlen(target_path);
143
42b2e94f
FR
144 symbol_path_tail = symbol_path + overlay_name_len;
145 symbol_path_tail_len = strlen(symbol_path_tail);
d1651b03
FR
146
147 new->name = kstrdup(prop->name, GFP_KERNEL);
42b2e94f 148 new->length = target_path_len + symbol_path_tail_len + 1;
d1651b03
FR
149 new->value = kzalloc(new->length, GFP_KERNEL);
150
151 if (!new->name || !new->value)
152 goto err_free;
153
154 strcpy(new->value, target_path);
42b2e94f 155 strcpy(new->value + target_path_len, symbol_path_tail);
d1651b03 156
d1651b03
FR
157 of_property_set_flag(new, OF_DYNAMIC);
158
159 return new;
160
161 err_free:
162 kfree(new->name);
163 kfree(new->value);
164 kfree(new);
165 return NULL;
d1651b03
FR
166}
167
0290c4ca
FR
168/**
169 * add_changeset_property() - add @overlay_prop to overlay changeset
170 * @ovcs: overlay changeset
171 * @target_node: where to place @overlay_prop in live tree
172 * @overlay_prop: property to add or update, from overlay tree
173 * is_symbols_node: 1 if @target_node is "/__symbols__"
174 *
175 * If @overlay_prop does not already exist in @target_node, add changeset entry
176 * to add @overlay_prop in @target_node, else add changeset entry to update
177 * value of @overlay_prop.
178 *
646afc4a 179 * Some special properties are not updated (no error returned).
0290c4ca 180 *
646afc4a 181 * Update of property in symbols node is not allowed.
0290c4ca
FR
182 *
183 * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
184 * invalid @overlay.
646afc4a 185 */
0290c4ca
FR
186static int add_changeset_property(struct overlay_changeset *ovcs,
187 struct device_node *target_node,
188 struct property *overlay_prop,
d1651b03 189 bool is_symbols_node)
7518b589 190{
0290c4ca 191 struct property *new_prop = NULL, *prop;
ac0f3e30 192 int ret = 0;
7518b589 193
0290c4ca 194 prop = of_find_property(target_node, overlay_prop->name, NULL);
7518b589 195
0290c4ca
FR
196 if (!of_prop_cmp(overlay_prop->name, "name") ||
197 !of_prop_cmp(overlay_prop->name, "phandle") ||
198 !of_prop_cmp(overlay_prop->name, "linux,phandle"))
7518b589
PA
199 return 0;
200
d1651b03 201 if (is_symbols_node) {
0290c4ca 202 if (prop)
d1651b03 203 return -EINVAL;
0290c4ca 204 new_prop = dup_and_fixup_symbol_prop(ovcs, overlay_prop);
d1651b03 205 } else {
0290c4ca 206 new_prop = __of_prop_dup(overlay_prop, GFP_KERNEL);
d1651b03
FR
207 }
208
0290c4ca 209 if (!new_prop)
7518b589
PA
210 return -ENOMEM;
211
0290c4ca
FR
212 if (!prop)
213 ret = of_changeset_add_property(&ovcs->cset, target_node,
214 new_prop);
646afc4a 215 else
0290c4ca
FR
216 ret = of_changeset_update_property(&ovcs->cset, target_node,
217 new_prop);
ac0f3e30
LW
218
219 if (ret) {
0290c4ca
FR
220 kfree(new_prop->name);
221 kfree(new_prop->value);
222 kfree(new_prop);
ac0f3e30
LW
223 }
224 return ret;
7518b589
PA
225}
226
0290c4ca
FR
227/**
228 * add_changeset_node() - add @node (and children) to overlay changeset
229 * @ovcs: overlay changeset
230 * @target_node: where to place @node in live tree
231 * @node: node from within overlay device tree fragment
232 *
233 * If @node does not already exist in @target_node, add changeset entry
234 * to add @node in @target_node.
235 *
236 * If @node already exists in @target_node, and the existing node has
237 * a phandle, the overlay node is not allowed to have a phandle.
238 *
239 * If @node has child nodes, add the children recursively via
240 * build_changeset_next_level().
241 *
242 * NOTE: Multiple mods of created nodes not supported.
243 *
244 * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
245 * invalid @overlay.
246 */
247static int add_changeset_node(struct overlay_changeset *ovcs,
248 struct device_node *target_node, struct device_node *node)
7518b589 249{
0290c4ca 250 const char *node_kbasename;
d3a89165 251 struct device_node *tchild;
7518b589
PA
252 int ret = 0;
253
0290c4ca
FR
254 node_kbasename = kbasename(node->full_name);
255 if (!node_kbasename)
7518b589
PA
256 return -ENOMEM;
257
0290c4ca
FR
258 for_each_child_of_node(target_node, tchild)
259 if (!of_node_cmp(node_kbasename, kbasename(tchild->full_name)))
c1cd1e01
FR
260 break;
261
61b4de4e 262 if (!tchild) {
0290c4ca
FR
263 tchild = __of_node_dup(node, "%pOF/%s",
264 target_node, node_kbasename);
7518b589
PA
265 if (!tchild)
266 return -ENOMEM;
267
0290c4ca 268 tchild->parent = target_node;
7518b589 269
0290c4ca 270 ret = of_changeset_attach_node(&ovcs->cset, tchild);
7518b589
PA
271 if (ret)
272 return ret;
273
61b4de4e 274 return build_changeset_next_level(ovcs, tchild, node, 0);
7518b589
PA
275 }
276
61b4de4e
FR
277 if (node->phandle)
278 return -EINVAL;
279
280 ret = build_changeset_next_level(ovcs, tchild, node, 0);
281 of_node_put(tchild);
282
7518b589
PA
283 return ret;
284}
285
0290c4ca
FR
286/**
287 * build_changeset_next_level() - add level of overlay changeset
288 * @ovcs: overlay changeset
289 * @target_node: where to place @overlay_node in live tree
290 * @overlay_node: node from within an overlay device tree fragment
291 * @is_symbols_node: @overlay_node is node "/__symbols__"
7518b589 292 *
0290c4ca
FR
293 * Add the properties (if any) and nodes (if any) from @overlay_node to the
294 * @ovcs->cset changeset. If an added node has child nodes, they will
295 * be added recursively.
646afc4a
FR
296 *
297 * Do not allow symbols node to have any children.
0290c4ca
FR
298 *
299 * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
300 * invalid @overlay_node.
7518b589 301 */
0290c4ca
FR
302static int build_changeset_next_level(struct overlay_changeset *ovcs,
303 struct device_node *target_node,
304 const struct device_node *overlay_node,
d1651b03 305 bool is_symbols_node)
7518b589
PA
306{
307 struct device_node *child;
308 struct property *prop;
309 int ret;
310
0290c4ca
FR
311 for_each_property_of_node(overlay_node, prop) {
312 ret = add_changeset_property(ovcs, target_node, prop,
313 is_symbols_node);
7518b589 314 if (ret) {
0d638a07 315 pr_err("Failed to apply prop @%pOF/%s\n",
0290c4ca 316 target_node, prop->name);
7518b589
PA
317 return ret;
318 }
319 }
320
d1651b03
FR
321 if (is_symbols_node)
322 return 0;
323
0290c4ca
FR
324 for_each_child_of_node(overlay_node, child) {
325 ret = add_changeset_node(ovcs, target_node, child);
bbed8794 326 if (ret) {
0290c4ca
FR
327 pr_err("Failed to apply node @%pOF/%s\n",
328 target_node, child->name);
001cf504 329 of_node_put(child);
7518b589
PA
330 return ret;
331 }
332 }
333
334 return 0;
335}
336
337/**
0290c4ca
FR
338 * build_changeset() - populate overlay changeset in @ovcs from @ovcs->fragments
339 * @ovcs: Overlay changeset
7518b589 340 *
0290c4ca
FR
341 * Create changeset @ovcs->cset to contain the nodes and properties of the
342 * overlay device tree fragments in @ovcs->fragments[]. If an error occurs,
343 * any portions of the changeset that were successfully created will remain
344 * in @ovcs->cset.
345 *
346 * Returns 0 on success, -ENOMEM if memory allocation failure, or -EINVAL if
347 * invalid overlay in @ovcs->fragments[].
7518b589 348 */
0290c4ca 349static int build_changeset(struct overlay_changeset *ovcs)
7518b589 350{
0290c4ca 351 int i, ret;
7518b589 352
0290c4ca
FR
353 for (i = 0; i < ovcs->count; i++) {
354 struct fragment *fragment = &ovcs->fragments[i];
7518b589 355
0290c4ca
FR
356 ret = build_changeset_next_level(ovcs, fragment->target,
357 fragment->overlay,
358 fragment->is_symbols_node);
359 if (ret) {
360 pr_err("apply failed '%pOF'\n", fragment->target);
361 return ret;
7518b589
PA
362 }
363 }
364
365 return 0;
366}
367
368/*
369 * Find the target node using a number of different strategies
646afc4a 370 * in order of preference:
7518b589 371 *
646afc4a
FR
372 * 1) "target" property containing the phandle of the target
373 * 2) "target-path" property containing the path of the target
7518b589
PA
374 */
375static struct device_node *find_target_node(struct device_node *info_node)
376{
377 const char *path;
378 u32 val;
379 int ret;
380
7518b589 381 ret = of_property_read_u32(info_node, "target", &val);
bbed8794 382 if (!ret)
7518b589
PA
383 return of_find_node_by_phandle(val);
384
7518b589 385 ret = of_property_read_string(info_node, "target-path", &path);
bbed8794 386 if (!ret)
7518b589
PA
387 return of_find_node_by_path(path);
388
606ad42a 389 pr_err("Failed to find target for node %p (%s)\n",
7518b589
PA
390 info_node, info_node->name);
391
392 return NULL;
393}
394
7518b589 395/**
0290c4ca
FR
396 * init_overlay_changeset() - initialize overlay changeset from overlay tree
397 * @ovcs Overlay changeset to build
398 * @tree: Contains all the overlay fragments and overlay fixup nodes
7518b589 399 *
0290c4ca
FR
400 * Initialize @ovcs. Populate @ovcs->fragments with node information from
401 * the top level of @tree. The relevant top level nodes are the fragment
402 * nodes and the __symbols__ node. Any other top level node will be ignored.
7518b589 403 *
0290c4ca 404 * Returns 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error
61b4de4e 405 * detected in @tree, or -ENOSPC if idr_alloc() error.
7518b589 406 */
0290c4ca 407static int init_overlay_changeset(struct overlay_changeset *ovcs,
7518b589
PA
408 struct device_node *tree)
409{
61b4de4e 410 struct device_node *node, *overlay_node;
0290c4ca
FR
411 struct fragment *fragment;
412 struct fragment *fragments;
413 int cnt, ret;
7518b589 414
61b4de4e
FR
415 INIT_LIST_HEAD(&ovcs->ovcs_list);
416
417 of_changeset_init(&ovcs->cset);
418
419 ovcs->id = idr_alloc(&ovcs_idr, ovcs, 1, 0, GFP_KERNEL);
420 if (ovcs->id <= 0)
421 return ovcs->id;
422
7518b589 423 cnt = 0;
7518b589 424
61b4de4e
FR
425 /* fragment nodes */
426 for_each_child_of_node(tree, node) {
427 overlay_node = of_get_child_by_name(node, "__overlay__");
428 if (overlay_node) {
429 cnt++;
430 of_node_put(overlay_node);
431 }
432 }
433
434 node = of_get_child_by_name(tree, "__symbols__");
435 if (node) {
d1651b03 436 cnt++;
61b4de4e
FR
437 of_node_put(node);
438 }
d1651b03 439
0290c4ca 440 fragments = kcalloc(cnt, sizeof(*fragments), GFP_KERNEL);
61b4de4e
FR
441 if (!fragments) {
442 ret = -ENOMEM;
443 goto err_free_idr;
444 }
7518b589
PA
445
446 cnt = 0;
447 for_each_child_of_node(tree, node) {
61b4de4e
FR
448 fragment = &fragments[cnt];
449 fragment->overlay = of_get_child_by_name(node, "__overlay__");
450 if (fragment->overlay) {
451 fragment->target = find_target_node(node);
452 if (!fragment->target) {
453 of_node_put(fragment->overlay);
454 ret = -EINVAL;
455 goto err_free_fragments;
456 } else {
457 cnt++;
458 }
459 }
7518b589
PA
460 }
461
d1651b03
FR
462 node = of_get_child_by_name(tree, "__symbols__");
463 if (node) {
0290c4ca
FR
464 fragment = &fragments[cnt];
465 fragment->overlay = node;
466 fragment->target = of_find_node_by_path("/__symbols__");
467 fragment->is_symbols_node = 1;
d1651b03 468
0290c4ca 469 if (!fragment->target) {
d1651b03 470 pr_err("no symbols in root of device tree.\n");
61b4de4e
FR
471 ret = -EINVAL;
472 goto err_free_fragments;
d1651b03
FR
473 }
474
475 cnt++;
476 }
477
bbed8794 478 if (!cnt) {
61b4de4e
FR
479 ret = -EINVAL;
480 goto err_free_fragments;
7518b589
PA
481 }
482
0290c4ca
FR
483 ovcs->count = cnt;
484 ovcs->fragments = fragments;
7518b589
PA
485
486 return 0;
61b4de4e
FR
487
488
489err_free_fragments:
490 kfree(fragments);
491err_free_idr:
492 idr_remove(&ovcs_idr, ovcs->id);
493
494 return ret;
7518b589
PA
495}
496
61b4de4e 497static void free_overlay_changeset(struct overlay_changeset *ovcs)
7518b589 498{
7518b589
PA
499 int i;
500
61b4de4e
FR
501 if (!ovcs->cset.entries.next)
502 return;
503 of_changeset_destroy(&ovcs->cset);
504
505 if (ovcs->id)
506 idr_remove(&ovcs_idr, ovcs->id);
507
508 for (i = 0; i < ovcs->count; i++) {
0290c4ca
FR
509 of_node_put(ovcs->fragments[i].target);
510 of_node_put(ovcs->fragments[i].overlay);
7518b589 511 }
0290c4ca 512 kfree(ovcs->fragments);
7518b589 513
61b4de4e
FR
514 kfree(ovcs);
515}
7518b589
PA
516
517/**
0290c4ca
FR
518 * of_overlay_apply() - Create and apply an overlay changeset
519 * @tree: Expanded overlay device tree
7518b589 520 *
0290c4ca
FR
521 * Creates and applies an overlay changeset. If successful, the overlay
522 * changeset is added to the overlay changeset list.
7518b589 523 *
0290c4ca 524 * Returns the id of the created overlay changeset, or a negative error number
7518b589 525 */
0290c4ca 526int of_overlay_apply(struct device_node *tree)
7518b589 527{
0290c4ca 528 struct overlay_changeset *ovcs;
61b4de4e 529 int ret;
7518b589 530
0290c4ca
FR
531 ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL);
532 if (!ovcs)
7518b589 533 return -ENOMEM;
7518b589
PA
534
535 mutex_lock(&of_mutex);
536
0290c4ca
FR
537 ret = init_overlay_changeset(ovcs, tree);
538 if (ret) {
61b4de4e
FR
539 pr_err("init_overlay_changeset() failed, ret = %d\n", ret);
540 goto err_free_overlay_changeset;
7518b589
PA
541 }
542
0290c4ca
FR
543 ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
544 if (ret < 0) {
545 pr_err("%s: Pre-apply notifier failed (ret=%d)\n",
546 __func__, ret);
61b4de4e 547 goto err_free_overlay_changeset;
39a842e2
AT
548 }
549
0290c4ca
FR
550 ret = build_changeset(ovcs);
551 if (ret)
61b4de4e 552 goto err_free_overlay_changeset;
606ad42a 553
0290c4ca
FR
554 ret = __of_changeset_apply(&ovcs->cset);
555 if (ret)
61b4de4e 556 goto err_free_overlay_changeset;
7518b589 557
0290c4ca 558 list_add_tail(&ovcs->ovcs_list, &ovcs_list);
7518b589 559
0290c4ca 560 overlay_notify(ovcs, OF_OVERLAY_POST_APPLY);
39a842e2 561
7518b589
PA
562 mutex_unlock(&of_mutex);
563
61b4de4e
FR
564 return ovcs->id;
565
566err_free_overlay_changeset:
567 free_overlay_changeset(ovcs);
7518b589 568
7518b589
PA
569 mutex_unlock(&of_mutex);
570
0290c4ca 571 return ret;
7518b589 572}
0290c4ca 573EXPORT_SYMBOL_GPL(of_overlay_apply);
7518b589 574
646afc4a 575/*
0290c4ca
FR
576 * Find @np in @tree.
577 *
578 * Returns 1 if @np is @tree or is contained in @tree, else 0
646afc4a 579 */
0290c4ca 580static int find_node(struct device_node *tree, struct device_node *np)
7518b589
PA
581{
582 struct device_node *child;
583
0290c4ca 584 if (tree == np)
7518b589
PA
585 return 1;
586
587 for_each_child_of_node(tree, child) {
0290c4ca 588 if (find_node(child, np)) {
001cf504 589 of_node_put(child);
7518b589 590 return 1;
001cf504 591 }
7518b589
PA
592 }
593
594 return 0;
595}
596
646afc4a 597/*
0290c4ca
FR
598 * Is @remove_ce_np a child of or the same as any
599 * node in an overlay changeset more topmost than @remove_ovcs?
600 *
601 * Returns 1 if found, else 0
646afc4a 602 */
0290c4ca
FR
603static int node_in_later_cs(struct overlay_changeset *remove_ovcs,
604 struct device_node *remove_ce_np)
7518b589 605{
0290c4ca 606 struct overlay_changeset *ovcs;
7518b589
PA
607 struct of_changeset_entry *ce;
608
0290c4ca
FR
609 list_for_each_entry_reverse(ovcs, &ovcs_list, ovcs_list) {
610 if (ovcs == remove_ovcs)
7518b589
PA
611 break;
612
0290c4ca
FR
613 list_for_each_entry(ce, &ovcs->cset.entries, node) {
614 if (find_node(ce->np, remove_ce_np)) {
0d638a07 615 pr_err("%s: #%d clashes #%d @%pOF\n",
0290c4ca
FR
616 __func__, remove_ovcs->id, ovcs->id,
617 remove_ce_np);
618 return 1;
7518b589
PA
619 }
620 }
621 }
622
0290c4ca 623 return 0;
7518b589
PA
624}
625
626/*
627 * We can safely remove the overlay only if it's the top-most one.
628 * Newly applied overlays are inserted at the tail of the overlay list,
629 * so a top most overlay is the one that is closest to the tail.
630 *
631 * The topmost check is done by exploiting this property. For each
632 * affected device node in the log list we check if this overlay is
633 * the one closest to the tail. If another overlay has affected this
634 * device node and is closest to the tail, then removal is not permited.
635 */
0290c4ca 636static int overlay_removal_is_ok(struct overlay_changeset *remove_ovcs)
7518b589 637{
0290c4ca 638 struct of_changeset_entry *remove_ce;
7518b589 639
0290c4ca
FR
640 list_for_each_entry(remove_ce, &remove_ovcs->cset.entries, node) {
641 if (node_in_later_cs(remove_ovcs, remove_ce->np)) {
642 pr_err("overlay #%d is not topmost\n", remove_ovcs->id);
7518b589
PA
643 return 0;
644 }
645 }
646
647 return 1;
648}
649
650/**
0290c4ca
FR
651 * of_overlay_remove() - Revert and free an overlay changeset
652 * @ovcs_id: Overlay changeset id number
7518b589 653 *
0290c4ca
FR
654 * Removes an overlay if it is permissible. ovcs_id was previously returned
655 * by of_overlay_apply().
7518b589 656 *
94a8bf97 657 * Returns 0 on success, or a negative error number
7518b589 658 */
0290c4ca 659int of_overlay_remove(int ovcs_id)
7518b589 660{
0290c4ca
FR
661 struct overlay_changeset *ovcs;
662 int ret = 0;
7518b589
PA
663
664 mutex_lock(&of_mutex);
665
0290c4ca
FR
666 ovcs = idr_find(&ovcs_idr, ovcs_id);
667 if (!ovcs) {
668 ret = -ENODEV;
669 pr_err("remove: Could not find overlay #%d\n", ovcs_id);
7518b589
PA
670 goto out;
671 }
672
0290c4ca
FR
673 if (!overlay_removal_is_ok(ovcs)) {
674 ret = -EBUSY;
7518b589
PA
675 goto out;
676 }
677
0290c4ca 678 overlay_notify(ovcs, OF_OVERLAY_PRE_REMOVE);
61b4de4e 679
0290c4ca 680 list_del(&ovcs->ovcs_list);
61b4de4e 681
0290c4ca 682 __of_changeset_revert(&ovcs->cset);
61b4de4e 683
0290c4ca 684 overlay_notify(ovcs, OF_OVERLAY_POST_REMOVE);
61b4de4e
FR
685
686 free_overlay_changeset(ovcs);
7518b589
PA
687
688out:
689 mutex_unlock(&of_mutex);
690
0290c4ca 691 return ret;
7518b589 692}
0290c4ca 693EXPORT_SYMBOL_GPL(of_overlay_remove);
7518b589
PA
694
695/**
0290c4ca 696 * of_overlay_remove_all() - Reverts and frees all overlay changesets
7518b589
PA
697 *
698 * Removes all overlays from the system in the correct order.
699 *
94a8bf97 700 * Returns 0 on success, or a negative error number
7518b589 701 */
0290c4ca 702int of_overlay_remove_all(void)
7518b589 703{
0290c4ca 704 struct overlay_changeset *ovcs, *ovcs_n;
61b4de4e 705 int ret;
7518b589
PA
706
707 /* the tail of list is guaranteed to be safe to remove */
0290c4ca 708 list_for_each_entry_safe_reverse(ovcs, ovcs_n, &ovcs_list, ovcs_list) {
61b4de4e
FR
709 ret = of_overlay_remove(ovcs->id);
710 if (ret)
711 return ret;
7518b589
PA
712 }
713
7518b589
PA
714 return 0;
715}
0290c4ca 716EXPORT_SYMBOL_GPL(of_overlay_remove_all);