overlay.c (bba73071b6f71be0a101658d7c13866e30b264a6) overlay.c (39a751a4cb7e4798f0ce1169ec92de4a1aae39e3)
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Functions for working with device tree overlays
4 *
5 * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
6 * Copyright (C) 2012 Texas Instruments Inc.
7 */
8
9#define pr_fmt(fmt) "OF: overlay: " fmt
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/of_device.h>
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Functions for working with device tree overlays
4 *
5 * Copyright (C) 2012 Pantelis Antoniou <panto@antoniou-consulting.com>
6 * Copyright (C) 2012 Texas Instruments Inc.
7 */
8
9#define pr_fmt(fmt) "OF: overlay: " fmt
10
11#include <linux/kernel.h>
12#include <linux/module.h>
13#include <linux/of.h>
14#include <linux/of_device.h>
15#include <linux/of_fdt.h>
15#include <linux/string.h>
16#include <linux/ctype.h>
17#include <linux/errno.h>
18#include <linux/slab.h>
16#include <linux/string.h>
17#include <linux/ctype.h>
18#include <linux/errno.h>
19#include <linux/slab.h>
20#include <linux/libfdt.h>
19#include <linux/err.h>
20#include <linux/idr.h>
21
22#include "of_private.h"
23
24/**
25 * struct fragment - info about fragment nodes in overlay expanded device tree
26 * @target: target of the overlay operation
27 * @overlay: pointer to the __overlay__ node
28 */
29struct fragment {
30 struct device_node *target;
31 struct device_node *overlay;
32};
33
34/**
35 * struct overlay_changeset
21#include <linux/err.h>
22#include <linux/idr.h>
23
24#include "of_private.h"
25
26/**
27 * struct fragment - info about fragment nodes in overlay expanded device tree
28 * @target: target of the overlay operation
29 * @overlay: pointer to the __overlay__ node
30 */
31struct fragment {
32 struct device_node *target;
33 struct device_node *overlay;
34};
35
36/**
37 * struct overlay_changeset
38 * @id: changeset identifier
36 * @ovcs_list: list on which we are located
39 * @ovcs_list: list on which we are located
40 * @fdt: FDT that was unflattened to create @overlay_tree
37 * @overlay_tree: expanded device tree that contains the fragment nodes
38 * @count: count of fragment structures
39 * @fragments: fragment nodes in the overlay expanded device tree
40 * @symbols_fragment: last element of @fragments[] is the __symbols__ node
41 * @cset: changeset to apply fragments to live device tree
42 */
43struct overlay_changeset {
44 int id;
45 struct list_head ovcs_list;
41 * @overlay_tree: expanded device tree that contains the fragment nodes
42 * @count: count of fragment structures
43 * @fragments: fragment nodes in the overlay expanded device tree
44 * @symbols_fragment: last element of @fragments[] is the __symbols__ node
45 * @cset: changeset to apply fragments to live device tree
46 */
47struct overlay_changeset {
48 int id;
49 struct list_head ovcs_list;
50 const void *fdt;
46 struct device_node *overlay_tree;
47 int count;
48 struct fragment *fragments;
49 bool symbols_fragment;
50 struct of_changeset cset;
51};
52
53/* flags are sticky - once set, do not reset */

--- 444 unchanged lines hidden (view full) ---

498 pr_err("Failed to find target for node %p (%s)\n",
499 info_node, info_node->name);
500
501 return NULL;
502}
503
504/**
505 * init_overlay_changeset() - initialize overlay changeset from overlay tree
51 struct device_node *overlay_tree;
52 int count;
53 struct fragment *fragments;
54 bool symbols_fragment;
55 struct of_changeset cset;
56};
57
58/* flags are sticky - once set, do not reset */

--- 444 unchanged lines hidden (view full) ---

