aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/of/dynamic.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/of/dynamic.c')
-rw-r--r--drivers/of/dynamic.c135
1 files changed, 115 insertions, 20 deletions
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c
index 4bc96af4d8e2..747d87619faf 100644
--- a/drivers/of/dynamic.c
+++ b/drivers/of/dynamic.c
@@ -491,11 +491,12 @@ static void __of_changeset_entry_invert(struct of_changeset_entry *ce,
491 } 491 }
492} 492}
493 493
494static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool revert) 494static int __of_changeset_entry_notify(struct of_changeset_entry *ce,
495 bool revert)
495{ 496{
496 struct of_reconfig_data rd; 497 struct of_reconfig_data rd;
497 struct of_changeset_entry ce_inverted; 498 struct of_changeset_entry ce_inverted;
498 int ret; 499 int ret = 0;
499 500
500 if (revert) { 501 if (revert) {
501 __of_changeset_entry_invert(ce, &ce_inverted); 502 __of_changeset_entry_invert(ce, &ce_inverted);
@@ -517,11 +518,12 @@ static void __of_changeset_entry_notify(struct of_changeset_entry *ce, bool reve
517 default: 518 default:
518 pr_err("invalid devicetree changeset action: %i\n", 519 pr_err("invalid devicetree changeset action: %i\n",
519 (int)ce->action); 520 (int)ce->action);
520 return; 521 ret = -EINVAL;
521 } 522 }
522 523
523 if (ret) 524 if (ret)
524 pr_err("changeset notifier error @%pOF\n", ce->np); 525 pr_err("changeset notifier error @%pOF\n", ce->np);
526 return ret;
525} 527}
526 528
527static int __of_changeset_entry_apply(struct of_changeset_entry *ce) 529static int __of_changeset_entry_apply(struct of_changeset_entry *ce)
@@ -655,32 +657,82 @@ void of_changeset_destroy(struct of_changeset *ocs)
655} 657}
656EXPORT_SYMBOL_GPL(of_changeset_destroy); 658EXPORT_SYMBOL_GPL(of_changeset_destroy);
657 659
658int __of_changeset_apply(struct of_changeset *ocs) 660/*
661 * Apply the changeset entries in @ocs.
662 * If apply fails, an attempt is made to revert the entries that were
663 * successfully applied.
664 *
665 * If multiple revert errors occur then only the final revert error is reported.
666 *
667 * Returns 0 on success, a negative error value in case of an error.
668 * If a revert error occurs, it is returned in *ret_revert.
669 */
670int __of_changeset_apply_entries(struct of_changeset *ocs, int *ret_revert)
659{ 671{
660 struct of_changeset_entry *ce; 672 struct of_changeset_entry *ce;
661 int ret; 673 int ret, ret_tmp;
662 674
663 /* perform the rest of the work */
664 pr_debug("changeset: applying...\n"); 675 pr_debug("changeset: applying...\n");
665 list_for_each_entry(ce, &ocs->entries, node) { 676 list_for_each_entry(ce, &ocs->entries, node) {
666 ret = __of_changeset_entry_apply(ce); 677 ret = __of_changeset_entry_apply(ce);
667 if (ret) { 678 if (ret) {
668 pr_err("Error applying changeset (%d)\n", ret); 679 pr_err("Error applying changeset (%d)\n", ret);
669 list_for_each_entry_continue_reverse(ce, &ocs->entries, node) 680 list_for_each_entry_continue_reverse(ce, &ocs->entries,
670 __of_changeset_entry_revert(ce); 681 node) {
682 ret_tmp = __of_changeset_entry_revert(ce);
683 if (ret_tmp)
684 *ret_revert = ret_tmp;
685 }
671 return ret; 686 return ret;
672 } 687 }
673 } 688 }
674 pr_debug("changeset: applied, emitting notifiers.\n"); 689
690 return 0;
691}
692
693/*
694 * Returns 0 on success, a negative error value in case of an error.
695 *
696 * If multiple changset entry notification errors occur then only the
697 * final notification error is reported.
698 */
699int __of_changeset_apply_notify(struct of_changeset *ocs)
700{
701 struct of_changeset_entry *ce;
702 int ret = 0, ret_tmp;
703
704 pr_debug("changeset: emitting notifiers.\n");
675 705
676 /* drop the global lock while emitting notifiers */ 706 /* drop the global lock while emitting notifiers */
677 mutex_unlock(&of_mutex); 707 mutex_unlock(&of_mutex);
678 list_for_each_entry(ce, &ocs->entries, node) 708 list_for_each_entry(ce, &ocs->entries, node) {
679 __of_changeset_entry_notify(ce, 0); 709 ret_tmp = __of_changeset_entry_notify(ce, 0);
710 if (ret_tmp)
711 ret = ret_tmp;
712 }
680 mutex_lock(&of_mutex); 713 mutex_lock(&of_mutex);
681 pr_debug("changeset: notifiers sent.\n"); 714 pr_debug("changeset: notifiers sent.\n");
682 715
683 return 0; 716 return ret;
717}
718
719/*
720 * Returns 0 on success, a negative error value in case of an error.
721 *
722 * If a changeset entry apply fails, an attempt is made to revert any
723 * previous entries in the changeset. If any of the reverts fails,
724 * that failure is not reported. Thus the state of the device tree
725 * is unknown if an apply error occurs.
726 */
727static int __of_changeset_apply(struct of_changeset *ocs)
728{
729 int ret, ret_revert = 0;
730
731 ret = __of_changeset_apply_entries(ocs, &ret_revert);
732 if (!ret)
733 ret = __of_changeset_apply_notify(ocs);
734
735 return ret;
684} 736}
685 737
686/** 738/**
@@ -707,31 +759,74 @@ int of_changeset_apply(struct of_changeset *ocs)
707} 759}
708EXPORT_SYMBOL_GPL(of_changeset_apply); 760EXPORT_SYMBOL_GPL(of_changeset_apply);
709 761
710int __of_changeset_revert(struct of_changeset *ocs) 762/*
763 * Revert the changeset entries in @ocs.
764 * If revert fails, an attempt is made to re-apply the entries that were
765 * successfully removed.
766 *
767 * If multiple re-apply errors occur then only the final apply error is
768 * reported.
769 *
770 * Returns 0 on success, a negative error value in case of an error.
771 * If an apply error occurs, it is returned in *ret_apply.
772 */
773int __of_changeset_revert_entries(struct of_changeset *ocs, int *ret_apply)
711{ 774{
712 struct of_changeset_entry *ce; 775 struct of_changeset_entry *ce;
713 int ret; 776 int ret, ret_tmp;
714 777
715 pr_debug("changeset: reverting...\n"); 778 pr_debug("changeset: reverting...\n");
716 list_for_each_entry_reverse(ce, &ocs->entries, node) { 779 list_for_each_entry_reverse(ce, &ocs->entries, node) {
717 ret = __of_changeset_entry_revert(ce); 780 ret = __of_changeset_entry_revert(ce);
718 if (ret) { 781 if (ret) {
719 pr_err("Error reverting changeset (%d)\n", ret); 782 pr_err("Error reverting changeset (%d)\n", ret);
720 list_for_each_entry_continue(ce, &ocs->entries, node) 783 list_for_each_entry_continue(ce, &ocs->entries, node) {
721 __of_changeset_entry_apply(ce); 784 ret_tmp = __of_changeset_entry_apply(ce);
785 if (ret_tmp)
786 *ret_apply = ret_tmp;
787 }
722 return ret; 788 return ret;
723 } 789 }
724 } 790 }
725 pr_debug("changeset: reverted, emitting notifiers.\n"); 791
792 return 0;
793}
794
795/*
796 * If multiple changset entry notification errors occur then only the
797 * final notification error is reported.
798 */
799int __of_changeset_revert_notify(struct of_changeset *ocs)
800{
801 struct of_changeset_entry *ce;
802 int ret = 0, ret_tmp;
803
804 pr_debug("changeset: emitting notifiers.\n");
726 805
727 /* drop the global lock while emitting notifiers */ 806 /* drop the global lock while emitting notifiers */
728 mutex_unlock(&of_mutex); 807 mutex_unlock(&of_mutex);
729 list_for_each_entry_reverse(ce, &ocs->entries, node) 808 list_for_each_entry_reverse(ce, &ocs->entries, node) {
730 __of_changeset_entry_notify(ce, 1); 809 ret_tmp = __of_changeset_entry_notify(ce, 1);
810 if (ret_tmp)
811 ret = ret_tmp;
812 }
731 mutex_lock(&of_mutex); 813 mutex_lock(&of_mutex);
732 pr_debug("changeset: notifiers sent.\n"); 814 pr_debug("changeset: notifiers sent.\n");
733 815
734 return 0; 816 return ret;
817}
818
819static int __of_changeset_revert(struct of_changeset *ocs)
820{
821 int ret, ret_reply;
822
823 ret_reply = 0;
824 ret = __of_changeset_revert_entries(ocs, &ret_reply);
825
826 if (!ret)
827 ret = __of_changeset_revert_notify(ocs);
828
829 return ret;
735} 830}
736 831
737/** 832/**