diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-14 11:53:39 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-14 11:53:39 -0400 |
commit | ae36e95cf81c98b111b84317adeb358aaffa80e2 (patch) | |
tree | 87ef144d3392cca199448117a737c657b7c4663a /drivers/of/dynamic.c | |
parent | cc8a44c671fd3a2c792e9e1f59ea1df52697cc8b (diff) | |
parent | 663d3f7c2e5e1b018a4c53277ccfde40329d98ca (diff) |
Merge tag 'devicetree-for-linus' of git://git.secretlab.ca/git/linux
Pull device tree updates from Grant Likely:
"The branch contains the following device tree changes the v3.17 merge
window:
Group changes to the device tree. In preparation for adding device
tree overlay support, OF_DYNAMIC is reworked so that a set of device
tree changes can be prepared and applied to the tree all at once.
OF_RECONFIG notifiers see the most significant change here so that
users always get a consistent view of the tree. Notifiers generation
is moved from before a change to after it, and notifiers for a group
of changes are emitted after the entire block of changes have been
applied
Automatic console selection from DT. Console drivers can now use
of_console_check() to see if the device node is specified as a console
device. If so then it gets added as a preferred console. UART
devices get this support automatically when uart_add_one_port() is
called.
DT unit tests no longer depend on pre-loaded data in the device tree.
Data is loaded dynamically at the start of unit tests, and then
unloaded again when the tests have completed.
Also contains a few bugfixes for reserved regions and early memory
setup"
* tag 'devicetree-for-linus' of git://git.secretlab.ca/git/linux: (21 commits)
of: Fixing OF Selftest build error
drivers: of: add automated assignment of reserved regions to client devices
of: Use proper types for checking memory overflow
of: typo fix in __of_prop_dup()
Adding selftest testdata dynamically into live tree
of: Add todo tasklist for Devicetree
of: Transactional DT support.
of: Reorder device tree changes and notifiers
of: Move dynamic node fixups out of powerpc and into common code
of: Make sure attached nodes don't carry along extra children
of: Make devicetree sysfs update functions consistent.
of: Create unlocked versions of node and property add/remove functions
OF: Utility helper functions for dynamic nodes
of: Move CONFIG_OF_DYNAMIC code into a separate file
of: rename of_aliases_mutex to just of_mutex
of/platform: Fix of_platform_device_destroy iteration of devices
of: Migrate of_find_node_by_name() users to for_each_node_by_name()
tty: Update hypervisor tty drivers to use core stdout parsing code.
arm/versatile: Add the uart as the stdout device.
of: Enable console on serial ports specified by /chosen/stdout-path
...
Diffstat (limited to 'drivers/of/dynamic.c')
-rw-r--r-- | drivers/of/dynamic.c | 660 |
1 files changed, 660 insertions, 0 deletions
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c new file mode 100644 index 000000000000..54fecc49a1fe --- /dev/null +++ b/drivers/of/dynamic.c | |||
@@ -0,0 +1,660 @@ | |||
1 | /* | ||
2 | * Support for dynamic device trees. | ||
3 | * | ||
4 | * On some platforms, the device tree can be manipulated at runtime. | ||
5 | * The routines in this section support adding, removing and changing | ||
6 | * device tree nodes. | ||
7 | */ | ||
8 | |||
9 | #include <linux/of.h> | ||
10 | #include <linux/spinlock.h> | ||
11 | #include <linux/slab.h> | ||
12 | #include <linux/string.h> | ||
13 | #include <linux/proc_fs.h> | ||
14 | |||
15 | #include "of_private.h" | ||
16 | |||
17 | /** | ||
18 | * of_node_get() - Increment refcount of a node | ||
19 | * @node: Node to inc refcount, NULL is supported to simplify writing of | ||
20 | * callers | ||
21 | * | ||
22 | * Returns node. | ||
23 | */ | ||
24 | struct device_node *of_node_get(struct device_node *node) | ||
25 | { | ||
26 | if (node) | ||
27 | kobject_get(&node->kobj); | ||
28 | return node; | ||
29 | } | ||
30 | EXPORT_SYMBOL(of_node_get); | ||
31 | |||
32 | /** | ||
33 | * of_node_put() - Decrement refcount of a node | ||
34 | * @node: Node to dec refcount, NULL is supported to simplify writing of | ||
35 | * callers | ||
36 | */ | ||
37 | void of_node_put(struct device_node *node) | ||
38 | { | ||
39 | if (node) | ||
40 | kobject_put(&node->kobj); | ||
41 | } | ||
42 | EXPORT_SYMBOL(of_node_put); | ||
43 | |||
44 | void __of_detach_node_sysfs(struct device_node *np) | ||
45 | { | ||
46 | struct property *pp; | ||
47 | |||
48 | BUG_ON(!of_node_is_initialized(np)); | ||
49 | if (!of_kset) | ||
50 | return; | ||
51 | |||
52 | /* only remove properties if on sysfs */ | ||
53 | if (of_node_is_attached(np)) { | ||
54 | for_each_property_of_node(np, pp) | ||
55 | sysfs_remove_bin_file(&np->kobj, &pp->attr); | ||
56 | kobject_del(&np->kobj); | ||
57 | } | ||
58 | |||
59 | /* finally remove the kobj_init ref */ | ||
60 | of_node_put(np); | ||
61 | } | ||
62 | |||
63 | static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); | ||
64 | |||
65 | int of_reconfig_notifier_register(struct notifier_block *nb) | ||
66 | { | ||
67 | return blocking_notifier_chain_register(&of_reconfig_chain, nb); | ||
68 | } | ||
69 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_register); | ||
70 | |||
71 | int of_reconfig_notifier_unregister(struct notifier_block *nb) | ||
72 | { | ||
73 | return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); | ||
74 | } | ||
75 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); | ||
76 | |||
77 | int of_reconfig_notify(unsigned long action, void *p) | ||
78 | { | ||
79 | int rc; | ||
80 | |||
81 | rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); | ||
82 | return notifier_to_errno(rc); | ||
83 | } | ||
84 | |||
85 | int of_property_notify(int action, struct device_node *np, | ||
86 | struct property *prop, struct property *oldprop) | ||
87 | { | ||
88 | struct of_prop_reconfig pr; | ||
89 | |||
90 | /* only call notifiers if the node is attached */ | ||
91 | if (!of_node_is_attached(np)) | ||
92 | return 0; | ||
93 | |||
94 | pr.dn = np; | ||
95 | pr.prop = prop; | ||
96 | pr.old_prop = oldprop; | ||
97 | return of_reconfig_notify(action, &pr); | ||
98 | } | ||
99 | |||
100 | void __of_attach_node(struct device_node *np) | ||
101 | { | ||
102 | const __be32 *phandle; | ||
103 | int sz; | ||
104 | |||
105 | np->name = __of_get_property(np, "name", NULL) ? : "<NULL>"; | ||
106 | np->type = __of_get_property(np, "device_type", NULL) ? : "<NULL>"; | ||
107 | |||
108 | phandle = __of_get_property(np, "phandle", &sz); | ||
109 | if (!phandle) | ||
110 | phandle = __of_get_property(np, "linux,phandle", &sz); | ||
111 | if (IS_ENABLED(PPC_PSERIES) && !phandle) | ||
112 | phandle = __of_get_property(np, "ibm,phandle", &sz); | ||
113 | np->phandle = (phandle && (sz >= 4)) ? be32_to_cpup(phandle) : 0; | ||
114 | |||
115 | np->child = NULL; | ||
116 | np->sibling = np->parent->child; | ||
117 | np->allnext = np->parent->allnext; | ||
118 | np->parent->allnext = np; | ||
119 | np->parent->child = np; | ||
120 | of_node_clear_flag(np, OF_DETACHED); | ||
121 | } | ||
122 | |||
123 | /** | ||
124 | * of_attach_node() - Plug a device node into the tree and global list. | ||
125 | */ | ||
126 | int of_attach_node(struct device_node *np) | ||
127 | { | ||
128 | unsigned long flags; | ||
129 | |||
130 | mutex_lock(&of_mutex); | ||
131 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
132 | __of_attach_node(np); | ||
133 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
134 | |||
135 | __of_attach_node_sysfs(np); | ||
136 | mutex_unlock(&of_mutex); | ||
137 | |||
138 | of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); | ||
139 | |||
140 | return 0; | ||
141 | } | ||
142 | |||
143 | void __of_detach_node(struct device_node *np) | ||
144 | { | ||
145 | struct device_node *parent; | ||
146 | |||
147 | if (WARN_ON(of_node_check_flag(np, OF_DETACHED))) | ||
148 | return; | ||
149 | |||
150 | parent = np->parent; | ||
151 | if (WARN_ON(!parent)) | ||
152 | return; | ||
153 | |||
154 | if (of_allnodes == np) | ||
155 | of_allnodes = np->allnext; | ||
156 | else { | ||
157 | struct device_node *prev; | ||
158 | for (prev = of_allnodes; | ||
159 | prev->allnext != np; | ||
160 | prev = prev->allnext) | ||
161 | ; | ||
162 | prev->allnext = np->allnext; | ||
163 | } | ||
164 | |||
165 | if (parent->child == np) | ||
166 | parent->child = np->sibling; | ||
167 | else { | ||
168 | struct device_node *prevsib; | ||
169 | for (prevsib = np->parent->child; | ||
170 | prevsib->sibling != np; | ||
171 | prevsib = prevsib->sibling) | ||
172 | ; | ||
173 | prevsib->sibling = np->sibling; | ||
174 | } | ||
175 | |||
176 | of_node_set_flag(np, OF_DETACHED); | ||
177 | } | ||
178 | |||
179 | /** | ||
180 | * of_detach_node() - "Unplug" a node from the device tree. | ||
181 | * | ||
182 | * The caller must hold a reference to the node. The memory associated with | ||
183 | * the node is not freed until its refcount goes to zero. | ||
184 | */ | ||
185 | int of_detach_node(struct device_node *np) | ||
186 | { | ||
187 | unsigned long flags; | ||
188 | int rc = 0; | ||
189 | |||
190 | mutex_lock(&of_mutex); | ||
191 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
192 | __of_detach_node(np); | ||
193 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
194 | |||
195 | __of_detach_node_sysfs(np); | ||
196 | mutex_unlock(&of_mutex); | ||
197 | |||
198 | of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); | ||
199 | |||
200 | return rc; | ||
201 | } | ||
202 | |||
203 | /** | ||
204 | * of_node_release() - release a dynamically allocated node | ||
205 | * @kref: kref element of the node to be released | ||
206 | * | ||
207 | * In of_node_put() this function is passed to kref_put() as the destructor. | ||
208 | */ | ||
209 | void of_node_release(struct kobject *kobj) | ||
210 | { | ||
211 | struct device_node *node = kobj_to_device_node(kobj); | ||
212 | struct property *prop = node->properties; | ||
213 | |||
214 | /* We should never be releasing nodes that haven't been detached. */ | ||
215 | if (!of_node_check_flag(node, OF_DETACHED)) { | ||
216 | pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); | ||
217 | dump_stack(); | ||
218 | return; | ||
219 | } | ||
220 | |||
221 | if (!of_node_check_flag(node, OF_DYNAMIC)) | ||
222 | return; | ||
223 | |||
224 | while (prop) { | ||
225 | struct property *next = prop->next; | ||
226 | kfree(prop->name); | ||
227 | kfree(prop->value); | ||
228 | kfree(prop); | ||
229 | prop = next; | ||
230 | |||
231 | if (!prop) { | ||
232 | prop = node->deadprops; | ||
233 | node->deadprops = NULL; | ||
234 | } | ||
235 | } | ||
236 | kfree(node->full_name); | ||
237 | kfree(node->data); | ||
238 | kfree(node); | ||
239 | } | ||
240 | |||
241 | /** | ||
242 | * __of_prop_dup - Copy a property dynamically. | ||
243 | * @prop: Property to copy | ||
244 | * @allocflags: Allocation flags (typically pass GFP_KERNEL) | ||
245 | * | ||
246 | * Copy a property by dynamically allocating the memory of both the | ||
247 | * property stucture and the property name & contents. The property's | ||
248 | * flags have the OF_DYNAMIC bit set so that we can differentiate between | ||
249 | * dynamically allocated properties and not. | ||
250 | * Returns the newly allocated property or NULL on out of memory error. | ||
251 | */ | ||
252 | struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags) | ||
253 | { | ||
254 | struct property *new; | ||
255 | |||
256 | new = kzalloc(sizeof(*new), allocflags); | ||
257 | if (!new) | ||
258 | return NULL; | ||
259 | |||
260 | /* | ||
261 | * NOTE: There is no check for zero length value. | ||
262 | * In case of a boolean property, this will allocate a value | ||
263 | * of zero bytes. We do this to work around the use | ||
264 | * of of_get_property() calls on boolean values. | ||
265 | */ | ||
266 | new->name = kstrdup(prop->name, allocflags); | ||
267 | new->value = kmemdup(prop->value, prop->length, allocflags); | ||
268 | new->length = prop->length; | ||
269 | if (!new->name || !new->value) | ||
270 | goto err_free; | ||
271 | |||
272 | /* mark the property as dynamic */ | ||
273 | of_property_set_flag(new, OF_DYNAMIC); | ||
274 | |||
275 | return new; | ||
276 | |||
277 | err_free: | ||
278 | kfree(new->name); | ||
279 | kfree(new->value); | ||
280 | kfree(new); | ||
281 | return NULL; | ||
282 | } | ||
283 | |||
284 | /** | ||
285 | * __of_node_alloc() - Create an empty device node dynamically. | ||
286 | * @full_name: Full name of the new device node | ||
287 | * @allocflags: Allocation flags (typically pass GFP_KERNEL) | ||
288 | * | ||
289 | * Create an empty device tree node, suitable for further modification. | ||
290 | * The node data are dynamically allocated and all the node flags | ||
291 | * have the OF_DYNAMIC & OF_DETACHED bits set. | ||
292 | * Returns the newly allocated node or NULL on out of memory error. | ||
293 | */ | ||
294 | struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags) | ||
295 | { | ||
296 | struct device_node *node; | ||
297 | |||
298 | node = kzalloc(sizeof(*node), allocflags); | ||
299 | if (!node) | ||
300 | return NULL; | ||
301 | |||
302 | node->full_name = kstrdup(full_name, allocflags); | ||
303 | of_node_set_flag(node, OF_DYNAMIC); | ||
304 | of_node_set_flag(node, OF_DETACHED); | ||
305 | if (!node->full_name) | ||
306 | goto err_free; | ||
307 | |||
308 | of_node_init(node); | ||
309 | |||
310 | return node; | ||
311 | |||
312 | err_free: | ||
313 | kfree(node->full_name); | ||
314 | kfree(node); | ||
315 | return NULL; | ||
316 | } | ||
317 | |||
318 | static void __of_changeset_entry_destroy(struct of_changeset_entry *ce) | ||
319 | { | ||
320 | of_node_put(ce->np); | ||
321 | list_del(&ce->node); | ||
322 | kfree(ce); | ||
323 | } | ||
324 | |||
325 | #ifdef DEBUG | ||
326 | static void __of_changeset_entry_dump(struct of_changeset_entry *ce) | ||
327 | { | ||
328 | switch (ce->action) { | ||
329 | case OF_RECONFIG_ADD_PROPERTY: | ||
330 | pr_debug("%p: %s %s/%s\n", | ||
331 | ce, "ADD_PROPERTY ", ce->np->full_name, | ||
332 | ce->prop->name); | ||
333 | break; | ||
334 | case OF_RECONFIG_REMOVE_PROPERTY: | ||
335 | pr_debug("%p: %s %s/%s\n", | ||
336 | ce, "REMOVE_PROPERTY", ce->np->full_name, | ||
337 | ce->prop->name); | ||
338 | break; | ||
339 | case OF_RECONFIG_UPDATE_PROPERTY: | ||
340 | pr_debug("%p: %s %s/%s\n", | ||
341 | ce, "UPDATE_PROPERTY", ce->np->full_name, | ||
342 | ce->prop->name); | ||
343 | break; | ||
344 | case OF_RECONFIG_ATTACH_NODE: | ||
345 | pr_debug("%p: %s %s\n", | ||
346 | ce, "ATTACH_NODE ", ce->np->full_name); | ||
347 | break; | ||
348 | case OF_RECONFIG_DETACH_NODE: | ||
349 | pr_debug("%p: %s %s\n", | ||
350 | ce, "DETACH_NODE ", ce->np->full_name); | ||
351 | break; | ||
352 | } | ||
353 | } | ||
354 | #else | ||
355 | static inline void __of_changeset_entry_dump(struct of_changeset_entry *ce) | ||
356 | { | ||
357 | /* empty */ | ||
358 | } | ||
359 | #endif | ||
360 | |||
361 | static void __of_changeset_entry_invert(struct of_changeset_entry *ce, | ||
362 | struct of_changeset_entry *rce) | ||
363 | { | ||
364 | memcpy(rce, ce, sizeof(*rce)); | ||
365 | |||
366 | switch (ce->action) { | ||
367 | case OF_RECONFIG_ATTACH_NODE: | ||
368 | rce->action = OF_RECONFIG_DETACH_NODE; | ||
369 | break; | ||
370 | case OF_RECONFIG_DETACH_NODE: | ||
371 | rce->action = OF_RECONFIG_ATTACH_NODE; | ||
372 | break; | ||
373 | case OF_RECONFIG_ADD_PROPERTY: | ||
374 | rce->action = OF_RECONFIG_REMOVE_PROPERTY; | ||
375 | break; | ||
376 | case OF_RECONFIG_REMOVE_PROPERTY: | ||
377 | rce->action = OF_RECONFIG_ADD_PROPERTY; | ||
378 | break; | ||
379 | case OF_RECONFIG_UPDATE_PROPERTY: | ||
380 | rce->old_prop = ce->prop; | ||
381 | rce->prop = ce->old_prop; | ||
382 | break; | ||
383 | } | ||
384 | } | ||
385 | |||
386 | static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool revert) | ||
387 | { | ||
388 | struct of_changeset_entry ce_inverted; | ||
389 | int ret; | ||
390 | |||
391 | if (revert) { | ||
392 | __of_changeset_entry_invert(ce, &ce_inverted); | ||
393 | ce = &ce_inverted; | ||
394 | } | ||
395 | |||
396 | switch (ce->action) { | ||
397 | case OF_RECONFIG_ATTACH_NODE: | ||
398 | case OF_RECONFIG_DETACH_NODE: | ||
399 | ret = of_reconfig_notify(ce->action, ce->np); | ||
400 | break; | ||
401 | case OF_RECONFIG_ADD_PROPERTY: | ||
402 | case OF_RECONFIG_REMOVE_PROPERTY: | ||
403 | case OF_RECONFIG_UPDATE_PROPERTY: | ||
404 | ret = of_property_notify(ce->action, ce->np, ce->prop, ce->old_prop); | ||
405 | break; | ||
406 | default: | ||
407 | pr_err("%s: invalid devicetree changeset action: %i\n", __func__, | ||
408 | (int)ce->action); | ||
409 | return; | ||
410 | } | ||
411 | |||
412 | if (ret) | ||
413 | pr_err("%s: notifier error @%s\n", __func__, ce->np->full_name); | ||
414 | } | ||
415 | |||
416 | static int __of_changeset_entry_apply(struct of_changeset_entry *ce) | ||
417 | { | ||
418 | struct property *old_prop, **propp; | ||
419 | unsigned long flags; | ||
420 | int ret = 0; | ||
421 | |||
422 | __of_changeset_entry_dump(ce); | ||
423 | |||
424 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
425 | switch (ce->action) { | ||
426 | case OF_RECONFIG_ATTACH_NODE: | ||
427 | __of_attach_node(ce->np); | ||
428 | break; | ||
429 | case OF_RECONFIG_DETACH_NODE: | ||
430 | __of_detach_node(ce->np); | ||
431 | break; | ||
432 | case OF_RECONFIG_ADD_PROPERTY: | ||
433 | /* If the property is in deadprops then it must be removed */ | ||
434 | for (propp = &ce->np->deadprops; *propp; propp = &(*propp)->next) { | ||
435 | if (*propp == ce->prop) { | ||
436 | *propp = ce->prop->next; | ||
437 | ce->prop->next = NULL; | ||
438 | break; | ||
439 | } | ||
440 | } | ||
441 | |||
442 | ret = __of_add_property(ce->np, ce->prop); | ||
443 | if (ret) { | ||
444 | pr_err("%s: add_property failed @%s/%s\n", | ||
445 | __func__, ce->np->full_name, | ||
446 | ce->prop->name); | ||
447 | break; | ||
448 | } | ||
449 | break; | ||
450 | case OF_RECONFIG_REMOVE_PROPERTY: | ||
451 | ret = __of_remove_property(ce->np, ce->prop); | ||
452 | if (ret) { | ||
453 | pr_err("%s: remove_property failed @%s/%s\n", | ||
454 | __func__, ce->np->full_name, | ||
455 | ce->prop->name); | ||
456 | break; | ||
457 | } | ||
458 | break; | ||
459 | |||
460 | case OF_RECONFIG_UPDATE_PROPERTY: | ||
461 | /* If the property is in deadprops then it must be removed */ | ||
462 | for (propp = &ce->np->deadprops; *propp; propp = &(*propp)->next) { | ||
463 | if (*propp == ce->prop) { | ||
464 | *propp = ce->prop->next; | ||
465 | ce->prop->next = NULL; | ||
466 | break; | ||
467 | } | ||
468 | } | ||
469 | |||
470 | ret = __of_update_property(ce->np, ce->prop, &old_prop); | ||
471 | if (ret) { | ||
472 | pr_err("%s: update_property failed @%s/%s\n", | ||
473 | __func__, ce->np->full_name, | ||
474 | ce->prop->name); | ||
475 | break; | ||
476 | } | ||
477 | break; | ||
478 | default: | ||
479 | ret = -EINVAL; | ||
480 | } | ||
481 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
482 | |||
483 | if (ret) | ||
484 | return ret; | ||
485 | |||
486 | switch (ce->action) { | ||
487 | case OF_RECONFIG_ATTACH_NODE: | ||
488 | __of_attach_node_sysfs(ce->np); | ||
489 | break; | ||
490 | case OF_RECONFIG_DETACH_NODE: | ||
491 | __of_detach_node_sysfs(ce->np); | ||
492 | break; | ||
493 | case OF_RECONFIG_ADD_PROPERTY: | ||
494 | /* ignore duplicate names */ | ||
495 | __of_add_property_sysfs(ce->np, ce->prop); | ||
496 | break; | ||
497 | case OF_RECONFIG_REMOVE_PROPERTY: | ||
498 | __of_remove_property_sysfs(ce->np, ce->prop); | ||
499 | break; | ||
500 | case OF_RECONFIG_UPDATE_PROPERTY: | ||
501 | __of_update_property_sysfs(ce->np, ce->prop, ce->old_prop); | ||
502 | break; | ||
503 | } | ||
504 | |||
505 | return 0; | ||
506 | } | ||
507 | |||
508 | static inline int __of_changeset_entry_revert(struct of_changeset_entry *ce) | ||
509 | { | ||
510 | struct of_changeset_entry ce_inverted; | ||
511 | |||
512 | __of_changeset_entry_invert(ce, &ce_inverted); | ||
513 | return __of_changeset_entry_apply(&ce_inverted); | ||
514 | } | ||
515 | |||
516 | /** | ||
517 | * of_changeset_init - Initialize a changeset for use | ||
518 | * | ||
519 | * @ocs: changeset pointer | ||
520 | * | ||
521 | * Initialize a changeset structure | ||
522 | */ | ||
523 | void of_changeset_init(struct of_changeset *ocs) | ||
524 | { | ||
525 | memset(ocs, 0, sizeof(*ocs)); | ||
526 | INIT_LIST_HEAD(&ocs->entries); | ||
527 | } | ||
528 | |||
529 | /** | ||
530 | * of_changeset_destroy - Destroy a changeset | ||
531 | * | ||
532 | * @ocs: changeset pointer | ||
533 | * | ||
534 | * Destroys a changeset. Note that if a changeset is applied, | ||
535 | * its changes to the tree cannot be reverted. | ||
536 | */ | ||
537 | void of_changeset_destroy(struct of_changeset *ocs) | ||
538 | { | ||
539 | struct of_changeset_entry *ce, *cen; | ||
540 | |||
541 | list_for_each_entry_safe_reverse(ce, cen, &ocs->entries, node) | ||
542 | __of_changeset_entry_destroy(ce); | ||
543 | } | ||
544 | |||
545 | /** | ||
546 | * of_changeset_apply - Applies a changeset | ||
547 | * | ||
548 | * @ocs: changeset pointer | ||
549 | * | ||
550 | * Applies a changeset to the live tree. | ||
551 | * Any side-effects of live tree state changes are applied here on | ||
552 | * sucess, like creation/destruction of devices and side-effects | ||
553 | * like creation of sysfs properties and directories. | ||
554 | * Returns 0 on success, a negative error value in case of an error. | ||
555 | * On error the partially applied effects are reverted. | ||
556 | */ | ||
557 | int of_changeset_apply(struct of_changeset *ocs) | ||
558 | { | ||
559 | struct of_changeset_entry *ce; | ||
560 | int ret; | ||
561 | |||
562 | /* perform the rest of the work */ | ||
563 | pr_debug("of_changeset: applying...\n"); | ||
564 | list_for_each_entry(ce, &ocs->entries, node) { | ||
565 | ret = __of_changeset_entry_apply(ce); | ||
566 | if (ret) { | ||
567 | pr_err("%s: Error applying changeset (%d)\n", __func__, ret); | ||
568 | list_for_each_entry_continue_reverse(ce, &ocs->entries, node) | ||
569 | __of_changeset_entry_revert(ce); | ||
570 | return ret; | ||
571 | } | ||
572 | } | ||
573 | pr_debug("of_changeset: applied, emitting notifiers.\n"); | ||
574 | |||
575 | /* drop the global lock while emitting notifiers */ | ||
576 | mutex_unlock(&of_mutex); | ||
577 | list_for_each_entry(ce, &ocs->entries, node) | ||
578 | __of_changeset_entry_notify(ce, 0); | ||
579 | mutex_lock(&of_mutex); | ||
580 | pr_debug("of_changeset: notifiers sent.\n"); | ||
581 | |||
582 | return 0; | ||
583 | } | ||
584 | |||
585 | /** | ||
586 | * of_changeset_revert - Reverts an applied changeset | ||
587 | * | ||
588 | * @ocs: changeset pointer | ||
589 | * | ||
590 | * Reverts a changeset returning the state of the tree to what it | ||
591 | * was before the application. | ||
592 | * Any side-effects like creation/destruction of devices and | ||
593 | * removal of sysfs properties and directories are applied. | ||
594 | * Returns 0 on success, a negative error value in case of an error. | ||
595 | */ | ||
596 | int of_changeset_revert(struct of_changeset *ocs) | ||
597 | { | ||
598 | struct of_changeset_entry *ce; | ||
599 | int ret; | ||
600 | |||
601 | pr_debug("of_changeset: reverting...\n"); | ||
602 | list_for_each_entry_reverse(ce, &ocs->entries, node) { | ||
603 | ret = __of_changeset_entry_revert(ce); | ||
604 | if (ret) { | ||
605 | pr_err("%s: Error reverting changeset (%d)\n", __func__, ret); | ||
606 | list_for_each_entry_continue(ce, &ocs->entries, node) | ||
607 | __of_changeset_entry_apply(ce); | ||
608 | return ret; | ||
609 | } | ||
610 | } | ||
611 | pr_debug("of_changeset: reverted, emitting notifiers.\n"); | ||
612 | |||
613 | /* drop the global lock while emitting notifiers */ | ||
614 | mutex_unlock(&of_mutex); | ||
615 | list_for_each_entry_reverse(ce, &ocs->entries, node) | ||
616 | __of_changeset_entry_notify(ce, 1); | ||
617 | mutex_lock(&of_mutex); | ||
618 | pr_debug("of_changeset: notifiers sent.\n"); | ||
619 | |||
620 | return 0; | ||
621 | } | ||
622 | |||
623 | /** | ||
624 | * of_changeset_action - Perform a changeset action | ||
625 | * | ||
626 | * @ocs: changeset pointer | ||
627 | * @action: action to perform | ||
628 | * @np: Pointer to device node | ||
629 | * @prop: Pointer to property | ||
630 | * | ||
631 | * On action being one of: | ||
632 | * + OF_RECONFIG_ATTACH_NODE | ||
633 | * + OF_RECONFIG_DETACH_NODE, | ||
634 | * + OF_RECONFIG_ADD_PROPERTY | ||
635 | * + OF_RECONFIG_REMOVE_PROPERTY, | ||
636 | * + OF_RECONFIG_UPDATE_PROPERTY | ||
637 | * Returns 0 on success, a negative error value in case of an error. | ||
638 | */ | ||
639 | int of_changeset_action(struct of_changeset *ocs, unsigned long action, | ||
640 | struct device_node *np, struct property *prop) | ||
641 | { | ||
642 | struct of_changeset_entry *ce; | ||
643 | |||
644 | ce = kzalloc(sizeof(*ce), GFP_KERNEL); | ||
645 | if (!ce) { | ||
646 | pr_err("%s: Failed to allocate\n", __func__); | ||
647 | return -ENOMEM; | ||
648 | } | ||
649 | /* get a reference to the node */ | ||
650 | ce->action = action; | ||
651 | ce->np = of_node_get(np); | ||
652 | ce->prop = prop; | ||
653 | |||
654 | if (action == OF_RECONFIG_UPDATE_PROPERTY && prop) | ||
655 | ce->old_prop = of_find_property(np, prop->name, NULL); | ||
656 | |||
657 | /* add it to the list */ | ||
658 | list_add_tail(&ce->node, &ocs->entries); | ||
659 | return 0; | ||
660 | } | ||