503 pr_err("Failed to find target for node %p (%s)\n",
504 info_node, info_node->name);
505
506 return NULL;
507}
508
509/**
510 * init_overlay_changeset() - initialize overlay changeset from overlay tree
506 * @ovcs Overlay changeset to build
511 * @ovcs: Overlay changeset to build
512 * @fdt: the FDT that was unflattened to create @tree
507 * @tree: Contains all the overlay fragments and overlay fixup nodes
508 *
509 * Initialize @ovcs. Populate @ovcs->fragments with node information from
510 * the top level of @tree. The relevant top level nodes are the fragment
511 * nodes and the __symbols__ node. Any other top level node will be ignored.
512 *
513 * Returns 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error
514 * detected in @tree, or -ENOSPC if idr_alloc() error.
515 */
516static int init_overlay_changeset(struct overlay_changeset *ovcs,
513 * @tree: Contains all the overlay fragments and overlay fixup nodes
514 *
515 * Initialize @ovcs. Populate @ovcs->fragments with node information from
516 * the top level of @tree. The relevant top level nodes are the fragment
517 * nodes and the __symbols__ node. Any other top level node will be ignored.
518 *
519 * Returns 0 on success, -ENOMEM if memory allocation failure, -EINVAL if error
520 * detected in @tree, or -ENOSPC if idr_alloc() error.
521 */
522static int init_overlay_changeset(struct overlay_changeset *ovcs,
517 struct device_node *tree)
523 const void *fdt, struct device_node *tree)
518{
519 struct device_node *node, *overlay_node;
520 struct fragment *fragment;
521 struct fragment *fragments;
522 int cnt, id, ret;
523
524 /*
525 * Warn for some issues. Can not return -EINVAL for these until

--- 4 unchanged lines hidden (view full) ---

530
531 if (!of_node_check_flag(tree, OF_DETACHED))
532 pr_debug("%s() tree is not detached\n", __func__);
533
534 if (!of_node_is_root(tree))
535 pr_debug("%s() tree is not root\n", __func__);
536
537 ovcs->overlay_tree = tree;
524{
525 struct device_node *node, *overlay_node;
526 struct fragment *fragment;
527 struct fragment *fragments;
528 int cnt, id, ret;
529
530 /*
531 * Warn for some issues. Can not return -EINVAL for these until

--- 4 unchanged lines hidden (view full) ---

536
537 if (!of_node_check_flag(tree, OF_DETACHED))
538 pr_debug("%s() tree is not detached\n", __func__);
539
540 if (!of_node_is_root(tree))
541 pr_debug("%s() tree is not root\n", __func__);
542
543 ovcs->overlay_tree = tree;
544 ovcs->fdt = fdt;
538
539 INIT_LIST_HEAD(&ovcs->ovcs_list);
540
541 of_changeset_init(&ovcs->cset);
542
543 id = idr_alloc(&ovcs_idr, ovcs, 1, 0, GFP_KERNEL);
544 if (id <= 0)
545 return id;

--- 55 unchanged lines hidden (view full) ---

601 ret = -EINVAL;
602 goto err_free_fragments;
603 }
604
605 cnt++;
606 }
607
608 if (!cnt) {
545
546 INIT_LIST_HEAD(&ovcs->ovcs_list);
547
548 of_changeset_init(&ovcs->cset);
549
550 id = idr_alloc(&ovcs_idr, ovcs, 1, 0, GFP_KERNEL);
551 if (id <= 0)
552 return id;

--- 55 unchanged lines hidden (view full) ---

608 ret = -EINVAL;
609 goto err_free_fragments;
610 }
611
612 cnt++;
613 }
614
615 if (!cnt) {
616 pr_err("no fragments or symbols in overlay\n");
609 ret = -EINVAL;
610 goto err_free_fragments;
611 }
612
613 ovcs->id = id;
614 ovcs->count = cnt;
615 ovcs->fragments = fragments;
616

--- 20 unchanged lines hidden (view full) ---

637 idr_remove(&ovcs_idr, ovcs->id);
638
639 for (i = 0; i < ovcs->count; i++) {
640 of_node_put(ovcs->fragments[i].target);
641 of_node_put(ovcs->fragments[i].overlay);
642 }
643 kfree(ovcs->fragments);
644
617 ret = -EINVAL;
618 goto err_free_fragments;
619 }
620
621 ovcs->id = id;
622 ovcs->count = cnt;
623 ovcs->fragments = fragments;
624

--- 20 unchanged lines hidden (view full) ---

645 idr_remove(&ovcs_idr, ovcs->id);
646
647 for (i = 0; i < ovcs->count; i++) {
648 of_node_put(ovcs->fragments[i].target);
649 of_node_put(ovcs->fragments[i].overlay);
650 }
651 kfree(ovcs->fragments);
652
653 /*
654 * TODO
655 *
656 * would like to: kfree(ovcs->overlay_tree);
657 * but can not since drivers may have pointers into this data
658 *
659 * would like to: kfree(ovcs->fdt);
660 * but can not since drivers may have pointers into this data
661 */
662
645 kfree(ovcs);
646}
647
663 kfree(ovcs);
664}
665
648/**
666/*
667 * internal documentation
668 *
649 * of_overlay_apply() - Create and apply an overlay changeset
669 * of_overlay_apply() - Create and apply an overlay changeset
670 * @fdt: the FDT that was unflattened to create @tree
650 * @tree: Expanded overlay device tree
651 * @ovcs_id: Pointer to overlay changeset id
652 *
653 * Creates and applies an overlay changeset.
654 *
655 * If an error occurs in a pre-apply notifier, then no changes are made
656 * to the device tree.
657 *

--- 22 unchanged lines hidden (view full) ---

680 * then the state of the device tree can not be determined, and any
681 * following attempt to apply or remove an overlay changeset will be
682 * refused.
683 *
684 * Returns 0 on success, or a negative error number. Overlay changeset
685 * id is returned to *ovcs_id.
686 */
687
671 * @tree: Expanded overlay device tree
672 * @ovcs_id: Pointer to overlay changeset id
673 *
674 * Creates and applies an overlay changeset.
675 *
676 * If an error occurs in a pre-apply notifier, then no changes are made
677 * to the device tree.
678 *

