aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPantelis Antoniou <pantelis.antoniou@konsulko.com>2014-10-28 16:35:58 -0400
committerGrant Likely <grant.likely@linaro.org>2014-11-24 17:25:10 -0500
commit7518b5890d8ac366faa2326ce2356ef6392ce63d (patch)
treee09fd7f3aa6613b70878c82b1cd372570eb2d503
parent801d728c10db4b28e01590b46bf1f0df930760cc (diff)
of/overlay: Introduce DT overlay support
Overlays are a method to dynamically modify part of the kernel's device tree with dynamically loaded data. Add the core functionality to parse, apply and remove an overlay changeset. The core functionality takes care of managing the overlay data format and performing the add and remove. Drivers are expected to use the overlay functionality to support custom expansion busses commonly found on consumer development boards like the BeagleBone or Raspberry Pi. The overlay code uses CONFIG_OF_DYNAMIC changesets to perform the low level work of modifying the devicetree. Documentation about internal and APIs is provided in Documentation/devicetree/overlay-notes.txt v2: - Switch from __of_node_alloc() to __of_node_dup() - Documentation fixups - Remove 2-pass processing of properties - Remove separate ov_lock; just use the DT mutex. v1: - Drop delete capability using '-' prefix. The '-' prefixed names are valid properties and nodes and there is no need for it just yet. - Do not update special properties - name & phandle ones. - Change order of node attachment, so that the special property update works. Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> Signed-off-by: Grant Likely <grant.likely@linaro.org>
-rw-r--r--Documentation/devicetree/overlay-notes.txt133
-rw-r--r--drivers/of/Kconfig7
-rw-r--r--drivers/of/Makefile1
-rw-r--r--drivers/of/overlay.c562
-rw-r--r--include/linux/of.h31
5 files changed, 734 insertions, 0 deletions
diff --git a/Documentation/devicetree/overlay-notes.txt b/Documentation/devicetree/overlay-notes.txt
new file mode 100644
index 000000000000..30ae758e3eef
--- /dev/null
+++ b/Documentation/devicetree/overlay-notes.txt
@@ -0,0 +1,133 @@
1Device Tree Overlay Notes
2-------------------------
3
4This document describes the implementation of the in-kernel
5device tree overlay functionality residing in drivers/of/overlay.c and is a
6companion document to Documentation/devicetree/dt-object-internal.txt[1] &
7Documentation/devicetree/dynamic-resolution-notes.txt[2]
8
9How overlays work
10-----------------
11
12A Device Tree's overlay purpose is to modify the kernel's live tree, and
13have the modification affecting the state of the the kernel in a way that
14is reflecting the changes.
15Since the kernel mainly deals with devices, any new device node that result
16in an active device should have it created while if the device node is either
17disabled or removed all together, the affected device should be deregistered.
18
19Lets take an example where we have a foo board with the following base tree
20which is taken from [1].
21
22---- foo.dts -----------------------------------------------------------------
23 /* FOO platform */
24 / {
25 compatible = "corp,foo";
26
27 /* shared resources */
28 res: res {
29 };
30
31 /* On chip peripherals */
32 ocp: ocp {
33 /* peripherals that are always instantiated */
34 peripheral1 { ... };
35 }
36 };
37---- foo.dts -----------------------------------------------------------------
38
39The overlay bar.dts, when loaded (and resolved as described in [2]) should
40
41---- bar.dts -----------------------------------------------------------------
42/plugin/; /* allow undefined label references and record them */
43/ {
44 .... /* various properties for loader use; i.e. part id etc. */
45 fragment@0 {
46 target = <&ocp>;
47 __overlay__ {
48 /* bar peripheral */
49 bar {
50 compatible = "corp,bar";
51 ... /* various properties and child nodes */
52 }
53 };
54 };
55};
56---- bar.dts -----------------------------------------------------------------
57
58result in foo+bar.dts
59
60---- foo+bar.dts -------------------------------------------------------------
61 /* FOO platform + bar peripheral */
62 / {
63 compatible = "corp,foo";
64
65 /* shared resources */
66 res: res {
67 };
68
69 /* On chip peripherals */
70 ocp: ocp {
71 /* peripherals that are always instantiated */
72 peripheral1 { ... };
73
74 /* bar peripheral */
75 bar {
76 compatible = "corp,bar";
77 ... /* various properties and child nodes */
78 }
79 }
80 };
81---- foo+bar.dts -------------------------------------------------------------
82
83As a result of the the overlay, a new device node (bar) has been created
84so a bar platform device will be registered and if a matching device driver
85is loaded the device will be created as expected.
86
87Overlay in-kernel API
88--------------------------------
89
90The API is quite easy to use.
91
921. Call of_overlay_create() to create and apply an overlay. The return value
93is a cookie identifying this overlay.
94
952. Call of_overlay_destroy() to remove and cleanup the overlay previously
96created via the call to of_overlay_create(). Removal of an overlay that
97is stacked by another will not be permitted.
98
99Finally, if you need to remove all overlays in one-go, just call
100of_overlay_destroy_all() which will remove every single one in the correct
101order.
102
103Overlay DTS Format
104------------------
105
106The DTS of an overlay should have the following format:
107
108{
109 /* ignored properties by the overlay */
110
111 fragment@0 { /* first child node */
112
113 target=<phandle>; /* phandle target of the overlay */
114 or
115 target-path="/path"; /* target path of the overlay */
116
117 __overlay__ {
118 property-a; /* add property-a to the target */
119 node-a { /* add to an existing, or create a node-a */
120 ...
121 };
122 };
123 }
124 fragment@1 { /* second child node */
125 ...
126 };
127 /* more fragments follow */
128}
129
130Using the non-phandle based target method allows one to use a base DT which does
131not contain a __symbols__ node, i.e. it was not compiled with the -@ option.
132The __symbols__ node is only required for the target=<phandle> method, since it
133contains the information required to map from a phandle to a tree location.
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig
index fbe8f8d418f7..18b2e2539f84 100644
--- a/drivers/of/Kconfig
+++ b/drivers/of/Kconfig
@@ -84,4 +84,11 @@ config OF_RESERVED_MEM
84config OF_RESOLVE 84config OF_RESOLVE
85 bool 85 bool
86 86
87config OF_OVERLAY
88 bool
89 depends on OF
90 select OF_DYNAMIC
91 select OF_DEVICE
92 select OF_RESOLVE
93
87endmenu # OF 94endmenu # OF
diff --git a/drivers/of/Makefile b/drivers/of/Makefile
index d90553fcd37f..7563f36c71db 100644
--- a/drivers/of/Makefile
+++ b/drivers/of/Makefile
@@ -14,6 +14,7 @@ obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o
14obj-$(CONFIG_OF_MTD) += of_mtd.o 14obj-$(CONFIG_OF_MTD) += of_mtd.o
15obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o 15obj-$(CONFIG_OF_RESERVED_MEM) += of_reserved_mem.o
16obj-$(CONFIG_OF_RESOLVE) += resolver.o 16obj-$(CONFIG_OF_RESOLVE) += resolver.o
17obj-$(CONFIG_OF_OVERLAY) += overlay.o
17 18
18CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt 19CFLAGS_fdt.o = -I$(src)/../../scripts/dtc/libfdt
19CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt 20CFLAGS_fdt_address.o = -I$(src)/../../scripts/dtc/libfdt
diff --git a/drivers/of/overlay.c b/drivers/of/overlay.c
new file mode 100644
index 000000000000..ea63fbd228ed
--- /dev/null
+++ b/drivers/of/overlay.c
@@ -0,0 +1,562 @@
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 */
11#undef DEBUG
12#include <linux/kernel.h>
13#include <linux/module.h>
14#include <linux/of.h>
15#include <linux/of_device.h>
16#include <linux/string.h>
17#include <linux/ctype.h>
18#include <linux/errno.h>
19#include <linux/string.h>
20#include <linux/slab.h>
21#include <linux/err.h>
22
23#include "of_private.h"
24
25/**
26 * struct of_overlay_info - Holds a single overlay info
27 * @target: target of the overlay operation
28 * @overlay: pointer to the overlay contents node
29 *
30 * Holds a single overlay state, including all the overlay logs &
31 * records.
32 */
33struct of_overlay_info {
34 struct device_node *target;
35 struct device_node *overlay;
36};
37
38/**
39 * struct of_overlay - Holds a complete overlay transaction
40 * @node: List on which we are located
41 * @count: Count of ovinfo structures
42 * @ovinfo_tab: Overlay info table (count sized)
43 * @cset: Changeset to be used
44 *
45 * Holds a complete overlay transaction
46 */
47struct of_overlay {
48 int id;
49 struct list_head node;
50 int count;
51 struct of_overlay_info *ovinfo_tab;
52 struct of_changeset cset;
53};
54
55static int of_overlay_apply_one(struct of_overlay *ov,
56 struct device_node *target, const struct device_node *overlay);
57
58static int of_overlay_apply_single_property(struct of_overlay *ov,
59 struct device_node *target, struct property *prop)
60{
61 struct property *propn, *tprop;
62
63 /* NOTE: Multiple changes of single properties not supported */
64 tprop = of_find_property(target, prop->name, NULL);
65
66 /* special properties are not meant to be updated (silent NOP) */
67 if (of_prop_cmp(prop->name, "name") == 0 ||
68 of_prop_cmp(prop->name, "phandle") == 0 ||
69 of_prop_cmp(prop->name, "linux,phandle") == 0)
70 return 0;
71
72 propn = __of_prop_dup(prop, GFP_KERNEL);
73 if (propn == NULL)
74 return -ENOMEM;
75
76 /* not found? add */
77 if (tprop == NULL)
78 return of_changeset_add_property(&ov->cset, target, propn);
79
80 /* found? update */
81 return of_changeset_update_property(&ov->cset, target, propn);
82}
83
84static int of_overlay_apply_single_device_node(struct of_overlay *ov,
85 struct device_node *target, struct device_node *child)
86{
87 const char *cname;
88 struct device_node *tchild, *grandchild;
89 int ret = 0;
90
91 cname = kbasename(child->full_name);
92 if (cname == NULL)
93 return -ENOMEM;
94
95 /* NOTE: Multiple mods of created nodes not supported */
96 tchild = of_get_child_by_name(target, cname);
97 if (tchild != NULL) {
98 /* apply overlay recursively */
99 ret = of_overlay_apply_one(ov, tchild, child);
100 of_node_put(tchild);
101 } else {
102 /* create empty tree as a target */
103 tchild = __of_node_dup(child, "%s/%s", target->full_name, cname);
104 if (!tchild)
105 return -ENOMEM;
106
107 /* point to parent */
108 tchild->parent = target;
109
110 ret = of_changeset_attach_node(&ov->cset, tchild);
111 if (ret)
112 return ret;
113
114 ret = of_overlay_apply_one(ov, tchild, child);
115 if (ret)
116 return ret;
117
118 /* The properties are already copied, now do the child nodes */
119 for_each_child_of_node(child, grandchild) {
120 ret = of_overlay_apply_single_device_node(ov, tchild, grandchild);
121 if (ret) {
122 pr_err("%s: Failed to apply single node @%s/%s\n",
123 __func__, tchild->full_name,
124 grandchild->name);
125 return ret;
126 }
127 }
128 }
129
130 return ret;
131}
132
133/*
134 * Apply a single overlay node recursively.
135 *
136 * Note that the in case of an error the target node is left
137 * in a inconsistent state. Error recovery should be performed
138 * by using the changeset.
139 */
140static int of_overlay_apply_one(struct of_overlay *ov,
141 struct device_node *target, const struct device_node *overlay)
142{
143 struct device_node *child;
144 struct property *prop;
145 int ret;
146
147 for_each_property_of_node(overlay, prop) {
148 ret = of_overlay_apply_single_property(ov, target, prop);
149 if (ret) {
150 pr_err("%s: Failed to apply prop @%s/%s\n",
151 __func__, target->full_name, prop->name);
152 return ret;
153 }
154 }
155
156 for_each_child_of_node(overlay, child) {
157 ret = of_overlay_apply_single_device_node(ov, target, child);
158 if (ret != 0) {
159 pr_err("%s: Failed to apply single node @%s/%s\n",
160 __func__, target->full_name,
161 child->name);
162 return ret;
163 }
164 }
165
166 return 0;
167}
168
169/**
170 * of_overlay_apply() - Apply @count overlays pointed at by @ovinfo_tab
171 * @ov: Overlay to apply
172 *
173 * Applies the overlays given, while handling all error conditions
174 * appropriately. Either the operation succeeds, or if it fails the
175 * live tree is reverted to the state before the attempt.
176 * Returns 0, or an error if the overlay attempt failed.
177 */
178static int of_overlay_apply(struct of_overlay *ov)
179{
180 int i, err;
181
182 /* first we apply the overlays atomically */
183 for (i = 0; i < ov->count; i++) {
184 struct of_overlay_info *ovinfo = &ov->ovinfo_tab[i];
185
186 err = of_overlay_apply_one(ov, ovinfo->target, ovinfo->overlay);
187 if (err != 0) {
188 pr_err("%s: overlay failed '%s'\n",
189 __func__, ovinfo->target->full_name);
190 return err;
191 }
192 }
193
194 return 0;
195}
196
197/*
198 * Find the target node using a number of different strategies
199 * in order of preference
200 *
201 * "target" property containing the phandle of the target
202 * "target-path" property containing the path of the target
203 */
204static struct device_node *find_target_node(struct device_node *info_node)
205{
206 const char *path;
207 u32 val;
208 int ret;
209
210 /* first try to go by using the target as a phandle */
211 ret = of_property_read_u32(info_node, "target", &val);
212 if (ret == 0)
213 return of_find_node_by_phandle(val);
214
215 /* now try to locate by path */
216 ret = of_property_read_string(info_node, "target-path", &path);
217 if (ret == 0)
218 return of_find_node_by_path(path);
219
220 pr_err("%s: Failed to find target for node %p (%s)\n", __func__,
221 info_node, info_node->name);
222
223 return NULL;
224}
225
226/**
227 * of_fill_overlay_info() - Fill an overlay info structure
228 * @ov Overlay to fill
229 * @info_node: Device node containing the overlay
230 * @ovinfo: Pointer to the overlay info structure to fill
231 *
232 * Fills an overlay info structure with the overlay information
233 * from a device node. This device node must have a target property
234 * which contains a phandle of the overlay target node, and an
235 * __overlay__ child node which has the overlay contents.
236 * Both ovinfo->target & ovinfo->overlay have their references taken.
237 *
238 * Returns 0 on success, or a negative error value.
239 */
240static int of_fill_overlay_info(struct of_overlay *ov,
241 struct device_node *info_node, struct of_overlay_info *ovinfo)
242{
243 ovinfo->overlay = of_get_child_by_name(info_node, "__overlay__");
244 if (ovinfo->overlay == NULL)
245 goto err_fail;
246
247 ovinfo->target = find_target_node(info_node);
248 if (ovinfo->target == NULL)
249 goto err_fail;
250
251 return 0;
252
253err_fail:
254 of_node_put(ovinfo->target);
255 of_node_put(ovinfo->overlay);
256
257 memset(ovinfo, 0, sizeof(*ovinfo));
258 return -EINVAL;
259}
260
261/**
262 * of_build_overlay_info() - Build an overlay info array
263 * @ov Overlay to build
264 * @tree: Device node containing all the overlays
265 *
266 * Helper function that given a tree containing overlay information,
267 * allocates and builds an overlay info array containing it, ready
268 * for use using of_overlay_apply.
269 *
270 * Returns 0 on success with the @cntp @ovinfop pointers valid,
271 * while on error a negative error value is returned.
272 */
273static int of_build_overlay_info(struct of_overlay *ov,
274 struct device_node *tree)
275{
276 struct device_node *node;
277 struct of_overlay_info *ovinfo;
278 int cnt, err;
279
280 /* worst case; every child is a node */
281 cnt = 0;
282 for_each_child_of_node(tree, node)
283 cnt++;
284
285 ovinfo = kcalloc(cnt, sizeof(*ovinfo), GFP_KERNEL);
286 if (ovinfo == NULL)
287 return -ENOMEM;
288
289 cnt = 0;
290 for_each_child_of_node(tree, node) {
291 memset(&ovinfo[cnt], 0, sizeof(*ovinfo));
292 err = of_fill_overlay_info(ov, node, &ovinfo[cnt]);
293 if (err == 0)
294 cnt++;
295 }
296
297 /* if nothing filled, return error */
298 if (cnt == 0) {
299 kfree(ovinfo);
300 return -ENODEV;
301 }
302
303 ov->count = cnt;
304 ov->ovinfo_tab = ovinfo;
305
306 return 0;
307}
308
309/**
310 * of_free_overlay_info() - Free an overlay info array
311 * @ov Overlay to free the overlay info from
312 * @ovinfo_tab: Array of overlay_info's to free
313 *
314 * Releases the memory of a previously allocated ovinfo array
315 * by of_build_overlay_info.
316 * Returns 0, or an error if the arguments are bogus.
317 */
318static int of_free_overlay_info(struct of_overlay *ov)
319{
320 struct of_overlay_info *ovinfo;
321 int i;
322
323 /* do it in reverse */
324 for (i = ov->count - 1; i >= 0; i--) {
325 ovinfo = &ov->ovinfo_tab[i];
326
327 of_node_put(ovinfo->target);
328 of_node_put(ovinfo->overlay);
329 }
330 kfree(ov->ovinfo_tab);
331
332 return 0;
333}
334
335static LIST_HEAD(ov_list);
336static DEFINE_IDR(ov_idr);
337
338/**
339 * of_overlay_create() - Create and apply an overlay
340 * @tree: Device node containing all the overlays
341 *
342 * Creates and applies an overlay while also keeping track
343 * of the overlay in a list. This list can be used to prevent
344 * illegal overlay removals.
345 *
346 * Returns the id of the created overlay, or an negative error number
347 */
348int of_overlay_create(struct device_node *tree)
349{
350 struct of_overlay *ov;
351 int err, id;
352
353 /* allocate the overlay structure */
354 ov = kzalloc(sizeof(*ov), GFP_KERNEL);
355 if (ov == NULL)
356 return -ENOMEM;
357 ov->id = -1;
358
359 INIT_LIST_HEAD(&ov->node);
360
361 of_changeset_init(&ov->cset);
362
363 mutex_lock(&of_mutex);
364
365 id = idr_alloc(&ov_idr, ov, 0, 0, GFP_KERNEL);
366 if (id < 0) {
367 pr_err("%s: idr_alloc() failed for tree@%s\n",
368 __func__, tree->full_name);
369 err = id;
370 goto err_destroy_trans;
371 }
372 ov->id = id;
373
374 /* build the overlay info structures */
375 err = of_build_overlay_info(ov, tree);
376 if (err) {
377 pr_err("%s: of_build_overlay_info() failed for tree@%s\n",
378 __func__, tree->full_name);
379 goto err_free_idr;
380 }
381
382 /* apply the overlay */
383 err = of_overlay_apply(ov);
384 if (err) {
385 pr_err("%s: of_overlay_apply() failed for tree@%s\n",
386 __func__, tree->full_name);
387 goto err_abort_trans;
388 }
389
390 /* apply the changeset */
391 err = of_changeset_apply(&ov->cset);
392 if (err) {
393 pr_err("%s: of_changeset_apply() failed for tree@%s\n",
394 __func__, tree->full_name);
395 goto err_revert_overlay;
396 }
397
398 /* add to the tail of the overlay list */
399 list_add_tail(&ov->node, &ov_list);
400
401 mutex_unlock(&of_mutex);
402
403 return id;
404
405err_revert_overlay:
406err_abort_trans:
407 of_free_overlay_info(ov);
408err_free_idr:
409 idr_remove(&ov_idr, ov->id);
410err_destroy_trans:
411 of_changeset_destroy(&ov->cset);
412 kfree(ov);
413 mutex_unlock(&of_mutex);
414
415 return err;
416}
417EXPORT_SYMBOL_GPL(of_overlay_create);
418
419/* check whether the given node, lies under the given tree */
420static int overlay_subtree_check(struct device_node *tree,
421 struct device_node *dn)
422{
423 struct device_node *child;
424
425 /* match? */
426 if (tree == dn)
427 return 1;
428
429 for_each_child_of_node(tree, child) {
430 if (overlay_subtree_check(child, dn))
431 return 1;
432 }
433
434 return 0;
435}
436
437/* check whether this overlay is the topmost */
438static int overlay_is_topmost(struct of_overlay *ov, struct device_node *dn)
439{
440 struct of_overlay *ovt;
441 struct of_changeset_entry *ce;
442
443 list_for_each_entry_reverse(ovt, &ov_list, node) {
444 /* if we hit ourselves, we're done */
445 if (ovt == ov)
446 break;
447
448 /* check against each subtree affected by this overlay */
449 list_for_each_entry(ce, &ovt->cset.entries, node) {
450 if (overlay_subtree_check(ce->np, dn)) {
451 pr_err("%s: #%d clashes #%d @%s\n",
452 __func__, ov->id, ovt->id,
453 dn->full_name);
454 return 0;
455 }
456 }
457 }
458
459 /* overlay is topmost */
460 return 1;
461}
462
463/*
464 * We can safely remove the overlay only if it's the top-most one.
465 * Newly applied overlays are inserted at the tail of the overlay list,
466 * so a top most overlay is the one that is closest to the tail.
467 *
468 * The topmost check is done by exploiting this property. For each
469 * affected device node in the log list we check if this overlay is
470 * the one closest to the tail. If another overlay has affected this
471 * device node and is closest to the tail, then removal is not permited.
472 */
473static int overlay_removal_is_ok(struct of_overlay *ov)
474{
475 struct of_changeset_entry *ce;
476
477 list_for_each_entry(ce, &ov->cset.entries, node) {
478 if (!overlay_is_topmost(ov, ce->np)) {
479 pr_err("%s: overlay #%d is not topmost\n",
480 __func__, ov->id);
481 return 0;
482 }
483 }
484
485 return 1;
486}
487
488/**
489 * of_overlay_destroy() - Removes an overlay
490 * @id: Overlay id number returned by a previous call to of_overlay_create
491 *
492 * Removes an overlay if it is permissible.
493 *
494 * Returns 0 on success, or an negative error number
495 */
496int of_overlay_destroy(int id)
497{
498 struct of_overlay *ov;
499 int err;
500
501 mutex_lock(&of_mutex);
502
503 ov = idr_find(&ov_idr, id);
504 if (ov == NULL) {
505 err = -ENODEV;
506 pr_err("%s: Could not find overlay #%d\n",
507 __func__, id);
508 goto out;
509 }
510
511 /* check whether the overlay is safe to remove */
512 if (!overlay_removal_is_ok(ov)) {
513 err = -EBUSY;
514 pr_err("%s: removal check failed for overlay #%d\n",
515 __func__, id);
516 goto out;
517 }
518
519
520 list_del(&ov->node);
521 of_changeset_revert(&ov->cset);
522 of_free_overlay_info(ov);
523 idr_remove(&ov_idr, id);
524 of_changeset_destroy(&ov->cset);
525 kfree(ov);
526
527 err = 0;
528
529out:
530 mutex_unlock(&of_mutex);
531
532 return err;
533}
534EXPORT_SYMBOL_GPL(of_overlay_destroy);
535
536/**
537 * of_overlay_destroy_all() - Removes all overlays from the system
538 *
539 * Removes all overlays from the system in the correct order.
540 *
541 * Returns 0 on success, or an negative error number
542 */
543int of_overlay_destroy_all(void)
544{
545 struct of_overlay *ov, *ovn;
546
547 mutex_lock(&of_mutex);
548
549 /* the tail of list is guaranteed to be safe to remove */
550 list_for_each_entry_safe_reverse(ov, ovn, &ov_list, node) {
551 list_del(&ov->node);
552 of_changeset_revert(&ov->cset);
553 of_free_overlay_info(ov);
554 idr_remove(&ov_idr, ov->id);
555 kfree(ov);
556 }
557
558 mutex_unlock(&of_mutex);
559
560 return 0;
561}
562EXPORT_SYMBOL_GPL(of_overlay_destroy_all);
diff --git a/include/linux/of.h b/include/linux/of.h
index fe1dec87fd68..aa01cf5852f8 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -23,6 +23,7 @@
23#include <linux/spinlock.h> 23#include <linux/spinlock.h>
24#include <linux/topology.h> 24#include <linux/topology.h>
25#include <linux/notifier.h> 25#include <linux/notifier.h>
26#include <linux/list.h>
26 27
27#include <asm/byteorder.h> 28#include <asm/byteorder.h>
28#include <asm/errno.h> 29#include <asm/errno.h>
@@ -957,4 +958,34 @@ static inline int of_reconfig_get_state_change(unsigned long action,
957/* CONFIG_OF_RESOLVE api */ 958/* CONFIG_OF_RESOLVE api */
958extern int of_resolve_phandles(struct device_node *tree); 959extern int of_resolve_phandles(struct device_node *tree);
959 960
961/**
962 * Overlay support
963 */
964
965#ifdef CONFIG_OF_OVERLAY
966
967/* ID based overlays; the API for external users */
968int of_overlay_create(struct device_node *tree);
969int of_overlay_destroy(int id);
970int of_overlay_destroy_all(void);
971
972#else
973
974static inline int of_overlay_create(struct device_node *tree)
975{
976 return -ENOTSUPP;
977}
978
979static inline int of_overlay_destroy(int id)
980{
981 return -ENOTSUPP;
982}
983
984static inline int of_overlay_destroy_all(void)
985{
986 return -ENOTSUPP;
987}
988
989#endif
990
960#endif /* _LINUX_OF_H */ 991#endif /* _LINUX_OF_H */