blob: af3b9a16df263ba21a83585d156cfd3cb852b1f8 [file] [log] [blame]
Pantelis Antoniou7518b5892014-10-28 22:35:58 +02001/*
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 */
Rob Herring606ad422016-06-15 08:32:18 -050011
12#define pr_fmt(fmt) "OF: overlay: " fmt
13
Pantelis Antoniou7518b5892014-10-28 22:35:58 +020014#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>
Pantelis Antoniou7518b5892014-10-28 22:35:58 +020021#include <linux/slab.h>
22#include <linux/err.h>
Mark Brown0d1886d2015-02-17 11:36:58 +090023#include <linux/idr.h>
Pantelis Antoniou7518b5892014-10-28 22:35:58 +020024
25#include "of_private.h"
26
27/**
28 * struct of_overlay_info - Holds a single overlay info
29 * @target: target of the overlay operation
30 * @overlay: pointer to the overlay contents node
31 *
32 * Holds a single overlay state, including all the overlay logs &
33 * records.
34 */
35struct of_overlay_info {
36 struct device_node *target;
37 struct device_node *overlay;
Frank Rowandd1651b02017-07-19 09:25:22 -070038 bool is_symbols_node;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +020039};
40
41/**
42 * struct of_overlay - Holds a complete overlay transaction
43 * @node: List on which we are located
44 * @count: Count of ovinfo structures
45 * @ovinfo_tab: Overlay info table (count sized)
46 * @cset: Changeset to be used
47 *
48 * Holds a complete overlay transaction
49 */
50struct of_overlay {
51 int id;
52 struct list_head node;
53 int count;
54 struct of_overlay_info *ovinfo_tab;
55 struct of_changeset cset;
56};
57
58static int of_overlay_apply_one(struct of_overlay *ov,
Frank Rowandd1651b02017-07-19 09:25:22 -070059 struct device_node *target, const struct device_node *overlay,
60 bool is_symbols_node);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +020061
Alan Tull39a842e2016-11-01 14:14:22 -050062static BLOCKING_NOTIFIER_HEAD(of_overlay_chain);
63
64int of_overlay_notifier_register(struct notifier_block *nb)
65{
66 return blocking_notifier_chain_register(&of_overlay_chain, nb);
67}
68EXPORT_SYMBOL_GPL(of_overlay_notifier_register);
69
70int of_overlay_notifier_unregister(struct notifier_block *nb)
71{
72 return blocking_notifier_chain_unregister(&of_overlay_chain, nb);
73}
74EXPORT_SYMBOL_GPL(of_overlay_notifier_unregister);
75
76static int of_overlay_notify(struct of_overlay *ov,
77 enum of_overlay_notify_action action)
78{
79 struct of_overlay_notify_data nd;
80 int i, ret;
81
82 for (i = 0; i < ov->count; i++) {
83 struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
84
85 nd.target = ovinfo->target;
86 nd.overlay = ovinfo->overlay;
87
88 ret = blocking_notifier_call_chain(&of_overlay_chain,
89 action, &nd);
90 if (ret)
91 return notifier_to_errno(ret);
92 }
93
94 return 0;
95}
96
Frank Rowandd1651b02017-07-19 09:25:22 -070097static struct property *dup_and_fixup_symbol_prop(struct of_overlay *ov,
98 const struct property *prop)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +020099{
Frank Rowandd1651b02017-07-19 09:25:22 -0700100 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
160static int of_overlay_apply_single_property(struct of_overlay *ov,
161 struct device_node *target, struct property *prop,
162 bool is_symbols_node)
163{
164 struct property *propn = NULL, *tprop;
Lixin Wangac0f3e32017-10-16 17:54:32 +0800165 int ret = 0;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200166
167 /* NOTE: Multiple changes of single properties not supported */
168 tprop = of_find_property(target, prop->name, NULL);
169
170 /* special properties are not meant to be updated (silent NOP) */
171 if (of_prop_cmp(prop->name, "name") == 0 ||
172 of_prop_cmp(prop->name, "phandle") == 0 ||
173 of_prop_cmp(prop->name, "linux,phandle") == 0)
174 return 0;
175
Frank Rowandd1651b02017-07-19 09:25:22 -0700176 if (is_symbols_node) {
177 /* changing a property in __symbols__ node not allowed */
178 if (tprop)
179 return -EINVAL;
180 propn = dup_and_fixup_symbol_prop(ov, prop);
181 } else {
182 propn = __of_prop_dup(prop, GFP_KERNEL);
183 }
184
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200185 if (propn == NULL)
186 return -ENOMEM;
187
188 /* not found? add */
189 if (tprop == NULL)
Lixin Wangac0f3e32017-10-16 17:54:32 +0800190 ret = of_changeset_add_property(&ov->cset, target, propn);
191 else /* found? update */
192 ret = of_changeset_update_property(&ov->cset, target, propn);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200193
Lixin Wangac0f3e32017-10-16 17:54:32 +0800194 if (ret) {
195 kfree(propn->name);
196 kfree(propn->value);
197 kfree(propn);
198 }
199 return ret;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200200}
201
202static int of_overlay_apply_single_device_node(struct of_overlay *ov,
203 struct device_node *target, struct device_node *child)
204{
205 const char *cname;
Fabio Estevamd3a89162015-03-03 10:04:45 -0300206 struct device_node *tchild;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200207 int ret = 0;
208
209 cname = kbasename(child->full_name);
210 if (cname == NULL)
211 return -ENOMEM;
212
213 /* NOTE: Multiple mods of created nodes not supported */
Frank Rowandc1cd1e02017-07-19 09:25:21 -0700214 for_each_child_of_node(target, tchild)
215 if (!of_node_cmp(cname, kbasename(tchild->full_name)))
216 break;
217
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200218 if (tchild != NULL) {
Frank Rowand7a12f452017-06-21 12:21:56 -0700219 /* new overlay phandle value conflicts with existing value */
220 if (child->phandle)
221 return -EINVAL;
222
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200223 /* apply overlay recursively */
Frank Rowandd1651b02017-07-19 09:25:22 -0700224 ret = of_overlay_apply_one(ov, tchild, child, 0);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200225 of_node_put(tchild);
226 } else {
227 /* create empty tree as a target */
Rob Herring0d638a02017-06-01 15:50:55 -0500228 tchild = __of_node_dup(child, "%pOF/%s", target, cname);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200229 if (!tchild)
230 return -ENOMEM;
231
232 /* point to parent */
233 tchild->parent = target;
234
235 ret = of_changeset_attach_node(&ov->cset, tchild);
236 if (ret)
237 return ret;
238
Frank Rowandd1651b02017-07-19 09:25:22 -0700239 ret = of_overlay_apply_one(ov, tchild, child, 0);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200240 if (ret)
241 return ret;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200242 }
243
244 return ret;
245}
246
247/*
248 * Apply a single overlay node recursively.
249 *
250 * Note that the in case of an error the target node is left
251 * in a inconsistent state. Error recovery should be performed
252 * by using the changeset.
253 */
254static int of_overlay_apply_one(struct of_overlay *ov,
Frank Rowandd1651b02017-07-19 09:25:22 -0700255 struct device_node *target, const struct device_node *overlay,
256 bool is_symbols_node)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200257{
258 struct device_node *child;
259 struct property *prop;
260 int ret;
261
262 for_each_property_of_node(overlay, prop) {
Frank Rowandd1651b02017-07-19 09:25:22 -0700263 ret = of_overlay_apply_single_property(ov, target, prop,
264 is_symbols_node);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200265 if (ret) {
Rob Herring0d638a02017-06-01 15:50:55 -0500266 pr_err("Failed to apply prop @%pOF/%s\n",
267 target, prop->name);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200268 return ret;
269 }
270 }
271
Frank Rowandd1651b02017-07-19 09:25:22 -0700272 /* do not allow symbols node to have any children */
273 if (is_symbols_node)
274 return 0;
275
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200276 for_each_child_of_node(overlay, child) {
277 ret = of_overlay_apply_single_device_node(ov, target, child);
278 if (ret != 0) {
Rob Herring0d638a02017-06-01 15:50:55 -0500279 pr_err("Failed to apply single node @%pOF/%s\n",
280 target, child->name);
Julia Lawall001cf502015-10-22 11:02:48 +0200281 of_node_put(child);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200282 return ret;
283 }
284 }
285
286 return 0;
287}
288
289/**
290 * of_overlay_apply() - Apply @count overlays pointed at by @ovinfo_tab
291 * @ov: Overlay to apply
292 *
293 * Applies the overlays given, while handling all error conditions
294 * appropriately. Either the operation succeeds, or if it fails the
295 * live tree is reverted to the state before the attempt.
296 * Returns 0, or an error if the overlay attempt failed.
297 */
298static int of_overlay_apply(struct of_overlay *ov)
299{
300 int i, err;
301
302 /* first we apply the overlays atomically */
303 for (i = 0; i < ov->count; i++) {
304 struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
305
Frank Rowandd1651b02017-07-19 09:25:22 -0700306 err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay,
307 ovinfo->is_symbols_node);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200308 if (err != 0) {
Rob Herring0d638a02017-06-01 15:50:55 -0500309 pr_err("apply failed '%pOF'\n", ovinfo->target);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200310 return err;
311 }
312 }
313
314 return 0;
315}
316
317/*
318 * Find the target node using a number of different strategies
319 * in order of preference
320 *
321 * "target" property containing the phandle of the target
322 * "target-path" property containing the path of the target
323 */
324static struct device_node *find_target_node(struct device_node *info_node)
325{
326 const char *path;
327 u32 val;
328 int ret;
329
330 /* first try to go by using the target as a phandle */
331 ret = of_property_read_u32(info_node, "target", &val);
332 if (ret == 0)
333 return of_find_node_by_phandle(val);
334
335 /* now try to locate by path */
336 ret = of_property_read_string(info_node, "target-path", &path);
337 if (ret == 0)
338 return of_find_node_by_path(path);
339
Rob Herring606ad422016-06-15 08:32:18 -0500340 pr_err("Failed to find target for node %p (%s)\n",
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200341 info_node, info_node->name);
342
343 return NULL;
344}
345
346/**
347 * of_fill_overlay_info() - Fill an overlay info structure
348 * @ov Overlay to fill
349 * @info_node: Device node containing the overlay
350 * @ovinfo: Pointer to the overlay info structure to fill
351 *
352 * Fills an overlay info structure with the overlay information
353 * from a device node. This device node must have a target property
354 * which contains a phandle of the overlay target node, and an
355 * __overlay__ child node which has the overlay contents.
356 * Both ovinfo->target & ovinfo->overlay have their references taken.
357 *
358 * Returns 0 on success, or a negative error value.
359 */
360static int of_fill_overlay_info(struct of_overlay *ov,
361 struct device_node *info_node, struct of_overlay_info *ovinfo)
362{
363 ovinfo->overlay = of_get_child_by_name(info_node, "__overlay__");
364 if (ovinfo->overlay == NULL)
365 goto err_fail;
366
367 ovinfo->target = find_target_node(info_node);
368 if (ovinfo->target == NULL)
369 goto err_fail;
370
371 return 0;
372
373err_fail:
374 of_node_put(ovinfo->target);
375 of_node_put(ovinfo->overlay);
376
377 memset(ovinfo, 0, sizeof(*ovinfo));
378 return -EINVAL;
379}
380
381/**
382 * of_build_overlay_info() - Build an overlay info array
383 * @ov Overlay to build
384 * @tree: Device node containing all the overlays
385 *
386 * Helper function that given a tree containing overlay information,
387 * allocates and builds an overlay info array containing it, ready
388 * for use using of_overlay_apply.
389 *
390 * Returns 0 on success with the @cntp @ovinfop pointers valid,
391 * while on error a negative error value is returned.
392 */
393static int of_build_overlay_info(struct of_overlay *ov,
394 struct device_node *tree)
395{
396 struct device_node *node;
397 struct of_overlay_info *ovinfo;
398 int cnt, err;
399
400 /* worst case; every child is a node */
401 cnt = 0;
402 for_each_child_of_node(tree, node)
403 cnt++;
404
Frank Rowandd1651b02017-07-19 09:25:22 -0700405 if (of_get_child_by_name(tree, "__symbols__"))
406 cnt++;
407
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200408 ovinfo = kcalloc(cnt, sizeof(*ovinfo), GFP_KERNEL);
409 if (ovinfo == NULL)
410 return -ENOMEM;
411
412 cnt = 0;
413 for_each_child_of_node(tree, node) {
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200414 err = of_fill_overlay_info(ov, node, &ovinfo[cnt]);
415 if (err == 0)
416 cnt++;
417 }
418
Frank Rowandd1651b02017-07-19 09:25:22 -0700419 node = of_get_child_by_name(tree, "__symbols__");
420 if (node) {
421 ovinfo[cnt].overlay = node;
422 ovinfo[cnt].target = of_find_node_by_path("/__symbols__");
423 ovinfo[cnt].is_symbols_node = 1;
424
425 if (!ovinfo[cnt].target) {
426 pr_err("no symbols in root of device tree.\n");
427 return -EINVAL;
428 }
429
430 cnt++;
431 }
432
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200433 /* if nothing filled, return error */
434 if (cnt == 0) {
435 kfree(ovinfo);
436 return -ENODEV;
437 }
438
439 ov->count = cnt;
440 ov->ovinfo_tab = ovinfo;
441
442 return 0;
443}
444
445/**
446 * of_free_overlay_info() - Free an overlay info array
447 * @ov Overlay to free the overlay info from
448 * @ovinfo_tab: Array of overlay_info's to free
449 *
450 * Releases the memory of a previously allocated ovinfo array
451 * by of_build_overlay_info.
452 * Returns 0, or an error if the arguments are bogus.
453 */
454static int of_free_overlay_info(struct of_overlay *ov)
455{
456 struct of_overlay_info *ovinfo;
457 int i;
458
459 /* do it in reverse */
460 for (i = ov->count - 1; i >= 0; i--) {
461 ovinfo = &ov->ovinfo_tab[i];
462
463 of_node_put(ovinfo->target);
464 of_node_put(ovinfo->overlay);
465 }
466 kfree(ov->ovinfo_tab);
467
468 return 0;
469}
470
471static LIST_HEAD(ov_list);
472static DEFINE_IDR(ov_idr);
473
474/**
475 * of_overlay_create() - Create and apply an overlay
476 * @tree: Device node containing all the overlays
477 *
478 * Creates and applies an overlay while also keeping track
479 * of the overlay in a list. This list can be used to prevent
480 * illegal overlay removals.
481 *
Geert Uytterhoeven94a8bf92015-05-21 14:10:26 +0200482 * Returns the id of the created overlay, or a negative error number
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200483 */
484int of_overlay_create(struct device_node *tree)
485{
486 struct of_overlay *ov;
487 int err, id;
488
489 /* allocate the overlay structure */
490 ov = kzalloc(sizeof(*ov), GFP_KERNEL);
491 if (ov == NULL)
492 return -ENOMEM;
493 ov->id = -1;
494
495 INIT_LIST_HEAD(&ov->node);
496
497 of_changeset_init(&ov->cset);
498
499 mutex_lock(&of_mutex);
500
501 id = idr_alloc(&ov_idr, ov, 0, 0, GFP_KERNEL);
502 if (id < 0) {
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200503 err = id;
504 goto err_destroy_trans;
505 }
506 ov->id = id;
507
508 /* build the overlay info structures */
509 err = of_build_overlay_info(ov, tree);
510 if (err) {
Rob Herring0d638a02017-06-01 15:50:55 -0500511 pr_err("of_build_overlay_info() failed for tree@%pOF\n",
512 tree);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200513 goto err_free_idr;
514 }
515
Alan Tull39a842e2016-11-01 14:14:22 -0500516 err = of_overlay_notify(ov, OF_OVERLAY_PRE_APPLY);
517 if (err < 0) {
518 pr_err("%s: Pre-apply notifier failed (err=%d)\n",
519 __func__, err);
520 goto err_free_idr;
521 }
522
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200523 /* apply the overlay */
524 err = of_overlay_apply(ov);
Rob Herring606ad422016-06-15 08:32:18 -0500525 if (err)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200526 goto err_abort_trans;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200527
528 /* apply the changeset */
Gavin Shan18322372015-11-05 00:12:49 +1100529 err = __of_changeset_apply(&ov->cset);
Rob Herring606ad422016-06-15 08:32:18 -0500530 if (err)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200531 goto err_revert_overlay;
Rob Herring606ad422016-06-15 08:32:18 -0500532
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200533
534 /* add to the tail of the overlay list */
535 list_add_tail(&ov->node, &ov_list);
536
Alan Tull39a842e2016-11-01 14:14:22 -0500537 of_overlay_notify(ov, OF_OVERLAY_POST_APPLY);
538
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200539 mutex_unlock(&of_mutex);
540
541 return id;
542
543err_revert_overlay:
544err_abort_trans:
545 of_free_overlay_info(ov);
546err_free_idr:
547 idr_remove(&ov_idr, ov->id);
548err_destroy_trans:
549 of_changeset_destroy(&ov->cset);
550 kfree(ov);
551 mutex_unlock(&of_mutex);
552
553 return err;
554}
555EXPORT_SYMBOL_GPL(of_overlay_create);
556
557/* check whether the given node, lies under the given tree */
558static int overlay_subtree_check(struct device_node *tree,
559 struct device_node *dn)
560{
561 struct device_node *child;
562
563 /* match? */
564 if (tree == dn)
565 return 1;
566
567 for_each_child_of_node(tree, child) {
Julia Lawall001cf502015-10-22 11:02:48 +0200568 if (overlay_subtree_check(child, dn)) {
569 of_node_put(child);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200570 return 1;
Julia Lawall001cf502015-10-22 11:02:48 +0200571 }
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200572 }
573
574 return 0;
575}
576
577/* check whether this overlay is the topmost */
578static int overlay_is_topmost(struct of_overlay *ov, struct device_node *dn)
579{
580 struct of_overlay *ovt;
581 struct of_changeset_entry *ce;
582
583 list_for_each_entry_reverse(ovt, &ov_list, node) {
584 /* if we hit ourselves, we're done */
585 if (ovt == ov)
586 break;
587
588 /* check against each subtree affected by this overlay */
589 list_for_each_entry(ce, &ovt->cset.entries, node) {
590 if (overlay_subtree_check(ce->np, dn)) {
Rob Herring0d638a02017-06-01 15:50:55 -0500591 pr_err("%s: #%d clashes #%d @%pOF\n",
592 __func__, ov->id, ovt->id, dn);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200593 return 0;
594 }
595 }
596 }
597
598 /* overlay is topmost */
599 return 1;
600}
601
602/*
603 * We can safely remove the overlay only if it's the top-most one.
604 * Newly applied overlays are inserted at the tail of the overlay list,
605 * so a top most overlay is the one that is closest to the tail.
606 *
607 * The topmost check is done by exploiting this property. For each
608 * affected device node in the log list we check if this overlay is
609 * the one closest to the tail. If another overlay has affected this
610 * device node and is closest to the tail, then removal is not permited.
611 */
612static int overlay_removal_is_ok(struct of_overlay *ov)
613{
614 struct of_changeset_entry *ce;
615
616 list_for_each_entry(ce, &ov->cset.entries, node) {
617 if (!overlay_is_topmost(ov, ce->np)) {
Rob Herring606ad422016-06-15 08:32:18 -0500618 pr_err("overlay #%d is not topmost\n", ov->id);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200619 return 0;
620 }
621 }
622
623 return 1;
624}
625
626/**
627 * of_overlay_destroy() - Removes an overlay
628 * @id: Overlay id number returned by a previous call to of_overlay_create
629 *
630 * Removes an overlay if it is permissible.
631 *
Geert Uytterhoeven94a8bf92015-05-21 14:10:26 +0200632 * Returns 0 on success, or a negative error number
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200633 */
634int of_overlay_destroy(int id)
635{
636 struct of_overlay *ov;
637 int err;
638
639 mutex_lock(&of_mutex);
640
641 ov = idr_find(&ov_idr, id);
642 if (ov == NULL) {
643 err = -ENODEV;
Rob Herring606ad422016-06-15 08:32:18 -0500644 pr_err("destroy: Could not find overlay #%d\n", id);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200645 goto out;
646 }
647
648 /* check whether the overlay is safe to remove */
649 if (!overlay_removal_is_ok(ov)) {
650 err = -EBUSY;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200651 goto out;
652 }
653
Alan Tull39a842e2016-11-01 14:14:22 -0500654 of_overlay_notify(ov, OF_OVERLAY_PRE_REMOVE);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200655 list_del(&ov->node);
Gavin Shan18322372015-11-05 00:12:49 +1100656 __of_changeset_revert(&ov->cset);
Alan Tull39a842e2016-11-01 14:14:22 -0500657 of_overlay_notify(ov, OF_OVERLAY_POST_REMOVE);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200658 of_free_overlay_info(ov);
659 idr_remove(&ov_idr, id);
660 of_changeset_destroy(&ov->cset);
661 kfree(ov);
662
663 err = 0;
664
665out:
666 mutex_unlock(&of_mutex);
667
668 return err;
669}
670EXPORT_SYMBOL_GPL(of_overlay_destroy);
671
672/**
673 * of_overlay_destroy_all() - Removes all overlays from the system
674 *
675 * Removes all overlays from the system in the correct order.
676 *
Geert Uytterhoeven94a8bf92015-05-21 14:10:26 +0200677 * Returns 0 on success, or a negative error number
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200678 */
679int of_overlay_destroy_all(void)
680{
681 struct of_overlay *ov, *ovn;
682
683 mutex_lock(&of_mutex);
684
685 /* the tail of list is guaranteed to be safe to remove */
686 list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) {
687 list_del(&ov->node);
Gavin Shan18322372015-11-05 00:12:49 +1100688 __of_changeset_revert(&ov->cset);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200689 of_free_overlay_info(ov);
690 idr_remove(&ov_idr, ov->id);
691 kfree(ov);
692 }
693
694 mutex_unlock(&of_mutex);
695
696 return 0;
697}
698EXPORT_SYMBOL_GPL(of_overlay_destroy_all);