--- 22 unchanged lines hidden (view full) ---

701 * then the state of the device tree can not be determined, and any
702 * following attempt to apply or remove an overlay changeset will be
703 * refused.
704 *
705 * Returns 0 on success, or a negative error number. Overlay changeset
706 * id is returned to *ovcs_id.
707 */
708
688int of_overlay_apply(struct device_node *tree, int *ovcs_id)
709static int of_overlay_apply(const void *fdt, struct device_node *tree,
710 int *ovcs_id)
689{
690 struct overlay_changeset *ovcs;
691 int ret = 0, ret_revert, ret_tmp;
692
711{
712 struct overlay_changeset *ovcs;
713 int ret = 0, ret_revert, ret_tmp;
714
693 *ovcs_id = 0;
715 /*
716 * As of this point, fdt and tree belong to the overlay changeset.
717 * overlay changeset code is responsible for freeing them.
718 */
694
695 if (devicetree_corrupt()) {
696 pr_err("devicetree state suspect, refuse to apply overlay\n");
719
720 if (devicetree_corrupt()) {
721 pr_err("devicetree state suspect, refuse to apply overlay\n");
722 kfree(fdt);
723 kfree(tree);
697 ret = -EBUSY;
698 goto out;
699 }
700
701 ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL);
702 if (!ovcs) {
724 ret = -EBUSY;
725 goto out;
726 }
727
728 ovcs = kzalloc(sizeof(*ovcs), GFP_KERNEL);
729 if (!ovcs) {
730 kfree(fdt);
731 kfree(tree);
703 ret = -ENOMEM;
704 goto out;
705 }
706
707 of_overlay_mutex_lock();
708 mutex_lock(&of_mutex);
709
710 ret = of_resolve_phandles(tree);
711 if (ret)
732 ret = -ENOMEM;
733 goto out;
734 }
735
736 of_overlay_mutex_lock();
737 mutex_lock(&of_mutex);
738
739 ret = of_resolve_phandles(tree);
740 if (ret)
712 goto err_free_overlay_changeset;
741 goto err_free_tree;
713
742
714 ret = init_overlay_changeset(ovcs, tree);
743 ret = init_overlay_changeset(ovcs, fdt, tree);
715 if (ret)
744 if (ret)
716 goto err_free_overlay_changeset;
745 goto err_free_tree;
717
746
747 /*
748 * after overlay_notify(), ovcs->overlay_tree related pointers may have
749 * leaked to drivers, so can not kfree() tree, aka ovcs->overlay_tree;
750 * and can not free fdt, aka ovcs->fdt
751 */
718 ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
719 if (ret) {
720 pr_err("overlay changeset pre-apply notify error %d\n", ret);
721 goto err_free_overlay_changeset;
722 }
723
724 ret = build_changeset(ovcs);
725 if (ret)

--- 23 unchanged lines hidden (view full) ---

749 pr_err("overlay changeset post-apply notify error %d\n",
750 ret_tmp);
751 if (!ret)
752 ret = ret_tmp;
753 }
754
755 goto out_unlock;
756
752 ret = overlay_notify(ovcs, OF_OVERLAY_PRE_APPLY);
753 if (ret) {
754 pr_err("overlay changeset pre-apply notify error %d\n", ret);
755 goto err_free_overlay_changeset;
756 }
757
758 ret = build_changeset(ovcs);
759 if (ret)

