aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPantelis Antoniou <pantelis.antoniou@konsulko.com>2014-07-04 12:58:49 -0400
committerGrant Likely <grant.likely@linaro.org>2014-07-23 19:29:15 -0400
commit201c910bd6898d81d4ac6685d0f421b7e10f3c5d (patch)
treeaec8c406908e71c7ad89750c6e9f4f8d0c094747
parent259092a35c7e11f1d4616b0f5b3ba7b851fe4fa6 (diff)
of: Transactional DT support.
Introducing DT transactional support. A DT transaction is a method which allows one to apply changes in the live tree, in such a way that either the full set of changes take effect, or the state of the tree can be rolled-back to the state it was before it was attempted. An applied transaction can be rolled-back at any time. Documentation is in Documentation/devicetree/changesets.txt Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com> [glikely: Removed device notifiers and reworked to be more consistent] Signed-off-by: Grant Likely <grant.likely@linaro.org>
-rw-r--r--Documentation/devicetree/changesets.txt40
-rw-r--r--drivers/of/dynamic.c344
-rw-r--r--drivers/of/of_private.h9
-rw-r--r--drivers/of/selftest.c51
-rw-r--r--drivers/of/testcase-data/testcases.dtsi10
-rw-r--r--include/linux/of.h76
6 files changed, 530 insertions, 0 deletions
diff --git a/Documentation/devicetree/changesets.txt b/Documentation/devicetree/changesets.txt
new file mode 100644
index 000000000000..935ba5acc34e
--- /dev/null
+++ b/Documentation/devicetree/changesets.txt
@@ -0,0 +1,40 @@
1A DT changeset is a method which allows one to apply changes
2in the live tree in such a way that either the full set of changes
3will be applied, or none of them will be. If an error occurs partway
4through applying the changeset, then the tree will be rolled back to the
5previous state. A changeset can also be removed after it has been
6applied.
7
8When a changeset is applied, all of the changes get applied to the tree
9at once before emitting OF_RECONFIG notifiers. This is so that the
10receiver sees a complete and consistent state of the tree when it
11receives the notifier.
12
13The sequence of a changeset is as follows.
14
151. of_changeset_init() - initializes a changeset
16
172. A number of DT tree change calls, of_changeset_attach_node(),
18of_changeset_detach_node(), of_changeset_add_property(),
19of_changeset_remove_property, of_changeset_update_property() to prepare
20a set of changes. No changes to the active tree are made at this point.
21All the change operations are recorded in the of_changeset 'entries'
22list.
23
243. mutex_lock(of_mutex) - starts a changeset; The global of_mutex
25ensures there can only be one editor at a time.
26
274. of_changeset_apply() - Apply the changes to the tree. Either the
28entire changeset will get applied, or if there is an error the tree will
29be restored to the previous state
30
315. mutex_unlock(of_mutex) - All operations complete, release the mutex
32
33If a successfully applied changeset needs to be removed, it can be done
34with the following sequence.
35
361. mutex_lock(of_mutex)
37
382. of_changeset_revert()
39
403. mutex_unlock(of_mutex)
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 7bd5501736a6..c1002b7be786 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -314,3 +314,347 @@ struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags)
314 kfree(node); 314 kfree(node);
315 return NULL; 315 return NULL;
316} 316}
317
318static 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
326static 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
355static inline void __of_changeset_entry_dump(struct of_changeset_entry *ce)
356{
357 /* empty */
358}
359#endif
360
361static 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
386static 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
416static 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
508static 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 */
523void 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 */
537void 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 */
557int 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 */
596int 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 */
639int 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}
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h
index f69ccb1fa308..858e0a5d9a11 100644
--- a/drivers/of/of_private.h
+++ b/drivers/of/of_private.h
@@ -81,4 +81,13 @@ extern int __of_attach_node_sysfs(struct device_node *np);
81extern void __of_detach_node(struct device_node *np); 81extern void __of_detach_node(struct device_node *np);
82extern void __of_detach_node_sysfs(struct device_node *np); 82extern void __of_detach_node_sysfs(struct device_node *np);
83 83
84/* iterators for transactions, used for overlays */
85/* forward iterator */
86#define for_each_transaction_entry(_oft, _te) \
87 list_for_each_entry(_te, &(_oft)->te_list, node)
88
89/* reverse iterator */
90#define for_each_transaction_entry_reverse(_oft, _te) \
91 list_for_each_entry_reverse(_te, &(_oft)->te_list, node)
92
84#endif /* _LINUX_OF_PRIVATE_H */ 93#endif /* _LINUX_OF_PRIVATE_H */
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c
index ee2166f0f36a..04e39a183e53 100644
--- a/drivers/of/selftest.c
+++ b/drivers/of/selftest.c
@@ -293,6 +293,56 @@ static void __init of_selftest_property_copy(void)
293#endif 293#endif
294} 294}
295 295
296static void __init of_selftest_changeset(void)
297{
298#ifdef CONFIG_OF_DYNAMIC
299 struct property *ppadd, padd = { .name = "prop-add", .length = 0, .value = "" };
300 struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" };
301 struct property *ppremove;
302 struct device_node *n1, *n2, *n21, *nremove, *parent;
303 struct of_changeset chgset;
304
305 of_changeset_init(&chgset);
306 n1 = __of_node_alloc("/testcase-data/changeset/n1", GFP_KERNEL);
307 selftest(n1, "testcase setup failure\n");
308 n2 = __of_node_alloc("/testcase-data/changeset/n2", GFP_KERNEL);
309 selftest(n2, "testcase setup failure\n");
310 n21 = __of_node_alloc("/testcase-data/changeset/n2/n21", GFP_KERNEL);
311 selftest(n21, "testcase setup failure %p\n", n21);
312 nremove = of_find_node_by_path("/testcase-data/changeset/node-remove");
313 selftest(nremove, "testcase setup failure\n");
314 ppadd = __of_prop_dup(&padd, GFP_KERNEL);
315 selftest(ppadd, "testcase setup failure\n");
316 ppupdate = __of_prop_dup(&pupdate, GFP_KERNEL);
317 selftest(ppupdate, "testcase setup failure\n");
318 parent = nremove->parent;
319 n1->parent = parent;
320 n2->parent = parent;
321 n21->parent = n2;
322 n2->child = n21;
323 ppremove = of_find_property(parent, "prop-remove", NULL);
324 selftest(ppremove, "failed to find removal prop");
325
326 of_changeset_init(&chgset);
327 selftest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n");
328 selftest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n");
329 selftest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n");
330 selftest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n");
331 selftest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop\n");
332 selftest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n");
333 selftest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n");
334 mutex_lock(&of_mutex);
335 selftest(!of_changeset_apply(&chgset), "apply failed\n");
336 mutex_unlock(&of_mutex);
337
338 mutex_lock(&of_mutex);
339 selftest(!of_changeset_revert(&chgset), "revert failed\n");
340 mutex_unlock(&of_mutex);
341
342 of_changeset_destroy(&chgset);
343#endif
344}
345
296static void __init of_selftest_parse_interrupts(void) 346static void __init of_selftest_parse_interrupts(void)
297{ 347{
298 struct device_node *np; 348 struct device_node *np;
@@ -561,6 +611,7 @@ static int __init of_selftest(void)
561 of_selftest_parse_phandle_with_args(); 611 of_selftest_parse_phandle_with_args();
562 of_selftest_property_match_string(); 612 of_selftest_property_match_string();
563 of_selftest_property_copy(); 613 of_selftest_property_copy();
614 of_selftest_changeset();
564 of_selftest_parse_interrupts(); 615 of_selftest_parse_interrupts();
565 of_selftest_parse_interrupts_extended(); 616 of_selftest_parse_interrupts_extended();
566 of_selftest_match_node(); 617 of_selftest_match_node();
diff --git a/drivers/of/testcase-data/testcases.dtsi b/drivers/of/testcase-data/testcases.dtsi
index 6d8d980ac858..669bb07df142 100644
--- a/drivers/of/testcase-data/testcases.dtsi
+++ b/drivers/of/testcase-data/testcases.dtsi
@@ -1,3 +1,13 @@
1/ {
2 testcase-data {
3 changeset {
4 prop-update = "hello";
5 prop-remove = "world";
6 node-remove {
7 };
8 };
9 };
10};
1#include "tests-phandle.dtsi" 11#include "tests-phandle.dtsi"
2#include "tests-interrupts.dtsi" 12#include "tests-interrupts.dtsi"
3#include "tests-match.dtsi" 13#include "tests-match.dtsi"
diff --git a/include/linux/of.h b/include/linux/of.h
index 400f18cb4fff..bc91fbb13ce8 100644
--- a/include/linux/of.h
+++ b/include/linux/of.h
@@ -786,4 +786,80 @@ typedef void (*of_init_fn_1)(struct device_node *);
786#define OF_DECLARE_2(table, name, compat, fn) \ 786#define OF_DECLARE_2(table, name, compat, fn) \
787 _OF_DECLARE(table, name, compat, fn, of_init_fn_2) 787 _OF_DECLARE(table, name, compat, fn, of_init_fn_2)
788 788
789/**
790 * struct of_changeset_entry - Holds a changeset entry
791 *
792 * @node: list_head for the log list
793 * @action: notifier action
794 * @np: pointer to the device node affected
795 * @prop: pointer to the property affected
796 * @old_prop: hold a pointer to the original property
797 *
798 * Every modification of the device tree during a changeset
799 * is held in a list of of_changeset_entry structures.
800 * That way we can recover from a partial application, or we can
801 * revert the changeset
802 */
803struct of_changeset_entry {
804 struct list_head node;
805 unsigned long action;
806 struct device_node *np;
807 struct property *prop;
808 struct property *old_prop;
809};
810
811/**
812 * struct of_changeset - changeset tracker structure
813 *
814 * @entries: list_head for the changeset entries
815 *
816 * changesets are a convenient way to apply bulk changes to the
817 * live tree. In case of an error, changes are rolled-back.
818 * changesets live on after initial application, and if not
819 * destroyed after use, they can be reverted in one single call.
820 */
821struct of_changeset {
822 struct list_head entries;
823};
824
825#ifdef CONFIG_OF_DYNAMIC
826extern void of_changeset_init(struct of_changeset *ocs);
827extern void of_changeset_destroy(struct of_changeset *ocs);
828extern int of_changeset_apply(struct of_changeset *ocs);
829extern int of_changeset_revert(struct of_changeset *ocs);
830extern int of_changeset_action(struct of_changeset *ocs,
831 unsigned long action, struct device_node *np,
832 struct property *prop);
833
834static inline int of_changeset_attach_node(struct of_changeset *ocs,
835 struct device_node *np)
836{
837 return of_changeset_action(ocs, OF_RECONFIG_ATTACH_NODE, np, NULL);
838}
839
840static inline int of_changeset_detach_node(struct of_changeset *ocs,
841 struct device_node *np)
842{
843 return of_changeset_action(ocs, OF_RECONFIG_DETACH_NODE, np, NULL);
844}
845
846static inline int of_changeset_add_property(struct of_changeset *ocs,
847 struct device_node *np, struct property *prop)
848{
849 return of_changeset_action(ocs, OF_RECONFIG_ADD_PROPERTY, np, prop);
850}
851
852static inline int of_changeset_remove_property(struct of_changeset *ocs,
853 struct device_node *np, struct property *prop)
854{
855 return of_changeset_action(ocs, OF_RECONFIG_REMOVE_PROPERTY, np, prop);
856}
857
858static inline int of_changeset_update_property(struct of_changeset *ocs,
859 struct device_node *np, struct property *prop)
860{
861 return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, prop);
862}
863#endif
864
789#endif /* _LINUX_OF_H */ 865#endif /* _LINUX_OF_H */