blob: d3f4a5974a11d835b5788e5d5720c8f253cb10f0 [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
Frank Rowandd1651b02017-07-19 09:25:22 -0700146 of_property_set_flag(new, OF_DYNAMIC);
147
148 return new;
149
150 err_free:
151 kfree(new->name);
152 kfree(new->value);
153 kfree(new);
154 return NULL;
155
156
157}
158
Frank Rowand646afc42017-10-17 16:36:21 -0700159/*
160 * Some special properties are not updated (no error returned).
161 * Update of property in symbols node is not allowed.
162 */
Frank Rowandd1651b02017-07-19 09:25:22 -0700163static int of_overlay_apply_single_property(struct of_overlay *ov,
164 struct device_node *target, struct property *prop,
165 bool is_symbols_node)
166{
167 struct property *propn = NULL, *tprop;
Lixin Wangac0f3e32017-10-16 17:54:32 +0800168 int ret = 0;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200169
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200170 tprop = of_find_property(target, prop->name, NULL);
171
Frank Rowandbbed8792017-10-17 16:36:22 -0700172 if (!of_prop_cmp(prop->name, "name") ||
173 !of_prop_cmp(prop->name, "phandle") ||
174 !of_prop_cmp(prop->name, "linux,phandle"))
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200175 return 0;
176
Frank Rowandd1651b02017-07-19 09:25:22 -0700177 if (is_symbols_node) {
Frank Rowandd1651b02017-07-19 09:25:22 -0700178 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
Frank Rowandbbed8792017-10-17 16:36:22 -0700185 if (!propn)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200186 return -ENOMEM;
187
Frank Rowandbbed8792017-10-17 16:36:22 -0700188 if (!tprop)
Lixin Wangac0f3e32017-10-16 17:54:32 +0800189 ret = of_changeset_add_property(&ov->cset, target, propn);
Frank Rowand646afc42017-10-17 16:36:21 -0700190 else
Lixin Wangac0f3e32017-10-16 17:54:32 +0800191 ret = of_changeset_update_property(&ov->cset, target, propn);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200192
Lixin Wangac0f3e32017-10-16 17:54:32 +0800193 if (ret) {
194 kfree(propn->name);
195 kfree(propn->value);
196 kfree(propn);
197 }
198 return ret;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200199}
200
201static int of_overlay_apply_single_device_node(struct of_overlay *ov,
202 struct device_node *target, struct device_node *child)
203{
204 const char *cname;
Fabio Estevamd3a89162015-03-03 10:04:45 -0300205 struct device_node *tchild;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200206 int ret = 0;
207
208 cname = kbasename(child->full_name);
Frank Rowandbbed8792017-10-17 16:36:22 -0700209 if (!cname)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200210 return -ENOMEM;
211
Frank Rowandc1cd1e02017-07-19 09:25:21 -0700212 for_each_child_of_node(target, tchild)
213 if (!of_node_cmp(cname, kbasename(tchild->full_name)))
214 break;
215
Frank Rowandbbed8792017-10-17 16:36:22 -0700216 if (tchild) {
Frank Rowand7a12f452017-06-21 12:21:56 -0700217 if (child->phandle)
218 return -EINVAL;
219
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200220 /* apply overlay recursively */
Frank Rowandd1651b02017-07-19 09:25:22 -0700221 ret = of_overlay_apply_one(ov, tchild, child, 0);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200222 of_node_put(tchild);
223 } else {
Rob Herring0d638a02017-06-01 15:50:55 -0500224 tchild = __of_node_dup(child, "%pOF/%s", target, cname);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200225 if (!tchild)
226 return -ENOMEM;
227
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200228 tchild->parent = target;
229
230 ret = of_changeset_attach_node(&ov->cset, tchild);
231 if (ret)
232 return ret;
233
Frank Rowandd1651b02017-07-19 09:25:22 -0700234 ret = of_overlay_apply_one(ov, tchild, child, 0);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200235 if (ret)
236 return ret;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200237 }
238
239 return ret;
240}
241
242/*
243 * Apply a single overlay node recursively.
244 *
245 * Note that the in case of an error the target node is left
246 * in a inconsistent state. Error recovery should be performed
247 * by using the changeset.
Frank Rowand646afc42017-10-17 16:36:21 -0700248 *
249 * Do not allow symbols node to have any children.
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200250 */
251static int of_overlay_apply_one(struct of_overlay *ov,
Frank Rowandd1651b02017-07-19 09:25:22 -0700252 struct device_node *target, const struct device_node *overlay,
253 bool is_symbols_node)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200254{
255 struct device_node *child;
256 struct property *prop;
257 int ret;
258
259 for_each_property_of_node(overlay, prop) {
Frank Rowandd1651b02017-07-19 09:25:22 -0700260 ret = of_overlay_apply_single_property(ov, target, prop,
261 is_symbols_node);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200262 if (ret) {
Rob Herring0d638a02017-06-01 15:50:55 -0500263 pr_err("Failed to apply prop @%pOF/%s\n",
264 target, prop->name);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200265 return ret;
266 }
267 }
268
Frank Rowandd1651b02017-07-19 09:25:22 -0700269 if (is_symbols_node)
270 return 0;
271
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200272 for_each_child_of_node(overlay, child) {
273 ret = of_overlay_apply_single_device_node(ov, target, child);
Frank Rowandbbed8792017-10-17 16:36:22 -0700274 if (ret) {
Rob Herring0d638a02017-06-01 15:50:55 -0500275 pr_err("Failed to apply single node @%pOF/%s\n",
276 target, child->name);
Julia Lawall001cf502015-10-22 11:02:48 +0200277 of_node_put(child);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200278 return ret;
279 }
280 }
281
282 return 0;
283}
284
285/**
286 * of_overlay_apply() - Apply @count overlays pointed at by @ovinfo_tab
287 * @ov: Overlay to apply
288 *
289 * Applies the overlays given, while handling all error conditions
290 * appropriately. Either the operation succeeds, or if it fails the
291 * live tree is reverted to the state before the attempt.
292 * Returns 0, or an error if the overlay attempt failed.
293 */
294static int of_overlay_apply(struct of_overlay *ov)
295{
296 int i, err;
297
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200298 for (i = 0; i < ov->count; i++) {
299 struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
300
Frank Rowandd1651b02017-07-19 09:25:22 -0700301 err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay,
302 ovinfo->is_symbols_node);
Frank Rowandbbed8792017-10-17 16:36:22 -0700303 if (err) {
Rob Herring0d638a02017-06-01 15:50:55 -0500304 pr_err("apply failed '%pOF'\n", ovinfo->target);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200305 return err;
306 }
307 }
308
309 return 0;
310}
311
312/*
313 * Find the target node using a number of different strategies
Frank Rowand646afc42017-10-17 16:36:21 -0700314 * in order of preference:
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200315 *
Frank Rowand646afc42017-10-17 16:36:21 -0700316 * 1) "target" property containing the phandle of the target
317 * 2) "target-path" property containing the path of the target
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200318 */
319static struct device_node *find_target_node(struct device_node *info_node)
320{
321 const char *path;
322 u32 val;
323 int ret;
324
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200325 ret = of_property_read_u32(info_node, "target", &val);
Frank Rowandbbed8792017-10-17 16:36:22 -0700326 if (!ret)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200327 return of_find_node_by_phandle(val);
328
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200329 ret = of_property_read_string(info_node, "target-path", &path);
Frank Rowandbbed8792017-10-17 16:36:22 -0700330 if (!ret)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200331 return of_find_node_by_path(path);
332
Rob Herring606ad422016-06-15 08:32:18 -0500333 pr_err("Failed to find target for node %p (%s)\n",
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200334 info_node, info_node->name);
335
336 return NULL;
337}
338
339/**
340 * of_fill_overlay_info() - Fill an overlay info structure
341 * @ov Overlay to fill
342 * @info_node: Device node containing the overlay
343 * @ovinfo: Pointer to the overlay info structure to fill
344 *
345 * Fills an overlay info structure with the overlay information
346 * from a device node. This device node must have a target property
347 * which contains a phandle of the overlay target node, and an
348 * __overlay__ child node which has the overlay contents.
349 * Both ovinfo->target & ovinfo->overlay have their references taken.
350 *
351 * Returns 0 on success, or a negative error value.
352 */
353static int of_fill_overlay_info(struct of_overlay *ov,
354 struct device_node *info_node, struct of_overlay_info *ovinfo)
355{
356 ovinfo->overlay = of_get_child_by_name(info_node, "__overlay__");
Frank Rowandbbed8792017-10-17 16:36:22 -0700357 if (!ovinfo->overlay)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200358 goto err_fail;
359
360 ovinfo->target = find_target_node(info_node);
Frank Rowandbbed8792017-10-17 16:36:22 -0700361 if (!ovinfo->target)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200362 goto err_fail;
363
364 return 0;
365
366err_fail:
367 of_node_put(ovinfo->target);
368 of_node_put(ovinfo->overlay);
369
370 memset(ovinfo, 0, sizeof(*ovinfo));
371 return -EINVAL;
372}
373
374/**
375 * of_build_overlay_info() - Build an overlay info array
376 * @ov Overlay to build
377 * @tree: Device node containing all the overlays
378 *
379 * Helper function that given a tree containing overlay information,
380 * allocates and builds an overlay info array containing it, ready
381 * for use using of_overlay_apply.
382 *
383 * Returns 0 on success with the @cntp @ovinfop pointers valid,
384 * while on error a negative error value is returned.
385 */
386static int of_build_overlay_info(struct of_overlay *ov,
387 struct device_node *tree)
388{
389 struct device_node *node;
390 struct of_overlay_info *ovinfo;
391 int cnt, err;
392
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200393 cnt = 0;
394 for_each_child_of_node(tree, node)
395 cnt++;
396
Frank Rowandd1651b02017-07-19 09:25:22 -0700397 if (of_get_child_by_name(tree, "__symbols__"))
398 cnt++;
399
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200400 ovinfo = kcalloc(cnt, sizeof(*ovinfo), GFP_KERNEL);
Frank Rowandbbed8792017-10-17 16:36:22 -0700401 if (!ovinfo)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200402 return -ENOMEM;
403
404 cnt = 0;
405 for_each_child_of_node(tree, node) {
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200406 err = of_fill_overlay_info(ov, node, &ovinfo[cnt]);
Frank Rowandbbed8792017-10-17 16:36:22 -0700407 if (!err)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200408 cnt++;
409 }
410
Frank Rowandd1651b02017-07-19 09:25:22 -0700411 node = of_get_child_by_name(tree, "__symbols__");
412 if (node) {
413 ovinfo[cnt].overlay = node;
414 ovinfo[cnt].target = of_find_node_by_path("/__symbols__");
415 ovinfo[cnt].is_symbols_node = 1;
416
417 if (!ovinfo[cnt].target) {
418 pr_err("no symbols in root of device tree.\n");
419 return -EINVAL;
420 }
421
422 cnt++;
423 }
424
Frank Rowandbbed8792017-10-17 16:36:22 -0700425 if (!cnt) {
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200426 kfree(ovinfo);
427 return -ENODEV;
428 }
429
430 ov->count = cnt;
431 ov->ovinfo_tab = ovinfo;
432
433 return 0;
434}
435
436/**
437 * of_free_overlay_info() - Free an overlay info array
438 * @ov Overlay to free the overlay info from
439 * @ovinfo_tab: Array of overlay_info's to free
440 *
441 * Releases the memory of a previously allocated ovinfo array
442 * by of_build_overlay_info.
443 * Returns 0, or an error if the arguments are bogus.
444 */
445static int of_free_overlay_info(struct of_overlay *ov)
446{
447 struct of_overlay_info *ovinfo;
448 int i;
449
450 /* do it in reverse */
451 for (i = ov->count - 1; i >= 0; i--) {
452 ovinfo = &ov->ovinfo_tab[i];
453
454 of_node_put(ovinfo->target);
455 of_node_put(ovinfo->overlay);
456 }
457 kfree(ov->ovinfo_tab);
458
459 return 0;
460}
461
462static LIST_HEAD(ov_list);
463static DEFINE_IDR(ov_idr);
464
465/**
466 * of_overlay_create() - Create and apply an overlay
467 * @tree: Device node containing all the overlays
468 *
469 * Creates and applies an overlay while also keeping track
470 * of the overlay in a list. This list can be used to prevent
471 * illegal overlay removals.
472 *
Geert Uytterhoeven94a8bf92015-05-21 14:10:26 +0200473 * Returns the id of the created overlay, or a negative error number
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200474 */
475int of_overlay_create(struct device_node *tree)
476{
477 struct of_overlay *ov;
478 int err, id;
479
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200480 ov = kzalloc(sizeof(*ov), GFP_KERNEL);
Frank Rowandbbed8792017-10-17 16:36:22 -0700481 if (!ov)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200482 return -ENOMEM;
483 ov->id = -1;
484
485 INIT_LIST_HEAD(&ov->node);
486
487 of_changeset_init(&ov->cset);
488
489 mutex_lock(&of_mutex);
490
491 id = idr_alloc(&ov_idr, ov, 0, 0, GFP_KERNEL);
492 if (id < 0) {
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200493 err = id;
494 goto err_destroy_trans;
495 }
496 ov->id = id;
497
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200498 err = of_build_overlay_info(ov, tree);
499 if (err) {
Rob Herring0d638a02017-06-01 15:50:55 -0500500 pr_err("of_build_overlay_info() failed for tree@%pOF\n",
501 tree);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200502 goto err_free_idr;
503 }
504
Alan Tull39a842e2016-11-01 14:14:22 -0500505 err = of_overlay_notify(ov, OF_OVERLAY_PRE_APPLY);
506 if (err < 0) {
507 pr_err("%s: Pre-apply notifier failed (err=%d)\n",
508 __func__, err);
509 goto err_free_idr;
510 }
511
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200512 err = of_overlay_apply(ov);
Rob Herring606ad422016-06-15 08:32:18 -0500513 if (err)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200514 goto err_abort_trans;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200515
Gavin Shan18322372015-11-05 00:12:49 +1100516 err = __of_changeset_apply(&ov->cset);
Rob Herring606ad422016-06-15 08:32:18 -0500517 if (err)
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200518 goto err_revert_overlay;
Rob Herring606ad422016-06-15 08:32:18 -0500519
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200520
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200521 list_add_tail(&ov->node, &ov_list);
522
Alan Tull39a842e2016-11-01 14:14:22 -0500523 of_overlay_notify(ov, OF_OVERLAY_POST_APPLY);
524
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200525 mutex_unlock(&of_mutex);
526
527 return id;
528
529err_revert_overlay:
530err_abort_trans:
531 of_free_overlay_info(ov);
532err_free_idr:
533 idr_remove(&ov_idr, ov->id);
534err_destroy_trans:
535 of_changeset_destroy(&ov->cset);
536 kfree(ov);
537 mutex_unlock(&of_mutex);
538
539 return err;
540}
541EXPORT_SYMBOL_GPL(of_overlay_create);
542
Frank Rowand646afc42017-10-17 16:36:21 -0700543/*
544 * check whether the given node, lies under the given tree
545 * return 1 if under tree, else 0
546 */
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200547static int overlay_subtree_check(struct device_node *tree,
548 struct device_node *dn)
549{
550 struct device_node *child;
551
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200552 if (tree == dn)
553 return 1;
554
555 for_each_child_of_node(tree, child) {
Julia Lawall001cf502015-10-22 11:02:48 +0200556 if (overlay_subtree_check(child, dn)) {
557 of_node_put(child);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200558 return 1;
Julia Lawall001cf502015-10-22 11:02:48 +0200559 }
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200560 }
561
562 return 0;
563}
564
Frank Rowand646afc42017-10-17 16:36:21 -0700565/*
566 * check whether this overlay is the topmost
567 * return 1 if topmost, else 0
568 */
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200569static int overlay_is_topmost(struct of_overlay *ov, struct device_node *dn)
570{
571 struct of_overlay *ovt;
572 struct of_changeset_entry *ce;
573
574 list_for_each_entry_reverse(ovt, &ov_list, node) {
575 /* if we hit ourselves, we're done */
576 if (ovt == ov)
577 break;
578
579 /* check against each subtree affected by this overlay */
580 list_for_each_entry(ce, &ovt->cset.entries, node) {
581 if (overlay_subtree_check(ce->np, dn)) {
Rob Herring0d638a02017-06-01 15:50:55 -0500582 pr_err("%s: #%d clashes #%d @%pOF\n",
583 __func__, ov->id, ovt->id, dn);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200584 return 0;
585 }
586 }
587 }
588
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200589 return 1;
590}
591
592/*
593 * We can safely remove the overlay only if it's the top-most one.
594 * Newly applied overlays are inserted at the tail of the overlay list,
595 * so a top most overlay is the one that is closest to the tail.
596 *
597 * The topmost check is done by exploiting this property. For each
598 * affected device node in the log list we check if this overlay is
599 * the one closest to the tail. If another overlay has affected this
600 * device node and is closest to the tail, then removal is not permited.
601 */
602static int overlay_removal_is_ok(struct of_overlay *ov)
603{
604 struct of_changeset_entry *ce;
605
606 list_for_each_entry(ce, &ov->cset.entries, node) {
607 if (!overlay_is_topmost(ov, ce->np)) {
Rob Herring606ad422016-06-15 08:32:18 -0500608 pr_err("overlay #%d is not topmost\n", ov->id);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200609 return 0;
610 }
611 }
612
613 return 1;
614}
615
616/**
617 * of_overlay_destroy() - Removes an overlay
618 * @id: Overlay id number returned by a previous call to of_overlay_create
619 *
620 * Removes an overlay if it is permissible.
621 *
Geert Uytterhoeven94a8bf92015-05-21 14:10:26 +0200622 * Returns 0 on success, or a negative error number
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200623 */
624int of_overlay_destroy(int id)
625{
626 struct of_overlay *ov;
627 int err;
628
629 mutex_lock(&of_mutex);
630
631 ov = idr_find(&ov_idr, id);
Frank Rowandbbed8792017-10-17 16:36:22 -0700632 if (!ov) {
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200633 err = -ENODEV;
Rob Herring606ad422016-06-15 08:32:18 -0500634 pr_err("destroy: Could not find overlay #%d\n", id);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200635 goto out;
636 }
637
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200638 if (!overlay_removal_is_ok(ov)) {
639 err = -EBUSY;
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200640 goto out;
641 }
642
Alan Tull39a842e2016-11-01 14:14:22 -0500643 of_overlay_notify(ov, OF_OVERLAY_PRE_REMOVE);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200644 list_del(&ov->node);
Gavin Shan18322372015-11-05 00:12:49 +1100645 __of_changeset_revert(&ov->cset);
Alan Tull39a842e2016-11-01 14:14:22 -0500646 of_overlay_notify(ov, OF_OVERLAY_POST_REMOVE);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200647 of_free_overlay_info(ov);
648 idr_remove(&ov_idr, id);
649 of_changeset_destroy(&ov->cset);
650 kfree(ov);
651
652 err = 0;
653
654out:
655 mutex_unlock(&of_mutex);
656
657 return err;
658}
659EXPORT_SYMBOL_GPL(of_overlay_destroy);
660
661/**
662 * of_overlay_destroy_all() - Removes all overlays from the system
663 *
664 * Removes all overlays from the system in the correct order.
665 *
Geert Uytterhoeven94a8bf92015-05-21 14:10:26 +0200666 * Returns 0 on success, or a negative error number
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200667 */
668int of_overlay_destroy_all(void)
669{
670 struct of_overlay *ov, *ovn;
671
672 mutex_lock(&of_mutex);
673
674 /* the tail of list is guaranteed to be safe to remove */
675 list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) {
676 list_del(&ov->node);
Gavin Shan18322372015-11-05 00:12:49 +1100677 __of_changeset_revert(&ov->cset);
Pantelis Antoniou7518b5892014-10-28 22:35:58 +0200678 of_free_overlay_info(ov);
679 idr_remove(&ov_idr, ov->id);
680 kfree(ov);
681 }
682
683 mutex_unlock(&of_mutex);
684
685 return 0;
686}
687EXPORT_SYMBOL_GPL(of_overlay_destroy_all);