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 --- |