--- 23 unchanged lines hidden (view full) ---

783 pr_err("overlay changeset post-apply notify error %d\n",
784 ret_tmp);
785 if (!ret)
786 ret = ret_tmp;
787 }
788
789 goto out_unlock;
790
791err_free_tree:
792 kfree(fdt);
793 kfree(tree);
794
757err_free_overlay_changeset:
758 free_overlay_changeset(ovcs);
759
760out_unlock:
761 mutex_unlock(&of_mutex);
762 of_overlay_mutex_unlock();
763
764out:
765 pr_debug("%s() err=%d\n", __func__, ret);
766
767 return ret;
768}
795err_free_overlay_changeset:
796 free_overlay_changeset(ovcs);
797
798out_unlock:
799 mutex_unlock(&of_mutex);
800 of_overlay_mutex_unlock();
801
802out:
803 pr_debug("%s() err=%d\n", __func__, ret);
804
805 return ret;
806}
769EXPORT_SYMBOL_GPL(of_overlay_apply);
770
807
808int of_overlay_fdt_apply(const void *overlay_fdt, u32 overlay_fdt_size,
809 int *ovcs_id)
810{
811 const void *new_fdt;
812 int ret;
813 u32 size;
814 struct device_node *overlay_root;
815
816 *ovcs_id = 0;
817 ret = 0;
818
819 if (overlay_fdt_size < sizeof(struct fdt_header) ||
820 fdt_check_header(overlay_fdt)) {
821 pr_err("Invalid overlay_fdt header\n");
822 return -EINVAL;
823 }
824
825 size = fdt_totalsize(overlay_fdt);
826 if (overlay_fdt_size < size)
827 return -EINVAL;
828
829 /*
830 * Must create permanent copy of FDT because of_fdt_unflatten_tree()
831 * will create pointers to the passed in FDT in the unflattened tree.
832 */
833 new_fdt = kmemdup(overlay_fdt, size, GFP_KERNEL);
834 if (!new_fdt)
835 return -ENOMEM;
836
837 of_fdt_unflatten_tree(new_fdt, NULL, &overlay_root);
838 if (!overlay_root) {
839 pr_err("unable to unflatten overlay_fdt\n");
840 ret = -EINVAL;
841 goto out_free_new_fdt;
842 }
843
844 ret = of_overlay_apply(new_fdt, overlay_root, ovcs_id);
845 if (ret < 0) {
846 /*
847 * new_fdt and overlay_root now belong to the overlay
848 * changeset.
849 * overlay changeset code is responsible for freeing them.
850 */
851 goto out;
852 }
853
854 return 0;
855
856
857out_free_new_fdt:
858 kfree(new_fdt);
859
860out:
861 return ret;
862}
863EXPORT_SYMBOL_GPL(of_overlay_fdt_apply);
864
771/*
772 * Find @np in @tree.
773 *
774 * Returns 1 if @np is @tree or is contained in @tree, else 0
775 */
776static int find_node(struct device_node *tree, struct device_node *np)
777{
778 struct device_node *child;

--- 199 unchanged lines hidden ---
865/*
866 * Find @np in @tree.
867 *
868 * Returns 1 if @np is @tree or is contained in @tree, else 0
869 */
870static int find_node(struct device_node *tree, struct device_node *np)
871{
872 struct device_node *child;

--- 199 unchanged lines hidden ---