diff options
author | Pantelis Antoniou <pantelis.antoniou@konsulko.com> | 2014-07-04 12:58:46 -0400 |
---|---|---|
committer | Grant Likely <grant.likely@linaro.org> | 2014-07-16 10:16:52 -0400 |
commit | d8c50088417ebf61ad8b132caad20d10f7736034 (patch) | |
tree | 40f3105ec3c03601e22301f36d207362e6d1226e /drivers/of/base.c | |
parent | 698433963b98d6de7b102c242805c99fda4fa1fb (diff) |
of: Create unlocked versions of node and property add/remove functions
The DT overlay code will need to manipulate nodes and properties while
already holding the devicetree lock, or on nodes that are not yet
attached to the tree, but the current helper functions don't allow that.
Extract the core behaviour from the accessors and create the following
unlocked variants.
The unlocked variants require either the lock to already be held or for
the nodes to be detached from the tree. Changes to live nodes will not
get updated in sysfs, so the caller must arrange for housekeeping to
take place after dropping the lock.
The new functions are: __of_add_property(), __of_remove_property(),
__of_update_property(), __of_attach_node() and __of_detach_node().
Signed-off-by: Pantelis Antoniou <pantelis.antoniou@konsulko.com>
[Remove unnecessary diff hunks and rewrite commit text]
Signed-off-by: Grant Likely <grant.likely@linaro.org>
Diffstat (limited to 'drivers/of/base.c')
-rw-r--r-- | drivers/of/base.c | 91 |
1 files changed, 54 insertions, 37 deletions
diff --git a/drivers/of/base.c b/drivers/of/base.c index 0d8955605738..b403f9d98461 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -1659,7 +1659,7 @@ EXPORT_SYMBOL(of_count_phandle_with_args); | |||
1659 | /** | 1659 | /** |
1660 | * __of_add_property - Add a property to a node without lock operations | 1660 | * __of_add_property - Add a property to a node without lock operations |
1661 | */ | 1661 | */ |
1662 | static int __of_add_property(struct device_node *np, struct property *prop) | 1662 | int __of_add_property(struct device_node *np, struct property *prop) |
1663 | { | 1663 | { |
1664 | struct property **next; | 1664 | struct property **next; |
1665 | 1665 | ||
@@ -1701,6 +1701,25 @@ int of_add_property(struct device_node *np, struct property *prop) | |||
1701 | return rc; | 1701 | return rc; |
1702 | } | 1702 | } |
1703 | 1703 | ||
1704 | int __of_remove_property(struct device_node *np, struct property *prop) | ||
1705 | { | ||
1706 | struct property **next; | ||
1707 | |||
1708 | for (next = &np->properties; *next; next = &(*next)->next) { | ||
1709 | if (*next == prop) | ||
1710 | break; | ||
1711 | } | ||
1712 | if (*next == NULL) | ||
1713 | return -ENODEV; | ||
1714 | |||
1715 | /* found the node */ | ||
1716 | *next = prop->next; | ||
1717 | prop->next = np->deadprops; | ||
1718 | np->deadprops = prop; | ||
1719 | |||
1720 | return 0; | ||
1721 | } | ||
1722 | |||
1704 | /** | 1723 | /** |
1705 | * of_remove_property - Remove a property from a node. | 1724 | * of_remove_property - Remove a property from a node. |
1706 | * | 1725 | * |
@@ -1711,9 +1730,7 @@ int of_add_property(struct device_node *np, struct property *prop) | |||
1711 | */ | 1730 | */ |
1712 | int of_remove_property(struct device_node *np, struct property *prop) | 1731 | int of_remove_property(struct device_node *np, struct property *prop) |
1713 | { | 1732 | { |
1714 | struct property **next; | ||
1715 | unsigned long flags; | 1733 | unsigned long flags; |
1716 | int found = 0; | ||
1717 | int rc; | 1734 | int rc; |
1718 | 1735 | ||
1719 | rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop); | 1736 | rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop); |
@@ -1721,22 +1738,11 @@ int of_remove_property(struct device_node *np, struct property *prop) | |||
1721 | return rc; | 1738 | return rc; |
1722 | 1739 | ||
1723 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1740 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1724 | next = &np->properties; | 1741 | rc = __of_remove_property(np, prop); |
1725 | while (*next) { | ||
1726 | if (*next == prop) { | ||
1727 | /* found the node */ | ||
1728 | *next = prop->next; | ||
1729 | prop->next = np->deadprops; | ||
1730 | np->deadprops = prop; | ||
1731 | found = 1; | ||
1732 | break; | ||
1733 | } | ||
1734 | next = &(*next)->next; | ||
1735 | } | ||
1736 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1742 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1737 | 1743 | ||
1738 | if (!found) | 1744 | if (rc) |
1739 | return -ENODEV; | 1745 | return rc; |
1740 | 1746 | ||
1741 | /* at early boot, bail hear and defer setup to of_init() */ | 1747 | /* at early boot, bail hear and defer setup to of_init() */ |
1742 | if (!of_kset) | 1748 | if (!of_kset) |
@@ -1747,6 +1753,32 @@ int of_remove_property(struct device_node *np, struct property *prop) | |||
1747 | return 0; | 1753 | return 0; |
1748 | } | 1754 | } |
1749 | 1755 | ||
1756 | int __of_update_property(struct device_node *np, struct property *newprop, | ||
1757 | struct property **oldpropp) | ||
1758 | { | ||
1759 | struct property **next, *oldprop; | ||
1760 | |||
1761 | for (next = &np->properties; *next; next = &(*next)->next) { | ||
1762 | if (of_prop_cmp((*next)->name, newprop->name) == 0) | ||
1763 | break; | ||
1764 | } | ||
1765 | *oldpropp = oldprop = *next; | ||
1766 | |||
1767 | if (oldprop) { | ||
1768 | /* replace the node */ | ||
1769 | newprop->next = oldprop->next; | ||
1770 | *next = newprop; | ||
1771 | oldprop->next = np->deadprops; | ||
1772 | np->deadprops = oldprop; | ||
1773 | } else { | ||
1774 | /* new node */ | ||
1775 | newprop->next = NULL; | ||
1776 | *next = newprop; | ||
1777 | } | ||
1778 | |||
1779 | return 0; | ||
1780 | } | ||
1781 | |||
1750 | /* | 1782 | /* |
1751 | * of_update_property - Update a property in a node, if the property does | 1783 | * of_update_property - Update a property in a node, if the property does |
1752 | * not exist, add it. | 1784 | * not exist, add it. |
@@ -1758,34 +1790,19 @@ int of_remove_property(struct device_node *np, struct property *prop) | |||
1758 | */ | 1790 | */ |
1759 | int of_update_property(struct device_node *np, struct property *newprop) | 1791 | int of_update_property(struct device_node *np, struct property *newprop) |
1760 | { | 1792 | { |
1761 | struct property **next, *oldprop; | 1793 | struct property *oldprop; |
1762 | unsigned long flags; | 1794 | unsigned long flags; |
1763 | int rc; | 1795 | int rc; |
1764 | 1796 | ||
1797 | if (!newprop->name) | ||
1798 | return -EINVAL; | ||
1799 | |||
1765 | rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); | 1800 | rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); |
1766 | if (rc) | 1801 | if (rc) |
1767 | return rc; | 1802 | return rc; |
1768 | 1803 | ||
1769 | if (!newprop->name) | ||
1770 | return -EINVAL; | ||
1771 | |||
1772 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1804 | raw_spin_lock_irqsave(&devtree_lock, flags); |
1773 | next = &np->properties; | 1805 | rc = __of_update_property(np, newprop, &oldprop); |
1774 | oldprop = __of_find_property(np, newprop->name, NULL); | ||
1775 | if (!oldprop) { | ||
1776 | /* add the new node */ | ||
1777 | rc = __of_add_property(np, newprop); | ||
1778 | } else while (*next) { | ||
1779 | /* replace the node */ | ||
1780 | if (*next == oldprop) { | ||
1781 | newprop->next = oldprop->next; | ||
1782 | *next = newprop; | ||
1783 | oldprop->next = np->deadprops; | ||
1784 | np->deadprops = oldprop; | ||
1785 | break; | ||
1786 | } | ||
1787 | next = &(*next)->next; | ||
1788 | } | ||
1789 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1806 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
1790 | if (rc) | 1807 | if (rc) |
1791 | return rc; | 1808 | return rc; |