diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-14 11:53:39 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2014-08-14 11:53:39 -0400 |
| commit | ae36e95cf81c98b111b84317adeb358aaffa80e2 (patch) | |
| tree | 87ef144d3392cca199448117a737c657b7c4663a /drivers/of | |
| parent | cc8a44c671fd3a2c792e9e1f59ea1df52697cc8b (diff) | |
| parent | 663d3f7c2e5e1b018a4c53277ccfde40329d98ca (diff) | |
Merge tag 'devicetree-for-linus' of git://git.secretlab.ca/git/linux
Pull device tree updates from Grant Likely:
"The branch contains the following device tree changes the v3.17 merge
window:
Group changes to the device tree. In preparation for adding device
tree overlay support, OF_DYNAMIC is reworked so that a set of device
tree changes can be prepared and applied to the tree all at once.
OF_RECONFIG notifiers see the most significant change here so that
users always get a consistent view of the tree. Notifiers generation
is moved from before a change to after it, and notifiers for a group
of changes are emitted after the entire block of changes have been
applied
Automatic console selection from DT. Console drivers can now use
of_console_check() to see if the device node is specified as a console
device. If so then it gets added as a preferred console. UART
devices get this support automatically when uart_add_one_port() is
called.
DT unit tests no longer depend on pre-loaded data in the device tree.
Data is loaded dynamically at the start of unit tests, and then
unloaded again when the tests have completed.
Also contains a few bugfixes for reserved regions and early memory
setup"
* tag 'devicetree-for-linus' of git://git.secretlab.ca/git/linux: (21 commits)
of: Fixing OF Selftest build error
drivers: of: add automated assignment of reserved regions to client devices
of: Use proper types for checking memory overflow
of: typo fix in __of_prop_dup()
Adding selftest testdata dynamically into live tree
of: Add todo tasklist for Devicetree
of: Transactional DT support.
of: Reorder device tree changes and notifiers
of: Move dynamic node fixups out of powerpc and into common code
of: Make sure attached nodes don't carry along extra children
of: Make devicetree sysfs update functions consistent.
of: Create unlocked versions of node and property add/remove functions
OF: Utility helper functions for dynamic nodes
of: Move CONFIG_OF_DYNAMIC code into a separate file
of: rename of_aliases_mutex to just of_mutex
of/platform: Fix of_platform_device_destroy iteration of devices
of: Migrate of_find_node_by_name() users to for_each_node_by_name()
tty: Update hypervisor tty drivers to use core stdout parsing code.
arm/versatile: Add the uart as the stdout device.
of: Enable console on serial ports specified by /chosen/stdout-path
...
Diffstat (limited to 'drivers/of')
| -rw-r--r-- | drivers/of/Kconfig | 3 | ||||
| -rw-r--r-- | drivers/of/Makefile | 4 | ||||
| -rw-r--r-- | drivers/of/base.c | 451 | ||||
| -rw-r--r-- | drivers/of/device.c | 4 | ||||
| -rw-r--r-- | drivers/of/dynamic.c | 660 | ||||
| -rw-r--r-- | drivers/of/fdt.c | 22 | ||||
| -rw-r--r-- | drivers/of/of_private.h | 59 | ||||
| -rw-r--r-- | drivers/of/of_reserved_mem.c | 70 | ||||
| -rw-r--r-- | drivers/of/platform.c | 32 | ||||
| -rw-r--r-- | drivers/of/selftest.c | 235 | ||||
| -rw-r--r-- | drivers/of/testcase-data/testcases.dts | 15 | ||||
| -rw-r--r-- | drivers/of/testcase-data/testcases.dtsi | 4 |
12 files changed, 1188 insertions, 371 deletions
diff --git a/drivers/of/Kconfig b/drivers/of/Kconfig index 2dcb0541012d..5160c4eb73c2 100644 --- a/drivers/of/Kconfig +++ b/drivers/of/Kconfig | |||
| @@ -9,7 +9,8 @@ menu "Device Tree and Open Firmware support" | |||
| 9 | 9 | ||
| 10 | config OF_SELFTEST | 10 | config OF_SELFTEST |
| 11 | bool "Device Tree Runtime self tests" | 11 | bool "Device Tree Runtime self tests" |
| 12 | depends on OF_IRQ | 12 | depends on OF_IRQ && OF_EARLY_FLATTREE |
| 13 | select OF_DYNAMIC | ||
| 13 | help | 14 | help |
| 14 | This option builds in test cases for the device tree infrastructure | 15 | This option builds in test cases for the device tree infrastructure |
| 15 | that are executed once at boot time, and the results dumped to the | 16 | that are executed once at boot time, and the results dumped to the |
diff --git a/drivers/of/Makefile b/drivers/of/Makefile index 099b1fb00af4..2b6a7b129d10 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile | |||
| @@ -1,11 +1,13 @@ | |||
| 1 | obj-y = base.o device.o platform.o | 1 | obj-y = base.o device.o platform.o |
| 2 | obj-$(CONFIG_OF_DYNAMIC) += dynamic.o | ||
| 2 | obj-$(CONFIG_OF_FLATTREE) += fdt.o | 3 | obj-$(CONFIG_OF_FLATTREE) += fdt.o |
| 3 | obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o | 4 | obj-$(CONFIG_OF_EARLY_FLATTREE) += fdt_address.o |
| 4 | obj-$(CONFIG_OF_PROMTREE) += pdt.o | 5 | obj-$(CONFIG_OF_PROMTREE) += pdt.o |
| 5 | obj-$(CONFIG_OF_ADDRESS) += address.o | 6 | obj-$(CONFIG_OF_ADDRESS) += address.o |
| 6 | obj-$(CONFIG_OF_IRQ) += irq.o | 7 | obj-$(CONFIG_OF_IRQ) += irq.o |
| 7 | obj-$(CONFIG_OF_NET) += of_net.o | 8 | obj-$(CONFIG_OF_NET) += of_net.o |
| 8 | obj-$(CONFIG_OF_SELFTEST) += selftest.o | 9 | obj-$(CONFIG_OF_SELFTEST) += of_selftest.o |
| 10 | of_selftest-objs := selftest.o testcase-data/testcases.dtb.o | ||
| 9 | obj-$(CONFIG_OF_MDIO) += of_mdio.o | 11 | obj-$(CONFIG_OF_MDIO) += of_mdio.o |
| 10 | obj-$(CONFIG_OF_PCI) += of_pci.o | 12 | obj-$(CONFIG_OF_PCI) += of_pci.o |
| 11 | obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o | 13 | obj-$(CONFIG_OF_PCI_IRQ) += of_pci_irq.o |
diff --git a/drivers/of/base.c b/drivers/of/base.c index b9864806e9b8..d8574adf0d62 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | * as published by the Free Software Foundation; either version | 17 | * as published by the Free Software Foundation; either version |
| 18 | * 2 of the License, or (at your option) any later version. | 18 | * 2 of the License, or (at your option) any later version. |
| 19 | */ | 19 | */ |
| 20 | #include <linux/console.h> | ||
| 20 | #include <linux/ctype.h> | 21 | #include <linux/ctype.h> |
| 21 | #include <linux/cpu.h> | 22 | #include <linux/cpu.h> |
| 22 | #include <linux/module.h> | 23 | #include <linux/module.h> |
| @@ -35,15 +36,17 @@ struct device_node *of_allnodes; | |||
| 35 | EXPORT_SYMBOL(of_allnodes); | 36 | EXPORT_SYMBOL(of_allnodes); |
| 36 | struct device_node *of_chosen; | 37 | struct device_node *of_chosen; |
| 37 | struct device_node *of_aliases; | 38 | struct device_node *of_aliases; |
| 38 | static struct device_node *of_stdout; | 39 | struct device_node *of_stdout; |
| 39 | 40 | ||
| 40 | static struct kset *of_kset; | 41 | struct kset *of_kset; |
| 41 | 42 | ||
| 42 | /* | 43 | /* |
| 43 | * Used to protect the of_aliases; but also overloaded to hold off addition of | 44 | * Used to protect the of_aliases, to hold off addition of nodes to sysfs. |
| 44 | * nodes to sysfs | 45 | * This mutex must be held whenever modifications are being made to the |
| 46 | * device tree. The of_{attach,detach}_node() and | ||
| 47 | * of_{add,remove,update}_property() helpers make sure this happens. | ||
| 45 | */ | 48 | */ |
| 46 | DEFINE_MUTEX(of_aliases_mutex); | 49 | DEFINE_MUTEX(of_mutex); |
| 47 | 50 | ||
| 48 | /* use when traversing tree through the allnext, child, sibling, | 51 | /* use when traversing tree through the allnext, child, sibling, |
| 49 | * or parent members of struct device_node. | 52 | * or parent members of struct device_node. |
| @@ -89,79 +92,7 @@ int __weak of_node_to_nid(struct device_node *np) | |||
| 89 | } | 92 | } |
| 90 | #endif | 93 | #endif |
| 91 | 94 | ||
| 92 | #if defined(CONFIG_OF_DYNAMIC) | 95 | #ifndef CONFIG_OF_DYNAMIC |
| 93 | /** | ||
| 94 | * of_node_get - Increment refcount of a node | ||
| 95 | * @node: Node to inc refcount, NULL is supported to | ||
| 96 | * simplify writing of callers | ||
| 97 | * | ||
| 98 | * Returns node. | ||
| 99 | */ | ||
| 100 | struct device_node *of_node_get(struct device_node *node) | ||
| 101 | { | ||
| 102 | if (node) | ||
| 103 | kobject_get(&node->kobj); | ||
| 104 | return node; | ||
| 105 | } | ||
| 106 | EXPORT_SYMBOL(of_node_get); | ||
| 107 | |||
| 108 | static inline struct device_node *kobj_to_device_node(struct kobject *kobj) | ||
| 109 | { | ||
| 110 | return container_of(kobj, struct device_node, kobj); | ||
| 111 | } | ||
| 112 | |||
| 113 | /** | ||
| 114 | * of_node_release - release a dynamically allocated node | ||
| 115 | * @kref: kref element of the node to be released | ||
| 116 | * | ||
| 117 | * In of_node_put() this function is passed to kref_put() | ||
| 118 | * as the destructor. | ||
| 119 | */ | ||
| 120 | static void of_node_release(struct kobject *kobj) | ||
| 121 | { | ||
| 122 | struct device_node *node = kobj_to_device_node(kobj); | ||
| 123 | struct property *prop = node->properties; | ||
| 124 | |||
| 125 | /* We should never be releasing nodes that haven't been detached. */ | ||
| 126 | if (!of_node_check_flag(node, OF_DETACHED)) { | ||
| 127 | pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); | ||
| 128 | dump_stack(); | ||
| 129 | return; | ||
| 130 | } | ||
| 131 | |||
| 132 | if (!of_node_check_flag(node, OF_DYNAMIC)) | ||
| 133 | return; | ||
| 134 | |||
| 135 | while (prop) { | ||
| 136 | struct property *next = prop->next; | ||
| 137 | kfree(prop->name); | ||
| 138 | kfree(prop->value); | ||
| 139 | kfree(prop); | ||
| 140 | prop = next; | ||
| 141 | |||
| 142 | if (!prop) { | ||
| 143 | prop = node->deadprops; | ||
| 144 | node->deadprops = NULL; | ||
| 145 | } | ||
| 146 | } | ||
| 147 | kfree(node->full_name); | ||
| 148 | kfree(node->data); | ||
| 149 | kfree(node); | ||
| 150 | } | ||
| 151 | |||
| 152 | /** | ||
| 153 | * of_node_put - Decrement refcount of a node | ||
| 154 | * @node: Node to dec refcount, NULL is supported to | ||
| 155 | * simplify writing of callers | ||
| 156 | * | ||
| 157 | */ | ||
| 158 | void of_node_put(struct device_node *node) | ||
| 159 | { | ||
| 160 | if (node) | ||
| 161 | kobject_put(&node->kobj); | ||
| 162 | } | ||
| 163 | EXPORT_SYMBOL(of_node_put); | ||
| 164 | #else | ||
| 165 | static void of_node_release(struct kobject *kobj) | 96 | static void of_node_release(struct kobject *kobj) |
| 166 | { | 97 | { |
| 167 | /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ | 98 | /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ |
| @@ -200,13 +131,16 @@ static const char *safe_name(struct kobject *kobj, const char *orig_name) | |||
| 200 | return name; | 131 | return name; |
| 201 | } | 132 | } |
| 202 | 133 | ||
| 203 | static int __of_add_property_sysfs(struct device_node *np, struct property *pp) | 134 | int __of_add_property_sysfs(struct device_node *np, struct property *pp) |
| 204 | { | 135 | { |
| 205 | int rc; | 136 | int rc; |
| 206 | 137 | ||
| 207 | /* Important: Don't leak passwords */ | 138 | /* Important: Don't leak passwords */ |
| 208 | bool secure = strncmp(pp->name, "security-", 9) == 0; | 139 | bool secure = strncmp(pp->name, "security-", 9) == 0; |
| 209 | 140 | ||
| 141 | if (!of_kset || !of_node_is_attached(np)) | ||
| 142 | return 0; | ||
| 143 | |||
| 210 | sysfs_bin_attr_init(&pp->attr); | 144 | sysfs_bin_attr_init(&pp->attr); |
| 211 | pp->attr.attr.name = safe_name(&np->kobj, pp->name); | 145 | pp->attr.attr.name = safe_name(&np->kobj, pp->name); |
| 212 | pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; | 146 | pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; |
| @@ -218,12 +152,15 @@ static int __of_add_property_sysfs(struct device_node *np, struct property *pp) | |||
| 218 | return rc; | 152 | return rc; |
| 219 | } | 153 | } |
| 220 | 154 | ||
| 221 | static int __of_node_add(struct device_node *np) | 155 | int __of_attach_node_sysfs(struct device_node *np) |
| 222 | { | 156 | { |
| 223 | const char *name; | 157 | const char *name; |
| 224 | struct property *pp; | 158 | struct property *pp; |
| 225 | int rc; | 159 | int rc; |
| 226 | 160 | ||
| 161 | if (!of_kset) | ||
| 162 | return 0; | ||
| 163 | |||
| 227 | np->kobj.kset = of_kset; | 164 | np->kobj.kset = of_kset; |
| 228 | if (!np->parent) { | 165 | if (!np->parent) { |
| 229 | /* Nodes without parents are new top level trees */ | 166 | /* Nodes without parents are new top level trees */ |
| @@ -245,59 +182,20 @@ static int __of_node_add(struct device_node *np) | |||
| 245 | return 0; | 182 | return 0; |
| 246 | } | 183 | } |
| 247 | 184 | ||
| 248 | int of_node_add(struct device_node *np) | ||
| 249 | { | ||
| 250 | int rc = 0; | ||
| 251 | |||
| 252 | BUG_ON(!of_node_is_initialized(np)); | ||
| 253 | |||
| 254 | /* | ||
| 255 | * Grab the mutex here so that in a race condition between of_init() and | ||
| 256 | * of_node_add(), node addition will still be consistent. | ||
| 257 | */ | ||
| 258 | mutex_lock(&of_aliases_mutex); | ||
| 259 | if (of_kset) | ||
| 260 | rc = __of_node_add(np); | ||
| 261 | else | ||
| 262 | /* This scenario may be perfectly valid, but report it anyway */ | ||
| 263 | pr_info("of_node_add(%s) before of_init()\n", np->full_name); | ||
| 264 | mutex_unlock(&of_aliases_mutex); | ||
| 265 | return rc; | ||
| 266 | } | ||
| 267 | |||
| 268 | #if defined(CONFIG_OF_DYNAMIC) | ||
| 269 | static void of_node_remove(struct device_node *np) | ||
| 270 | { | ||
| 271 | struct property *pp; | ||
| 272 | |||
| 273 | BUG_ON(!of_node_is_initialized(np)); | ||
| 274 | |||
| 275 | /* only remove properties if on sysfs */ | ||
| 276 | if (of_node_is_attached(np)) { | ||
| 277 | for_each_property_of_node(np, pp) | ||
| 278 | sysfs_remove_bin_file(&np->kobj, &pp->attr); | ||
| 279 | kobject_del(&np->kobj); | ||
| 280 | } | ||
| 281 | |||
| 282 | /* finally remove the kobj_init ref */ | ||
| 283 | of_node_put(np); | ||
| 284 | } | ||
| 285 | #endif | ||
| 286 | |||
| 287 | static int __init of_init(void) | 185 | static int __init of_init(void) |
| 288 | { | 186 | { |
| 289 | struct device_node *np; | 187 | struct device_node *np; |
| 290 | 188 | ||
| 291 | /* Create the kset, and register existing nodes */ | 189 | /* Create the kset, and register existing nodes */ |
| 292 | mutex_lock(&of_aliases_mutex); | 190 | mutex_lock(&of_mutex); |
| 293 | of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); | 191 | of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); |
| 294 | if (!of_kset) { | 192 | if (!of_kset) { |
| 295 | mutex_unlock(&of_aliases_mutex); | 193 | mutex_unlock(&of_mutex); |
| 296 | return -ENOMEM; | 194 | return -ENOMEM; |
| 297 | } | 195 | } |
| 298 | for_each_of_allnodes(np) | 196 | for_each_of_allnodes(np) |
| 299 | __of_node_add(np); | 197 | __of_attach_node_sysfs(np); |
| 300 | mutex_unlock(&of_aliases_mutex); | 198 | mutex_unlock(&of_mutex); |
| 301 | 199 | ||
| 302 | /* Symlink in /proc as required by userspace ABI */ | 200 | /* Symlink in /proc as required by userspace ABI */ |
| 303 | if (of_allnodes) | 201 | if (of_allnodes) |
| @@ -369,8 +267,8 @@ EXPORT_SYMBOL(of_find_all_nodes); | |||
| 369 | * Find a property with a given name for a given node | 267 | * Find a property with a given name for a given node |
| 370 | * and return the value. | 268 | * and return the value. |
| 371 | */ | 269 | */ |
| 372 | static const void *__of_get_property(const struct device_node *np, | 270 | const void *__of_get_property(const struct device_node *np, |
| 373 | const char *name, int *lenp) | 271 | const char *name, int *lenp) |
| 374 | { | 272 | { |
| 375 | struct property *pp = __of_find_property(np, name, lenp); | 273 | struct property *pp = __of_find_property(np, name, lenp); |
| 376 | 274 | ||
| @@ -1748,32 +1646,10 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_na | |||
| 1748 | } | 1646 | } |
| 1749 | EXPORT_SYMBOL(of_count_phandle_with_args); | 1647 | EXPORT_SYMBOL(of_count_phandle_with_args); |
| 1750 | 1648 | ||
| 1751 | #if defined(CONFIG_OF_DYNAMIC) | ||
| 1752 | static int of_property_notify(int action, struct device_node *np, | ||
| 1753 | struct property *prop) | ||
| 1754 | { | ||
| 1755 | struct of_prop_reconfig pr; | ||
| 1756 | |||
| 1757 | /* only call notifiers if the node is attached */ | ||
| 1758 | if (!of_node_is_attached(np)) | ||
| 1759 | return 0; | ||
| 1760 | |||
| 1761 | pr.dn = np; | ||
| 1762 | pr.prop = prop; | ||
| 1763 | return of_reconfig_notify(action, &pr); | ||
| 1764 | } | ||
| 1765 | #else | ||
| 1766 | static int of_property_notify(int action, struct device_node *np, | ||
| 1767 | struct property *prop) | ||
| 1768 | { | ||
| 1769 | return 0; | ||
| 1770 | } | ||
| 1771 | #endif | ||
| 1772 | |||
| 1773 | /** | 1649 | /** |
| 1774 | * __of_add_property - Add a property to a node without lock operations | 1650 | * __of_add_property - Add a property to a node without lock operations |
| 1775 | */ | 1651 | */ |
| 1776 | static int __of_add_property(struct device_node *np, struct property *prop) | 1652 | int __of_add_property(struct device_node *np, struct property *prop) |
| 1777 | { | 1653 | { |
| 1778 | struct property **next; | 1654 | struct property **next; |
| 1779 | 1655 | ||
| @@ -1799,22 +1675,49 @@ int of_add_property(struct device_node *np, struct property *prop) | |||
| 1799 | unsigned long flags; | 1675 | unsigned long flags; |
| 1800 | int rc; | 1676 | int rc; |
| 1801 | 1677 | ||
| 1802 | rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop); | 1678 | mutex_lock(&of_mutex); |
| 1803 | if (rc) | ||
| 1804 | return rc; | ||
| 1805 | 1679 | ||
| 1806 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1680 | raw_spin_lock_irqsave(&devtree_lock, flags); |
| 1807 | rc = __of_add_property(np, prop); | 1681 | rc = __of_add_property(np, prop); |
| 1808 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1682 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 1809 | if (rc) | ||
| 1810 | return rc; | ||
| 1811 | 1683 | ||
| 1812 | if (of_node_is_attached(np)) | 1684 | if (!rc) |
| 1813 | __of_add_property_sysfs(np, prop); | 1685 | __of_add_property_sysfs(np, prop); |
| 1814 | 1686 | ||
| 1687 | mutex_unlock(&of_mutex); | ||
| 1688 | |||
| 1689 | if (!rc) | ||
| 1690 | of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop, NULL); | ||
| 1691 | |||
| 1815 | return rc; | 1692 | return rc; |
| 1816 | } | 1693 | } |
| 1817 | 1694 | ||
| 1695 | int __of_remove_property(struct device_node *np, struct property *prop) | ||
| 1696 | { | ||
| 1697 | struct property **next; | ||
| 1698 | |||
| 1699 | for (next = &np->properties; *next; next = &(*next)->next) { | ||
| 1700 | if (*next == prop) | ||
| 1701 | break; | ||
| 1702 | } | ||
| 1703 | if (*next == NULL) | ||
| 1704 | return -ENODEV; | ||
| 1705 | |||
| 1706 | /* found the node */ | ||
| 1707 | *next = prop->next; | ||
| 1708 | prop->next = np->deadprops; | ||
| 1709 | np->deadprops = prop; | ||
| 1710 | |||
| 1711 | return 0; | ||
| 1712 | } | ||
| 1713 | |||
| 1714 | void __of_remove_property_sysfs(struct device_node *np, struct property *prop) | ||
| 1715 | { | ||
| 1716 | /* at early boot, bail here and defer setup to of_init() */ | ||
| 1717 | if (of_kset && of_node_is_attached(np)) | ||
| 1718 | sysfs_remove_bin_file(&np->kobj, &prop->attr); | ||
| 1719 | } | ||
| 1720 | |||
| 1818 | /** | 1721 | /** |
| 1819 | * of_remove_property - Remove a property from a node. | 1722 | * of_remove_property - Remove a property from a node. |
| 1820 | * | 1723 | * |
| @@ -1825,211 +1728,98 @@ int of_add_property(struct device_node *np, struct property *prop) | |||
| 1825 | */ | 1728 | */ |
| 1826 | int of_remove_property(struct device_node *np, struct property *prop) | 1729 | int of_remove_property(struct device_node *np, struct property *prop) |
| 1827 | { | 1730 | { |
| 1828 | struct property **next; | ||
| 1829 | unsigned long flags; | 1731 | unsigned long flags; |
| 1830 | int found = 0; | ||
| 1831 | int rc; | 1732 | int rc; |
| 1832 | 1733 | ||
| 1833 | rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop); | 1734 | mutex_lock(&of_mutex); |
| 1834 | if (rc) | ||
| 1835 | return rc; | ||
| 1836 | 1735 | ||
| 1837 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1736 | raw_spin_lock_irqsave(&devtree_lock, flags); |
| 1838 | next = &np->properties; | 1737 | rc = __of_remove_property(np, prop); |
| 1839 | while (*next) { | ||
| 1840 | if (*next == prop) { | ||
| 1841 | /* found the node */ | ||
| 1842 | *next = prop->next; | ||
| 1843 | prop->next = np->deadprops; | ||
| 1844 | np->deadprops = prop; | ||
| 1845 | found = 1; | ||
| 1846 | break; | ||
| 1847 | } | ||
| 1848 | next = &(*next)->next; | ||
| 1849 | } | ||
| 1850 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1738 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 1851 | 1739 | ||
| 1852 | if (!found) | 1740 | if (!rc) |
| 1853 | return -ENODEV; | 1741 | __of_remove_property_sysfs(np, prop); |
| 1854 | 1742 | ||
| 1855 | /* at early boot, bail hear and defer setup to of_init() */ | 1743 | mutex_unlock(&of_mutex); |
| 1856 | if (!of_kset) | ||
| 1857 | return 0; | ||
| 1858 | 1744 | ||
| 1859 | sysfs_remove_bin_file(&np->kobj, &prop->attr); | 1745 | if (!rc) |
| 1746 | of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop, NULL); | ||
| 1860 | 1747 | ||
| 1861 | return 0; | 1748 | return rc; |
| 1862 | } | 1749 | } |
| 1863 | 1750 | ||
| 1864 | /* | 1751 | int __of_update_property(struct device_node *np, struct property *newprop, |
| 1865 | * of_update_property - Update a property in a node, if the property does | 1752 | struct property **oldpropp) |
| 1866 | * not exist, add it. | ||
| 1867 | * | ||
| 1868 | * Note that we don't actually remove it, since we have given out | ||
| 1869 | * who-knows-how-many pointers to the data using get-property. | ||
| 1870 | * Instead we just move the property to the "dead properties" list, | ||
| 1871 | * and add the new property to the property list | ||
| 1872 | */ | ||
| 1873 | int of_update_property(struct device_node *np, struct property *newprop) | ||
| 1874 | { | 1753 | { |
| 1875 | struct property **next, *oldprop; | 1754 | struct property **next, *oldprop; |
| 1876 | unsigned long flags; | ||
| 1877 | int rc; | ||
| 1878 | |||
| 1879 | rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); | ||
| 1880 | if (rc) | ||
| 1881 | return rc; | ||
| 1882 | 1755 | ||
| 1883 | if (!newprop->name) | 1756 | for (next = &np->properties; *next; next = &(*next)->next) { |
| 1884 | return -EINVAL; | 1757 | if (of_prop_cmp((*next)->name, newprop->name) == 0) |
| 1758 | break; | ||
| 1759 | } | ||
| 1760 | *oldpropp = oldprop = *next; | ||
| 1885 | 1761 | ||
| 1886 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1762 | if (oldprop) { |
| 1887 | next = &np->properties; | ||
| 1888 | oldprop = __of_find_property(np, newprop->name, NULL); | ||
| 1889 | if (!oldprop) { | ||
| 1890 | /* add the new node */ | ||
| 1891 | rc = __of_add_property(np, newprop); | ||
| 1892 | } else while (*next) { | ||
| 1893 | /* replace the node */ | 1763 | /* replace the node */ |
| 1894 | if (*next == oldprop) { | 1764 | newprop->next = oldprop->next; |
| 1895 | newprop->next = oldprop->next; | 1765 | *next = newprop; |
| 1896 | *next = newprop; | 1766 | oldprop->next = np->deadprops; |
| 1897 | oldprop->next = np->deadprops; | 1767 | np->deadprops = oldprop; |
| 1898 | np->deadprops = oldprop; | 1768 | } else { |
| 1899 | break; | 1769 | /* new node */ |
| 1900 | } | 1770 | newprop->next = NULL; |
| 1901 | next = &(*next)->next; | 1771 | *next = newprop; |
| 1902 | } | 1772 | } |
| 1903 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 1904 | if (rc) | ||
| 1905 | return rc; | ||
| 1906 | 1773 | ||
| 1774 | return 0; | ||
| 1775 | } | ||
| 1776 | |||
| 1777 | void __of_update_property_sysfs(struct device_node *np, struct property *newprop, | ||
| 1778 | struct property *oldprop) | ||
| 1779 | { | ||
| 1907 | /* At early boot, bail out and defer setup to of_init() */ | 1780 | /* At early boot, bail out and defer setup to of_init() */ |
| 1908 | if (!of_kset) | 1781 | if (!of_kset) |
| 1909 | return 0; | 1782 | return; |
| 1910 | 1783 | ||
| 1911 | /* Update the sysfs attribute */ | ||
| 1912 | if (oldprop) | 1784 | if (oldprop) |
| 1913 | sysfs_remove_bin_file(&np->kobj, &oldprop->attr); | 1785 | sysfs_remove_bin_file(&np->kobj, &oldprop->attr); |
| 1914 | __of_add_property_sysfs(np, newprop); | 1786 | __of_add_property_sysfs(np, newprop); |
| 1915 | |||
| 1916 | return 0; | ||
| 1917 | } | 1787 | } |
| 1918 | 1788 | ||
| 1919 | #if defined(CONFIG_OF_DYNAMIC) | ||
| 1920 | /* | 1789 | /* |
| 1921 | * Support for dynamic device trees. | 1790 | * of_update_property - Update a property in a node, if the property does |
| 1791 | * not exist, add it. | ||
| 1922 | * | 1792 | * |
| 1923 | * On some platforms, the device tree can be manipulated at runtime. | 1793 | * Note that we don't actually remove it, since we have given out |
| 1924 | * The routines in this section support adding, removing and changing | 1794 | * who-knows-how-many pointers to the data using get-property. |
| 1925 | * device tree nodes. | 1795 | * Instead we just move the property to the "dead properties" list, |
| 1926 | */ | 1796 | * and add the new property to the property list |
| 1927 | |||
| 1928 | static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); | ||
| 1929 | |||
| 1930 | int of_reconfig_notifier_register(struct notifier_block *nb) | ||
| 1931 | { | ||
| 1932 | return blocking_notifier_chain_register(&of_reconfig_chain, nb); | ||
| 1933 | } | ||
| 1934 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_register); | ||
| 1935 | |||
| 1936 | int of_reconfig_notifier_unregister(struct notifier_block *nb) | ||
| 1937 | { | ||
| 1938 | return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); | ||
| 1939 | } | ||
| 1940 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); | ||
| 1941 | |||
| 1942 | int of_reconfig_notify(unsigned long action, void *p) | ||
| 1943 | { | ||
| 1944 | int rc; | ||
| 1945 | |||
| 1946 | rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); | ||
| 1947 | return notifier_to_errno(rc); | ||
| 1948 | } | ||
| 1949 | |||
| 1950 | /** | ||
| 1951 | * of_attach_node - Plug a device node into the tree and global list. | ||
| 1952 | */ | 1797 | */ |
| 1953 | int of_attach_node(struct device_node *np) | 1798 | int of_update_property(struct device_node *np, struct property *newprop) |
| 1954 | { | 1799 | { |
| 1800 | struct property *oldprop; | ||
| 1955 | unsigned long flags; | 1801 | unsigned long flags; |
| 1956 | int rc; | 1802 | int rc; |
| 1957 | 1803 | ||
| 1958 | rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); | 1804 | if (!newprop->name) |
| 1959 | if (rc) | 1805 | return -EINVAL; |
| 1960 | return rc; | ||
| 1961 | |||
| 1962 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
| 1963 | np->sibling = np->parent->child; | ||
| 1964 | np->allnext = np->parent->allnext; | ||
| 1965 | np->parent->allnext = np; | ||
| 1966 | np->parent->child = np; | ||
| 1967 | of_node_clear_flag(np, OF_DETACHED); | ||
| 1968 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 1969 | |||
| 1970 | of_node_add(np); | ||
| 1971 | return 0; | ||
| 1972 | } | ||
| 1973 | |||
| 1974 | /** | ||
| 1975 | * of_detach_node - "Unplug" a node from the device tree. | ||
| 1976 | * | ||
| 1977 | * The caller must hold a reference to the node. The memory associated with | ||
| 1978 | * the node is not freed until its refcount goes to zero. | ||
| 1979 | */ | ||
| 1980 | int of_detach_node(struct device_node *np) | ||
| 1981 | { | ||
| 1982 | struct device_node *parent; | ||
| 1983 | unsigned long flags; | ||
| 1984 | int rc = 0; | ||
| 1985 | 1806 | ||
| 1986 | rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); | 1807 | mutex_lock(&of_mutex); |
| 1987 | if (rc) | ||
| 1988 | return rc; | ||
| 1989 | 1808 | ||
| 1990 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1809 | raw_spin_lock_irqsave(&devtree_lock, flags); |
| 1810 | rc = __of_update_property(np, newprop, &oldprop); | ||
| 1811 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 1991 | 1812 | ||
| 1992 | if (of_node_check_flag(np, OF_DETACHED)) { | 1813 | if (!rc) |
| 1993 | /* someone already detached it */ | 1814 | __of_update_property_sysfs(np, newprop, oldprop); |
| 1994 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 1995 | return rc; | ||
| 1996 | } | ||
| 1997 | |||
| 1998 | parent = np->parent; | ||
| 1999 | if (!parent) { | ||
| 2000 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 2001 | return rc; | ||
| 2002 | } | ||
| 2003 | 1815 | ||
| 2004 | if (of_allnodes == np) | 1816 | mutex_unlock(&of_mutex); |
| 2005 | of_allnodes = np->allnext; | ||
| 2006 | else { | ||
| 2007 | struct device_node *prev; | ||
| 2008 | for (prev = of_allnodes; | ||
| 2009 | prev->allnext != np; | ||
| 2010 | prev = prev->allnext) | ||
| 2011 | ; | ||
| 2012 | prev->allnext = np->allnext; | ||
| 2013 | } | ||
| 2014 | 1817 | ||
| 2015 | if (parent->child == np) | 1818 | if (!rc) |
| 2016 | parent->child = np->sibling; | 1819 | of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop, oldprop); |
| 2017 | else { | ||
| 2018 | struct device_node *prevsib; | ||
| 2019 | for (prevsib = np->parent->child; | ||
| 2020 | prevsib->sibling != np; | ||
| 2021 | prevsib = prevsib->sibling) | ||
| 2022 | ; | ||
| 2023 | prevsib->sibling = np->sibling; | ||
| 2024 | } | ||
| 2025 | |||
| 2026 | of_node_set_flag(np, OF_DETACHED); | ||
| 2027 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 2028 | 1820 | ||
| 2029 | of_node_remove(np); | ||
| 2030 | return rc; | 1821 | return rc; |
| 2031 | } | 1822 | } |
| 2032 | #endif /* defined(CONFIG_OF_DYNAMIC) */ | ||
| 2033 | 1823 | ||
| 2034 | static void of_alias_add(struct alias_prop *ap, struct device_node *np, | 1824 | static void of_alias_add(struct alias_prop *ap, struct device_node *np, |
| 2035 | int id, const char *stem, int stem_len) | 1825 | int id, const char *stem, int stem_len) |
| @@ -2062,9 +1852,12 @@ void of_alias_scan(void * (*dt_alloc)(u64 size, u64 align)) | |||
| 2062 | of_chosen = of_find_node_by_path("/chosen@0"); | 1852 | of_chosen = of_find_node_by_path("/chosen@0"); |
| 2063 | 1853 | ||
| 2064 | if (of_chosen) { | 1854 | if (of_chosen) { |
| 1855 | /* linux,stdout-path and /aliases/stdout are for legacy compatibility */ | ||
| 2065 | const char *name = of_get_property(of_chosen, "stdout-path", NULL); | 1856 | const char *name = of_get_property(of_chosen, "stdout-path", NULL); |
| 2066 | if (!name) | 1857 | if (!name) |
| 2067 | name = of_get_property(of_chosen, "linux,stdout-path", NULL); | 1858 | name = of_get_property(of_chosen, "linux,stdout-path", NULL); |
| 1859 | if (IS_ENABLED(CONFIG_PPC) && !name) | ||
| 1860 | name = of_get_property(of_aliases, "stdout", NULL); | ||
| 2068 | if (name) | 1861 | if (name) |
| 2069 | of_stdout = of_find_node_by_path(name); | 1862 | of_stdout = of_find_node_by_path(name); |
| 2070 | } | 1863 | } |
| @@ -2122,7 +1915,7 @@ int of_alias_get_id(struct device_node *np, const char *stem) | |||
| 2122 | struct alias_prop *app; | 1915 | struct alias_prop *app; |
| 2123 | int id = -ENODEV; | 1916 | int id = -ENODEV; |
| 2124 | 1917 | ||
| 2125 | mutex_lock(&of_aliases_mutex); | 1918 | mutex_lock(&of_mutex); |
| 2126 | list_for_each_entry(app, &aliases_lookup, link) { | 1919 | list_for_each_entry(app, &aliases_lookup, link) { |
| 2127 | if (strcmp(app->stem, stem) != 0) | 1920 | if (strcmp(app->stem, stem) != 0) |
| 2128 | continue; | 1921 | continue; |
| @@ -2132,7 +1925,7 @@ int of_alias_get_id(struct device_node *np, const char *stem) | |||
| 2132 | break; | 1925 | break; |
| 2133 | } | 1926 | } |
| 2134 | } | 1927 | } |
| 2135 | mutex_unlock(&of_aliases_mutex); | 1928 | mutex_unlock(&of_mutex); |
| 2136 | 1929 | ||
| 2137 | return id; | 1930 | return id; |
| 2138 | } | 1931 | } |
| @@ -2180,20 +1973,22 @@ const char *of_prop_next_string(struct property *prop, const char *cur) | |||
| 2180 | EXPORT_SYMBOL_GPL(of_prop_next_string); | 1973 | EXPORT_SYMBOL_GPL(of_prop_next_string); |
| 2181 | 1974 | ||
| 2182 | /** | 1975 | /** |
| 2183 | * of_device_is_stdout_path - check if a device node matches the | 1976 | * of_console_check() - Test and setup console for DT setup |
| 2184 | * linux,stdout-path property | 1977 | * @dn - Pointer to device node |
| 2185 | * | 1978 | * @name - Name to use for preferred console without index. ex. "ttyS" |
| 2186 | * Check if this device node matches the linux,stdout-path property | 1979 | * @index - Index to use for preferred console. |
| 2187 | * in the chosen node. return true if yes, false otherwise. | 1980 | * |
| 1981 | * Check if the given device node matches the stdout-path property in the | ||
| 1982 | * /chosen node. If it does then register it as the preferred console and return | ||
| 1983 | * TRUE. Otherwise return FALSE. | ||
| 2188 | */ | 1984 | */ |
| 2189 | int of_device_is_stdout_path(struct device_node *dn) | 1985 | bool of_console_check(struct device_node *dn, char *name, int index) |
| 2190 | { | 1986 | { |
| 2191 | if (!of_stdout) | 1987 | if (!dn || dn != of_stdout || console_set_on_cmdline) |
| 2192 | return false; | 1988 | return false; |
| 2193 | 1989 | return add_preferred_console(name, index, NULL); | |
| 2194 | return of_stdout == dn; | ||
| 2195 | } | 1990 | } |
| 2196 | EXPORT_SYMBOL_GPL(of_device_is_stdout_path); | 1991 | EXPORT_SYMBOL_GPL(of_console_check); |
| 2197 | 1992 | ||
| 2198 | /** | 1993 | /** |
| 2199 | * of_find_next_cache_node - Find a node's subsidiary cache | 1994 | * of_find_next_cache_node - Find a node's subsidiary cache |
diff --git a/drivers/of/device.c b/drivers/of/device.c index dafb9736ab9b..46d6c75c1404 100644 --- a/drivers/of/device.c +++ b/drivers/of/device.c | |||
| @@ -160,7 +160,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
| 160 | add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); | 160 | add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen); |
| 161 | 161 | ||
| 162 | seen = 0; | 162 | seen = 0; |
| 163 | mutex_lock(&of_aliases_mutex); | 163 | mutex_lock(&of_mutex); |
| 164 | list_for_each_entry(app, &aliases_lookup, link) { | 164 | list_for_each_entry(app, &aliases_lookup, link) { |
| 165 | if (dev->of_node == app->np) { | 165 | if (dev->of_node == app->np) { |
| 166 | add_uevent_var(env, "OF_ALIAS_%d=%s", seen, | 166 | add_uevent_var(env, "OF_ALIAS_%d=%s", seen, |
| @@ -168,7 +168,7 @@ void of_device_uevent(struct device *dev, struct kobj_uevent_env *env) | |||
| 168 | seen++; | 168 | seen++; |
| 169 | } | 169 | } |
| 170 | } | 170 | } |
| 171 | mutex_unlock(&of_aliases_mutex); | 171 | mutex_unlock(&of_mutex); |
| 172 | } | 172 | } |
| 173 | 173 | ||
| 174 | int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) | 174 | int of_device_uevent_modalias(struct device *dev, struct kobj_uevent_env *env) |
diff --git a/drivers/of/dynamic.c b/drivers/of/dynamic.c new file mode 100644 index 000000000000..54fecc49a1fe --- /dev/null +++ b/drivers/of/dynamic.c | |||
| @@ -0,0 +1,660 @@ | |||
| 1 | /* | ||
| 2 | * Support for dynamic device trees. | ||
| 3 | * | ||
| 4 | * On some platforms, the device tree can be manipulated at runtime. | ||
| 5 | * The routines in this section support adding, removing and changing | ||
| 6 | * device tree nodes. | ||
| 7 | */ | ||
| 8 | |||
| 9 | #include <linux/of.h> | ||
| 10 | #include <linux/spinlock.h> | ||
| 11 | #include <linux/slab.h> | ||
| 12 | #include <linux/string.h> | ||
| 13 | #include <linux/proc_fs.h> | ||
| 14 | |||
| 15 | #include "of_private.h" | ||
| 16 | |||
| 17 | /** | ||
| 18 | * of_node_get() - Increment refcount of a node | ||
| 19 | * @node: Node to inc refcount, NULL is supported to simplify writing of | ||
| 20 | * callers | ||
| 21 | * | ||
| 22 | * Returns node. | ||
| 23 | */ | ||
| 24 | struct device_node *of_node_get(struct device_node *node) | ||
| 25 | { | ||
| 26 | if (node) | ||
| 27 | kobject_get(&node->kobj); | ||
| 28 | return node; | ||
| 29 | } | ||
| 30 | EXPORT_SYMBOL(of_node_get); | ||
| 31 | |||
| 32 | /** | ||
| 33 | * of_node_put() - Decrement refcount of a node | ||
| 34 | * @node: Node to dec refcount, NULL is supported to simplify writing of | ||
| 35 | * callers | ||
| 36 | */ | ||
| 37 | void of_node_put(struct device_node *node) | ||
| 38 | { | ||
| 39 | if (node) | ||
| 40 | kobject_put(&node->kobj); | ||
| 41 | } | ||
| 42 | EXPORT_SYMBOL(of_node_put); | ||
| 43 | |||
| 44 | void __of_detach_node_sysfs(struct device_node *np) | ||
| 45 | { | ||
| 46 | struct property *pp; | ||
| 47 | |||
| 48 | BUG_ON(!of_node_is_initialized(np)); | ||
| 49 | if (!of_kset) | ||
| 50 | return; | ||
| 51 | |||
| 52 | /* only remove properties if on sysfs */ | ||
| 53 | if (of_node_is_attached(np)) { | ||
| 54 | for_each_property_of_node(np, pp) | ||
| 55 | sysfs_remove_bin_file(&np->kobj, &pp->attr); | ||
| 56 | kobject_del(&np->kobj); | ||
| 57 | } | ||
| 58 | |||
| 59 | /* finally remove the kobj_init ref */ | ||
| 60 | of_node_put(np); | ||
| 61 | } | ||
| 62 | |||
| 63 | static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); | ||
| 64 | |||
| 65 | int of_reconfig_notifier_register(struct notifier_block *nb) | ||
| 66 | { | ||
| 67 | return blocking_notifier_chain_register(&of_reconfig_chain, nb); | ||
| 68 | } | ||
| 69 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_register); | ||
| 70 | |||
| 71 | int of_reconfig_notifier_unregister(struct notifier_block *nb) | ||
| 72 | { | ||
| 73 | return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); | ||
| 74 | } | ||
| 75 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); | ||
| 76 | |||
| 77 | int of_reconfig_notify(unsigned long action, void *p) | ||
| 78 | { | ||
| 79 | int rc; | ||
| 80 | |||
| 81 | rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); | ||
| 82 | return notifier_to_errno(rc); | ||
| 83 | } | ||
| 84 | |||
| 85 | int of_property_notify(int action, struct device_node *np, | ||
| 86 | struct property *prop, struct property *oldprop) | ||
| 87 | { | ||
| 88 | struct of_prop_reconfig pr; | ||
| 89 | |||
| 90 | /* only call notifiers if the node is attached */ | ||
| 91 | if (!of_node_is_attached(np)) | ||
| 92 | return 0; | ||
| 93 | |||
| 94 | pr.dn = np; | ||
| 95 | pr.prop = prop; | ||
| 96 | pr.old_prop = oldprop; | ||
| 97 | return of_reconfig_notify(action, &pr); | ||
| 98 | } | ||
| 99 | |||
| 100 | void __of_attach_node(struct device_node *np) | ||
| 101 | { | ||
| 102 | const __be32 *phandle; | ||
| 103 | int sz; | ||
| 104 | |||
| 105 | np->name = __of_get_property(np, "name", NULL) ? : "<NULL>"; | ||
| 106 | np->type = __of_get_property(np, "device_type", NULL) ? : "<NULL>"; | ||
| 107 | |||
| 108 | phandle = __of_get_property(np, "phandle", &sz); | ||
| 109 | if (!phandle) | ||
| 110 | phandle = __of_get_property(np, "linux,phandle", &sz); | ||
| 111 | if (IS_ENABLED(PPC_PSERIES) && !phandle) | ||
| 112 | phandle = __of_get_property(np, "ibm,phandle", &sz); | ||
| 113 | np->phandle = (phandle && (sz >= 4)) ? be32_to_cpup(phandle) : 0; | ||
| 114 | |||
| 115 | np->child = NULL; | ||
| 116 | np->sibling = np->parent->child; | ||
| 117 | np->allnext = np->parent->allnext; | ||
| 118 | np->parent->allnext = np; | ||
| 119 | np->parent->child = np; | ||
| 120 | of_node_clear_flag(np, OF_DETACHED); | ||
| 121 | } | ||
| 122 | |||
| 123 | /** | ||
| 124 | * of_attach_node() - Plug a device node into the tree and global list. | ||
| 125 | */ | ||
| 126 | int of_attach_node(struct device_node *np) | ||
| 127 | { | ||
| 128 | unsigned long flags; | ||
| 129 | |||
| 130 | mutex_lock(&of_mutex); | ||
| 131 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
| 132 | __of_attach_node(np); | ||
| 133 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 134 | |||
| 135 | __of_attach_node_sysfs(np); | ||
| 136 | mutex_unlock(&of_mutex); | ||
| 137 | |||
| 138 | of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); | ||
| 139 | |||
| 140 | return 0; | ||
| 141 | } | ||
| 142 | |||
| 143 | void __of_detach_node(struct device_node *np) | ||
| 144 | { | ||
| 145 | struct device_node *parent; | ||
| 146 | |||
| 147 | if (WARN_ON(of_node_check_flag(np, OF_DETACHED))) | ||
| 148 | return; | ||
| 149 | |||
| 150 | parent = np->parent; | ||
| 151 | if (WARN_ON(!parent)) | ||
| 152 | return; | ||
| 153 | |||
| 154 | if (of_allnodes == np) | ||
| 155 | of_allnodes = np->allnext; | ||
| 156 | else { | ||
| 157 | struct device_node *prev; | ||
| 158 | for (prev = of_allnodes; | ||
| 159 | prev->allnext != np; | ||
| 160 | prev = prev->allnext) | ||
| 161 | ; | ||
| 162 | prev->allnext = np->allnext; | ||
| 163 | } | ||
| 164 | |||
| 165 | if (parent->child == np) | ||
| 166 | parent->child = np->sibling; | ||
| 167 | else { | ||
| 168 | struct device_node *prevsib; | ||
| 169 | for (prevsib = np->parent->child; | ||
| 170 | prevsib->sibling != np; | ||
| 171 | prevsib = prevsib->sibling) | ||
| 172 | ; | ||
| 173 | prevsib->sibling = np->sibling; | ||
| 174 | } | ||
| 175 | |||
| 176 | of_node_set_flag(np, OF_DETACHED); | ||
| 177 | } | ||
| 178 | |||
| 179 | /** | ||
| 180 | * of_detach_node() - "Unplug" a node from the device tree. | ||
| 181 | * | ||
| 182 | * The caller must hold a reference to the node. The memory associated with | ||
| 183 | * the node is not freed until its refcount goes to zero. | ||
| 184 | */ | ||
| 185 | int of_detach_node(struct device_node *np) | ||
| 186 | { | ||
| 187 | unsigned long flags; | ||
| 188 | int rc = 0; | ||
| 189 | |||
| 190 | mutex_lock(&of_mutex); | ||
| 191 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
| 192 | __of_detach_node(np); | ||
| 193 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 194 | |||
| 195 | __of_detach_node_sysfs(np); | ||
| 196 | mutex_unlock(&of_mutex); | ||
| 197 | |||
| 198 | of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); | ||
| 199 | |||
| 200 | return rc; | ||
| 201 | } | ||
| 202 | |||
| 203 | /** | ||
| 204 | * of_node_release() - release a dynamically allocated node | ||
| 205 | * @kref: kref element of the node to be released | ||
| 206 | * | ||
| 207 | * In of_node_put() this function is passed to kref_put() as the destructor. | ||
| 208 | */ | ||
| 209 | void of_node_release(struct kobject *kobj) | ||
| 210 | { | ||
| 211 | struct device_node *node = kobj_to_device_node(kobj); | ||
| 212 | struct property *prop = node->properties; | ||
| 213 | |||
| 214 | /* We should never be releasing nodes that haven't been detached. */ | ||
| 215 | if (!of_node_check_flag(node, OF_DETACHED)) { | ||
| 216 | pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); | ||
| 217 | dump_stack(); | ||
| 218 | return; | ||
| 219 | } | ||
| 220 | |||
| 221 | if (!of_node_check_flag(node, OF_DYNAMIC)) | ||
| 222 | return; | ||
| 223 | |||
| 224 | while (prop) { | ||
| 225 | struct property *next = prop->next; | ||
| 226 | kfree(prop->name); | ||
| 227 | kfree(prop->value); | ||
| 228 | kfree(prop); | ||
| 229 | prop = next; | ||
| 230 | |||
| 231 | if (!prop) { | ||
| 232 | prop = node->deadprops; | ||
| 233 | node->deadprops = NULL; | ||
| 234 | } | ||
| 235 | } | ||
| 236 | kfree(node->full_name); | ||
| 237 | kfree(node->data); | ||
| 238 | kfree(node); | ||
| 239 | } | ||
| 240 | |||
| 241 | /** | ||
| 242 | * __of_prop_dup - Copy a property dynamically. | ||
| 243 | * @prop: Property to copy | ||
| 244 | * @allocflags: Allocation flags (typically pass GFP_KERNEL) | ||
| 245 | * | ||
| 246 | * Copy a property by dynamically allocating the memory of both the | ||
| 247 | * property stucture and the property name & contents. The property's | ||
| 248 | * flags have the OF_DYNAMIC bit set so that we can differentiate between | ||
| 249 | * dynamically allocated properties and not. | ||
| 250 | * Returns the newly allocated property or NULL on out of memory error. | ||
| 251 | */ | ||
| 252 | struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags) | ||
| 253 | { | ||
| 254 | struct property *new; | ||
| 255 | |||
| 256 | new = kzalloc(sizeof(*new), allocflags); | ||
| 257 | if (!new) | ||
| 258 | return NULL; | ||
| 259 | |||
| 260 | /* | ||
| 261 | * NOTE: There is no check for zero length value. | ||
| 262 | * In case of a boolean property, this will allocate a value | ||
| 263 | * of zero bytes. We do this to work around the use | ||
| 264 | * of of_get_property() calls on boolean values. | ||
| 265 | */ | ||
| 266 | new->name = kstrdup(prop->name, allocflags); | ||
| 267 | new->value = kmemdup(prop->value, prop->length, allocflags); | ||
| 268 | new->length = prop->length; | ||
| 269 | if (!new->name || !new->value) | ||
| 270 | goto err_free; | ||
| 271 | |||
| 272 | /* mark the property as dynamic */ | ||
| 273 | of_property_set_flag(new, OF_DYNAMIC); | ||
| 274 | |||
| 275 | return new; | ||
| 276 | |||
| 277 | err_free: | ||
| 278 | kfree(new->name); | ||
| 279 | kfree(new->value); | ||
| 280 | kfree(new); | ||
| 281 | return NULL; | ||
| 282 | } | ||
| 283 | |||
| 284 | /** | ||
| 285 | * __of_node_alloc() - Create an empty device node dynamically. | ||
| 286 | * @full_name: Full name of the new device node | ||
| 287 | * @allocflags: Allocation flags (typically pass GFP_KERNEL) | ||
| 288 | * | ||
| 289 | * Create an empty device tree node, suitable for further modification. | ||
| 290 | * The node data are dynamically allocated and all the node flags | ||
| 291 | * have the OF_DYNAMIC & OF_DETACHED bits set. | ||
| 292 | * Returns the newly allocated node or NULL on out of memory error. | ||
| 293 | */ | ||
| 294 | struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags) | ||
| 295 | { | ||
| 296 | struct device_node *node; | ||
| 297 | |||
| 298 | node = kzalloc(sizeof(*node), allocflags); | ||
| 299 | if (!node) | ||
| 300 | return NULL; | ||
| 301 | |||
| 302 | node->full_name = kstrdup(full_name, allocflags); | ||
| 303 | of_node_set_flag(node, OF_DYNAMIC); | ||
| 304 | of_node_set_flag(node, OF_DETACHED); | ||
| 305 | if (!node->full_name) | ||
| 306 | goto err_free; | ||
| 307 | |||
| 308 | of_node_init(node); | ||
| 309 | |||
| 310 | return node; | ||
| 311 | |||
| 312 | err_free: | ||
| 313 | kfree(node->full_name); | ||
| 314 | kfree(node); | ||
| 315 | return NULL; | ||
| 316 | } | ||
| 317 | |||
| 318 | static 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 | ||
| 326 | static 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 | ||
| 355 | static inline void __of_changeset_entry_dump(struct of_changeset_entry *ce) | ||
| 356 | { | ||
| 357 | /* empty */ | ||
| 358 | } | ||
| 359 | #endif | ||
| 360 | |||
| 361 | static 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 | |||
| 386 | static 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 | |||
| 416 | static 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 | |||
| 508 | static 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 | */ | ||
| 523 | void 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 | */ | ||
| 537 | void 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 | */ | ||
| 557 | int 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 | */ | ||
| 596 | int 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 | */ | ||
| 639 | int 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/fdt.c b/drivers/of/fdt.c index 9aa012e6ea0a..f46a24ffa3fe 100644 --- a/drivers/of/fdt.c +++ b/drivers/of/fdt.c | |||
| @@ -923,24 +923,24 @@ int __init early_init_dt_scan_chosen(unsigned long node, const char *uname, | |||
| 923 | } | 923 | } |
| 924 | 924 | ||
| 925 | #ifdef CONFIG_HAVE_MEMBLOCK | 925 | #ifdef CONFIG_HAVE_MEMBLOCK |
| 926 | #define MAX_PHYS_ADDR ((phys_addr_t)~0) | ||
| 927 | |||
| 926 | void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) | 928 | void __init __weak early_init_dt_add_memory_arch(u64 base, u64 size) |
| 927 | { | 929 | { |
| 928 | const u64 phys_offset = __pa(PAGE_OFFSET); | 930 | const u64 phys_offset = __pa(PAGE_OFFSET); |
| 929 | base &= PAGE_MASK; | 931 | base &= PAGE_MASK; |
| 930 | size &= PAGE_MASK; | 932 | size &= PAGE_MASK; |
| 931 | 933 | ||
| 932 | if (sizeof(phys_addr_t) < sizeof(u64)) { | 934 | if (base > MAX_PHYS_ADDR) { |
| 933 | if (base > ULONG_MAX) { | 935 | pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", |
| 934 | pr_warning("Ignoring memory block 0x%llx - 0x%llx\n", | 936 | base, base + size); |
| 935 | base, base + size); | 937 | return; |
| 936 | return; | 938 | } |
| 937 | } | ||
| 938 | 939 | ||
| 939 | if (base + size > ULONG_MAX) { | 940 | if (base + size > MAX_PHYS_ADDR) { |
| 940 | pr_warning("Ignoring memory range 0x%lx - 0x%llx\n", | 941 | pr_warning("Ignoring memory range 0x%lx - 0x%llx\n", |
| 941 | ULONG_MAX, base + size); | 942 | ULONG_MAX, base + size); |
| 942 | size = ULONG_MAX - base; | 943 | size = MAX_PHYS_ADDR - base; |
| 943 | } | ||
| 944 | } | 944 | } |
| 945 | 945 | ||
| 946 | if (base + size < phys_offset) { | 946 | if (base + size < phys_offset) { |
diff --git a/drivers/of/of_private.h b/drivers/of/of_private.h index ff350c8fa7ac..858e0a5d9a11 100644 --- a/drivers/of/of_private.h +++ b/drivers/of/of_private.h | |||
| @@ -31,6 +31,63 @@ struct alias_prop { | |||
| 31 | char stem[0]; | 31 | char stem[0]; |
| 32 | }; | 32 | }; |
| 33 | 33 | ||
| 34 | extern struct mutex of_aliases_mutex; | 34 | extern struct mutex of_mutex; |
| 35 | extern struct list_head aliases_lookup; | 35 | extern struct list_head aliases_lookup; |
| 36 | extern struct kset *of_kset; | ||
| 37 | |||
| 38 | |||
| 39 | static inline struct device_node *kobj_to_device_node(struct kobject *kobj) | ||
| 40 | { | ||
| 41 | return container_of(kobj, struct device_node, kobj); | ||
| 42 | } | ||
| 43 | |||
| 44 | #if defined(CONFIG_OF_DYNAMIC) | ||
| 45 | extern int of_property_notify(int action, struct device_node *np, | ||
| 46 | struct property *prop, struct property *old_prop); | ||
| 47 | extern void of_node_release(struct kobject *kobj); | ||
| 48 | #else /* CONFIG_OF_DYNAMIC */ | ||
| 49 | static inline int of_property_notify(int action, struct device_node *np, | ||
| 50 | struct property *prop, struct property *old_prop) | ||
| 51 | { | ||
| 52 | return 0; | ||
| 53 | } | ||
| 54 | #endif /* CONFIG_OF_DYNAMIC */ | ||
| 55 | |||
| 56 | /** | ||
| 57 | * General utilities for working with live trees. | ||
| 58 | * | ||
| 59 | * All functions with two leading underscores operate | ||
| 60 | * without taking node references, so you either have to | ||
| 61 | * own the devtree lock or work on detached trees only. | ||
| 62 | */ | ||
| 63 | struct property *__of_prop_dup(const struct property *prop, gfp_t allocflags); | ||
| 64 | struct device_node *__of_node_alloc(const char *full_name, gfp_t allocflags); | ||
| 65 | |||
| 66 | extern const void *__of_get_property(const struct device_node *np, | ||
| 67 | const char *name, int *lenp); | ||
| 68 | extern int __of_add_property(struct device_node *np, struct property *prop); | ||
| 69 | extern int __of_add_property_sysfs(struct device_node *np, | ||
| 70 | struct property *prop); | ||
| 71 | extern int __of_remove_property(struct device_node *np, struct property *prop); | ||
| 72 | extern void __of_remove_property_sysfs(struct device_node *np, | ||
| 73 | struct property *prop); | ||
| 74 | extern int __of_update_property(struct device_node *np, | ||
| 75 | struct property *newprop, struct property **oldprop); | ||
| 76 | extern void __of_update_property_sysfs(struct device_node *np, | ||
| 77 | struct property *newprop, struct property *oldprop); | ||
| 78 | |||
| 79 | extern void __of_attach_node(struct device_node *np); | ||
| 80 | extern int __of_attach_node_sysfs(struct device_node *np); | ||
| 81 | extern void __of_detach_node(struct device_node *np); | ||
| 82 | extern void __of_detach_node_sysfs(struct device_node *np); | ||
| 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 | |||
| 36 | #endif /* _LINUX_OF_PRIVATE_H */ | 93 | #endif /* _LINUX_OF_PRIVATE_H */ |
diff --git a/drivers/of/of_reserved_mem.c b/drivers/of/of_reserved_mem.c index 632aae861375..59fb12e84e6b 100644 --- a/drivers/of/of_reserved_mem.c +++ b/drivers/of/of_reserved_mem.c | |||
| @@ -206,8 +206,16 @@ void __init fdt_init_reserved_mem(void) | |||
| 206 | for (i = 0; i < reserved_mem_count; i++) { | 206 | for (i = 0; i < reserved_mem_count; i++) { |
| 207 | struct reserved_mem *rmem = &reserved_mem[i]; | 207 | struct reserved_mem *rmem = &reserved_mem[i]; |
| 208 | unsigned long node = rmem->fdt_node; | 208 | unsigned long node = rmem->fdt_node; |
| 209 | int len; | ||
| 210 | const __be32 *prop; | ||
| 209 | int err = 0; | 211 | int err = 0; |
| 210 | 212 | ||
| 213 | prop = of_get_flat_dt_prop(node, "phandle", &len); | ||
| 214 | if (!prop) | ||
| 215 | prop = of_get_flat_dt_prop(node, "linux,phandle", &len); | ||
| 216 | if (prop) | ||
| 217 | rmem->phandle = of_read_number(prop, len/4); | ||
| 218 | |||
| 211 | if (rmem->size == 0) | 219 | if (rmem->size == 0) |
| 212 | err = __reserved_mem_alloc_size(node, rmem->name, | 220 | err = __reserved_mem_alloc_size(node, rmem->name, |
| 213 | &rmem->base, &rmem->size); | 221 | &rmem->base, &rmem->size); |
| @@ -215,3 +223,65 @@ void __init fdt_init_reserved_mem(void) | |||
| 215 | __reserved_mem_init_node(rmem); | 223 | __reserved_mem_init_node(rmem); |
| 216 | } | 224 | } |
| 217 | } | 225 | } |
| 226 | |||
| 227 | static inline struct reserved_mem *__find_rmem(struct device_node *node) | ||
| 228 | { | ||
| 229 | unsigned int i; | ||
| 230 | |||
| 231 | if (!node->phandle) | ||
| 232 | return NULL; | ||
| 233 | |||
| 234 | for (i = 0; i < reserved_mem_count; i++) | ||
| 235 | if (reserved_mem[i].phandle == node->phandle) | ||
| 236 | return &reserved_mem[i]; | ||
| 237 | return NULL; | ||
| 238 | } | ||
| 239 | |||
| 240 | /** | ||
| 241 | * of_reserved_mem_device_init() - assign reserved memory region to given device | ||
| 242 | * | ||
| 243 | * This function assign memory region pointed by "memory-region" device tree | ||
| 244 | * property to the given device. | ||
| 245 | */ | ||
| 246 | void of_reserved_mem_device_init(struct device *dev) | ||
| 247 | { | ||
| 248 | struct reserved_mem *rmem; | ||
| 249 | struct device_node *np; | ||
| 250 | |||
| 251 | np = of_parse_phandle(dev->of_node, "memory-region", 0); | ||
| 252 | if (!np) | ||
| 253 | return; | ||
| 254 | |||
| 255 | rmem = __find_rmem(np); | ||
| 256 | of_node_put(np); | ||
| 257 | |||
| 258 | if (!rmem || !rmem->ops || !rmem->ops->device_init) | ||
| 259 | return; | ||
| 260 | |||
| 261 | rmem->ops->device_init(rmem, dev); | ||
| 262 | dev_info(dev, "assigned reserved memory node %s\n", rmem->name); | ||
| 263 | } | ||
| 264 | |||
| 265 | /** | ||
| 266 | * of_reserved_mem_device_release() - release reserved memory device structures | ||
| 267 | * | ||
| 268 | * This function releases structures allocated for memory region handling for | ||
| 269 | * the given device. | ||
| 270 | */ | ||
| 271 | void of_reserved_mem_device_release(struct device *dev) | ||
| 272 | { | ||
| 273 | struct reserved_mem *rmem; | ||
| 274 | struct device_node *np; | ||
| 275 | |||
| 276 | np = of_parse_phandle(dev->of_node, "memory-region", 0); | ||
| 277 | if (!np) | ||
| 278 | return; | ||
| 279 | |||
| 280 | rmem = __find_rmem(np); | ||
| 281 | of_node_put(np); | ||
| 282 | |||
| 283 | if (!rmem || !rmem->ops || !rmem->ops->device_release) | ||
| 284 | return; | ||
| 285 | |||
| 286 | rmem->ops->device_release(rmem, dev); | ||
| 287 | } | ||
diff --git a/drivers/of/platform.c b/drivers/of/platform.c index 500436f9be7f..0197725e033a 100644 --- a/drivers/of/platform.c +++ b/drivers/of/platform.c | |||
| @@ -422,6 +422,7 @@ static int of_platform_bus_create(struct device_node *bus, | |||
| 422 | break; | 422 | break; |
| 423 | } | 423 | } |
| 424 | } | 424 | } |
| 425 | of_node_set_flag(bus, OF_POPULATED_BUS); | ||
| 425 | return rc; | 426 | return rc; |
| 426 | } | 427 | } |
| 427 | 428 | ||
| @@ -508,19 +509,13 @@ EXPORT_SYMBOL_GPL(of_platform_populate); | |||
| 508 | 509 | ||
| 509 | static int of_platform_device_destroy(struct device *dev, void *data) | 510 | static int of_platform_device_destroy(struct device *dev, void *data) |
| 510 | { | 511 | { |
| 511 | bool *children_left = data; | ||
| 512 | |||
| 513 | /* Do not touch devices not populated from the device tree */ | 512 | /* Do not touch devices not populated from the device tree */ |
| 514 | if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED)) { | 513 | if (!dev->of_node || !of_node_check_flag(dev->of_node, OF_POPULATED)) |
| 515 | *children_left = true; | ||
| 516 | return 0; | 514 | return 0; |
| 517 | } | ||
| 518 | 515 | ||
| 519 | /* Recurse, but don't touch this device if it has any children left */ | 516 | /* Recurse for any nodes that were treated as busses */ |
| 520 | if (of_platform_depopulate(dev) != 0) { | 517 | if (of_node_check_flag(dev->of_node, OF_POPULATED_BUS)) |
| 521 | *children_left = true; | 518 | device_for_each_child(dev, NULL, of_platform_device_destroy); |
| 522 | return 0; | ||
| 523 | } | ||
| 524 | 519 | ||
| 525 | if (dev->bus == &platform_bus_type) | 520 | if (dev->bus == &platform_bus_type) |
| 526 | platform_device_unregister(to_platform_device(dev)); | 521 | platform_device_unregister(to_platform_device(dev)); |
| @@ -528,19 +523,15 @@ static int of_platform_device_destroy(struct device *dev, void *data) | |||
| 528 | else if (dev->bus == &amba_bustype) | 523 | else if (dev->bus == &amba_bustype) |
| 529 | amba_device_unregister(to_amba_device(dev)); | 524 | amba_device_unregister(to_amba_device(dev)); |
| 530 | #endif | 525 | #endif |
| 531 | else { | ||
| 532 | *children_left = true; | ||
| 533 | return 0; | ||
| 534 | } | ||
| 535 | 526 | ||
| 536 | of_node_clear_flag(dev->of_node, OF_POPULATED); | 527 | of_node_clear_flag(dev->of_node, OF_POPULATED); |
| 537 | 528 | of_node_clear_flag(dev->of_node, OF_POPULATED_BUS); | |
| 538 | return 0; | 529 | return 0; |
| 539 | } | 530 | } |
| 540 | 531 | ||
| 541 | /** | 532 | /** |
| 542 | * of_platform_depopulate() - Remove devices populated from device tree | 533 | * of_platform_depopulate() - Remove devices populated from device tree |
| 543 | * @parent: device which childred will be removed | 534 | * @parent: device which children will be removed |
| 544 | * | 535 | * |
| 545 | * Complementary to of_platform_populate(), this function removes children | 536 | * Complementary to of_platform_populate(), this function removes children |
| 546 | * of the given device (and, recurrently, their children) that have been | 537 | * of the given device (and, recurrently, their children) that have been |
| @@ -550,14 +541,9 @@ static int of_platform_device_destroy(struct device *dev, void *data) | |||
| 550 | * Returns 0 when all children devices have been removed or | 541 | * Returns 0 when all children devices have been removed or |
| 551 | * -EBUSY when some children remained. | 542 | * -EBUSY when some children remained. |
| 552 | */ | 543 | */ |
| 553 | int of_platform_depopulate(struct device *parent) | 544 | void of_platform_depopulate(struct device *parent) |
| 554 | { | 545 | { |
| 555 | bool children_left = false; | 546 | device_for_each_child(parent, NULL, of_platform_device_destroy); |
| 556 | |||
| 557 | device_for_each_child(parent, &children_left, | ||
| 558 | of_platform_device_destroy); | ||
| 559 | |||
| 560 | return children_left ? -EBUSY : 0; | ||
| 561 | } | 547 | } |
| 562 | EXPORT_SYMBOL_GPL(of_platform_depopulate); | 548 | EXPORT_SYMBOL_GPL(of_platform_depopulate); |
| 563 | 549 | ||
diff --git a/drivers/of/selftest.c b/drivers/of/selftest.c index 077314eebb95..d41002667833 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <linux/errno.h> | 9 | #include <linux/errno.h> |
| 10 | #include <linux/module.h> | 10 | #include <linux/module.h> |
| 11 | #include <linux/of.h> | 11 | #include <linux/of.h> |
| 12 | #include <linux/of_fdt.h> | ||
| 12 | #include <linux/of_irq.h> | 13 | #include <linux/of_irq.h> |
| 13 | #include <linux/of_platform.h> | 14 | #include <linux/of_platform.h> |
| 14 | #include <linux/list.h> | 15 | #include <linux/list.h> |
| @@ -16,11 +17,17 @@ | |||
| 16 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 17 | #include <linux/device.h> | 18 | #include <linux/device.h> |
| 18 | 19 | ||
| 20 | #include "of_private.h" | ||
| 21 | |||
| 19 | static struct selftest_results { | 22 | static struct selftest_results { |
| 20 | int passed; | 23 | int passed; |
| 21 | int failed; | 24 | int failed; |
| 22 | } selftest_results; | 25 | } selftest_results; |
| 23 | 26 | ||
| 27 | #define NO_OF_NODES 2 | ||
| 28 | static struct device_node *nodes[NO_OF_NODES]; | ||
| 29 | static int last_node_index; | ||
| 30 | |||
| 24 | #define selftest(result, fmt, ...) { \ | 31 | #define selftest(result, fmt, ...) { \ |
| 25 | if (!(result)) { \ | 32 | if (!(result)) { \ |
| 26 | selftest_results.failed++; \ | 33 | selftest_results.failed++; \ |
| @@ -266,6 +273,81 @@ static void __init of_selftest_property_match_string(void) | |||
| 266 | selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); | 273 | selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); |
| 267 | } | 274 | } |
| 268 | 275 | ||
| 276 | #define propcmp(p1, p2) (((p1)->length == (p2)->length) && \ | ||
| 277 | (p1)->value && (p2)->value && \ | ||
| 278 | !memcmp((p1)->value, (p2)->value, (p1)->length) && \ | ||
| 279 | !strcmp((p1)->name, (p2)->name)) | ||
| 280 | static void __init of_selftest_property_copy(void) | ||
| 281 | { | ||
| 282 | #ifdef CONFIG_OF_DYNAMIC | ||
| 283 | struct property p1 = { .name = "p1", .length = 0, .value = "" }; | ||
| 284 | struct property p2 = { .name = "p2", .length = 5, .value = "abcd" }; | ||
| 285 | struct property *new; | ||
| 286 | |||
| 287 | new = __of_prop_dup(&p1, GFP_KERNEL); | ||
| 288 | selftest(new && propcmp(&p1, new), "empty property didn't copy correctly\n"); | ||
| 289 | kfree(new->value); | ||
| 290 | kfree(new->name); | ||
| 291 | kfree(new); | ||
| 292 | |||
| 293 | new = __of_prop_dup(&p2, GFP_KERNEL); | ||
| 294 | selftest(new && propcmp(&p2, new), "non-empty property didn't copy correctly\n"); | ||
| 295 | kfree(new->value); | ||
| 296 | kfree(new->name); | ||
| 297 | kfree(new); | ||
| 298 | #endif | ||
| 299 | } | ||
| 300 | |||
| 301 | static void __init of_selftest_changeset(void) | ||
| 302 | { | ||
| 303 | #ifdef CONFIG_OF_DYNAMIC | ||
| 304 | struct property *ppadd, padd = { .name = "prop-add", .length = 0, .value = "" }; | ||
| 305 | struct property *ppupdate, pupdate = { .name = "prop-update", .length = 5, .value = "abcd" }; | ||
| 306 | struct property *ppremove; | ||
| 307 | struct device_node *n1, *n2, *n21, *nremove, *parent; | ||
| 308 | struct of_changeset chgset; | ||
| 309 | |||
| 310 | of_changeset_init(&chgset); | ||
| 311 | n1 = __of_node_alloc("/testcase-data/changeset/n1", GFP_KERNEL); | ||
| 312 | selftest(n1, "testcase setup failure\n"); | ||
| 313 | n2 = __of_node_alloc("/testcase-data/changeset/n2", GFP_KERNEL); | ||
| 314 | selftest(n2, "testcase setup failure\n"); | ||
| 315 | n21 = __of_node_alloc("/testcase-data/changeset/n2/n21", GFP_KERNEL); | ||
| 316 | selftest(n21, "testcase setup failure %p\n", n21); | ||
| 317 | nremove = of_find_node_by_path("/testcase-data/changeset/node-remove"); | ||
| 318 | selftest(nremove, "testcase setup failure\n"); | ||
| 319 | ppadd = __of_prop_dup(&padd, GFP_KERNEL); | ||
| 320 | selftest(ppadd, "testcase setup failure\n"); | ||
| 321 | ppupdate = __of_prop_dup(&pupdate, GFP_KERNEL); | ||
| 322 | selftest(ppupdate, "testcase setup failure\n"); | ||
| 323 | parent = nremove->parent; | ||
| 324 | n1->parent = parent; | ||
| 325 | n2->parent = parent; | ||
| 326 | n21->parent = n2; | ||
| 327 | n2->child = n21; | ||
| 328 | ppremove = of_find_property(parent, "prop-remove", NULL); | ||
| 329 | selftest(ppremove, "failed to find removal prop"); | ||
| 330 | |||
| 331 | of_changeset_init(&chgset); | ||
| 332 | selftest(!of_changeset_attach_node(&chgset, n1), "fail attach n1\n"); | ||
| 333 | selftest(!of_changeset_attach_node(&chgset, n2), "fail attach n2\n"); | ||
| 334 | selftest(!of_changeset_detach_node(&chgset, nremove), "fail remove node\n"); | ||
| 335 | selftest(!of_changeset_attach_node(&chgset, n21), "fail attach n21\n"); | ||
| 336 | selftest(!of_changeset_add_property(&chgset, parent, ppadd), "fail add prop\n"); | ||
| 337 | selftest(!of_changeset_update_property(&chgset, parent, ppupdate), "fail update prop\n"); | ||
| 338 | selftest(!of_changeset_remove_property(&chgset, parent, ppremove), "fail remove prop\n"); | ||
| 339 | mutex_lock(&of_mutex); | ||
| 340 | selftest(!of_changeset_apply(&chgset), "apply failed\n"); | ||
| 341 | mutex_unlock(&of_mutex); | ||
| 342 | |||
| 343 | mutex_lock(&of_mutex); | ||
| 344 | selftest(!of_changeset_revert(&chgset), "revert failed\n"); | ||
| 345 | mutex_unlock(&of_mutex); | ||
| 346 | |||
| 347 | of_changeset_destroy(&chgset); | ||
| 348 | #endif | ||
| 349 | } | ||
| 350 | |||
| 269 | static void __init of_selftest_parse_interrupts(void) | 351 | static void __init of_selftest_parse_interrupts(void) |
| 270 | { | 352 | { |
| 271 | struct device_node *np; | 353 | struct device_node *np; |
| @@ -517,9 +599,156 @@ static void __init of_selftest_platform_populate(void) | |||
| 517 | } | 599 | } |
| 518 | } | 600 | } |
| 519 | 601 | ||
| 602 | /** | ||
| 603 | * update_node_properties - adds the properties | ||
| 604 | * of np into dup node (present in live tree) and | ||
| 605 | * updates parent of children of np to dup. | ||
| 606 | * | ||
| 607 | * @np: node already present in live tree | ||
| 608 | * @dup: node present in live tree to be updated | ||
| 609 | */ | ||
| 610 | static void update_node_properties(struct device_node *np, | ||
| 611 | struct device_node *dup) | ||
| 612 | { | ||
| 613 | struct property *prop; | ||
| 614 | struct device_node *child; | ||
| 615 | |||
| 616 | for_each_property_of_node(np, prop) | ||
| 617 | of_add_property(dup, prop); | ||
| 618 | |||
| 619 | for_each_child_of_node(np, child) | ||
| 620 | child->parent = dup; | ||
| 621 | } | ||
| 622 | |||
| 623 | /** | ||
| 624 | * attach_node_and_children - attaches nodes | ||
| 625 | * and its children to live tree | ||
| 626 | * | ||
| 627 | * @np: Node to attach to live tree | ||
| 628 | */ | ||
| 629 | static int attach_node_and_children(struct device_node *np) | ||
| 630 | { | ||
| 631 | struct device_node *next, *root = np, *dup; | ||
| 632 | |||
| 633 | if (!np) { | ||
| 634 | pr_warn("%s: No tree to attach; not running tests\n", | ||
| 635 | __func__); | ||
| 636 | return -ENODATA; | ||
| 637 | } | ||
| 638 | |||
| 639 | |||
| 640 | /* skip root node */ | ||
| 641 | np = np->child; | ||
| 642 | /* storing a copy in temporary node */ | ||
| 643 | dup = np; | ||
| 644 | |||
| 645 | while (dup) { | ||
| 646 | nodes[last_node_index++] = dup; | ||
| 647 | dup = dup->sibling; | ||
| 648 | } | ||
| 649 | dup = NULL; | ||
| 650 | |||
| 651 | while (np) { | ||
| 652 | next = np->allnext; | ||
| 653 | dup = of_find_node_by_path(np->full_name); | ||
| 654 | if (dup) | ||
| 655 | update_node_properties(np, dup); | ||
| 656 | else { | ||
| 657 | np->child = NULL; | ||
| 658 | if (np->parent == root) | ||
| 659 | np->parent = of_allnodes; | ||
| 660 | of_attach_node(np); | ||
| 661 | } | ||
| 662 | np = next; | ||
| 663 | } | ||
| 664 | |||
| 665 | return 0; | ||
| 666 | } | ||
| 667 | |||
| 668 | /** | ||
| 669 | * selftest_data_add - Reads, copies data from | ||
| 670 | * linked tree and attaches it to the live tree | ||
| 671 | */ | ||
| 672 | static int __init selftest_data_add(void) | ||
| 673 | { | ||
| 674 | void *selftest_data; | ||
| 675 | struct device_node *selftest_data_node; | ||
| 676 | extern uint8_t __dtb_testcases_begin[]; | ||
| 677 | extern uint8_t __dtb_testcases_end[]; | ||
| 678 | const int size = __dtb_testcases_end - __dtb_testcases_begin; | ||
| 679 | |||
| 680 | if (!size || !of_allnodes) { | ||
| 681 | pr_warn("%s: No testcase data to attach; not running tests\n", | ||
| 682 | __func__); | ||
| 683 | return -ENODATA; | ||
| 684 | } | ||
| 685 | |||
| 686 | /* creating copy */ | ||
| 687 | selftest_data = kmemdup(__dtb_testcases_begin, size, GFP_KERNEL); | ||
| 688 | |||
| 689 | if (!selftest_data) { | ||
| 690 | pr_warn("%s: Failed to allocate memory for selftest_data; " | ||
| 691 | "not running tests\n", __func__); | ||
| 692 | return -ENOMEM; | ||
| 693 | } | ||
| 694 | of_fdt_unflatten_tree(selftest_data, &selftest_data_node); | ||
| 695 | |||
| 696 | /* attach the sub-tree to live tree */ | ||
| 697 | return attach_node_and_children(selftest_data_node); | ||
| 698 | } | ||
| 699 | |||
| 700 | /** | ||
| 701 | * detach_node_and_children - detaches node | ||
| 702 | * and its children from live tree | ||
| 703 | * | ||
| 704 | * @np: Node to detach from live tree | ||
| 705 | */ | ||
| 706 | static void detach_node_and_children(struct device_node *np) | ||
| 707 | { | ||
| 708 | while (np->child) | ||
| 709 | detach_node_and_children(np->child); | ||
| 710 | |||
| 711 | while (np->sibling) | ||
| 712 | detach_node_and_children(np->sibling); | ||
| 713 | |||
| 714 | of_detach_node(np); | ||
| 715 | } | ||
| 716 | |||
| 717 | /** | ||
| 718 | * selftest_data_remove - removes the selftest data | ||
| 719 | * nodes from the live tree | ||
| 720 | */ | ||
| 721 | static void selftest_data_remove(void) | ||
| 722 | { | ||
| 723 | struct device_node *np; | ||
| 724 | struct property *prop; | ||
| 725 | |||
| 726 | while (last_node_index >= 0) { | ||
| 727 | if (nodes[last_node_index]) { | ||
| 728 | np = of_find_node_by_path(nodes[last_node_index]->full_name); | ||
| 729 | if (strcmp(np->full_name, "/aliases") != 0) { | ||
| 730 | detach_node_and_children(np->child); | ||
| 731 | of_detach_node(np); | ||
| 732 | } else { | ||
| 733 | for_each_property_of_node(np, prop) { | ||
| 734 | if (strcmp(prop->name, "testcase-alias") == 0) | ||
| 735 | of_remove_property(np, prop); | ||
| 736 | } | ||
| 737 | } | ||
| 738 | } | ||
| 739 | last_node_index--; | ||
| 740 | } | ||
| 741 | } | ||
| 742 | |||
| 520 | static int __init of_selftest(void) | 743 | static int __init of_selftest(void) |
| 521 | { | 744 | { |
| 522 | struct device_node *np; | 745 | struct device_node *np; |
| 746 | int res; | ||
| 747 | |||
| 748 | /* adding data for selftest */ | ||
| 749 | res = selftest_data_add(); | ||
| 750 | if (res) | ||
| 751 | return res; | ||
| 523 | 752 | ||
| 524 | np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); | 753 | np = of_find_node_by_path("/testcase-data/phandle-tests/consumer-a"); |
| 525 | if (!np) { | 754 | if (!np) { |
| @@ -533,12 +762,18 @@ static int __init of_selftest(void) | |||
| 533 | of_selftest_dynamic(); | 762 | of_selftest_dynamic(); |
| 534 | of_selftest_parse_phandle_with_args(); | 763 | of_selftest_parse_phandle_with_args(); |
| 535 | of_selftest_property_match_string(); | 764 | of_selftest_property_match_string(); |
| 765 | of_selftest_property_copy(); | ||
| 766 | of_selftest_changeset(); | ||
| 536 | of_selftest_parse_interrupts(); | 767 | of_selftest_parse_interrupts(); |
| 537 | of_selftest_parse_interrupts_extended(); | 768 | of_selftest_parse_interrupts_extended(); |
| 538 | of_selftest_match_node(); | 769 | of_selftest_match_node(); |
| 539 | of_selftest_platform_populate(); | 770 | of_selftest_platform_populate(); |
| 540 | pr_info("end of selftest - %i passed, %i failed\n", | 771 | pr_info("end of selftest - %i passed, %i failed\n", |
| 541 | selftest_results.passed, selftest_results.failed); | 772 | selftest_results.passed, selftest_results.failed); |
| 773 | |||
| 774 | /* removing selftest data from live tree */ | ||
| 775 | selftest_data_remove(); | ||
| 776 | |||
| 542 | return 0; | 777 | return 0; |
| 543 | } | 778 | } |
| 544 | late_initcall(of_selftest); | 779 | late_initcall(of_selftest); |
diff --git a/drivers/of/testcase-data/testcases.dts b/drivers/of/testcase-data/testcases.dts new file mode 100644 index 000000000000..219ef9324e9c --- /dev/null +++ b/drivers/of/testcase-data/testcases.dts | |||
| @@ -0,0 +1,15 @@ | |||
| 1 | /dts-v1/; | ||
| 2 | / { | ||
| 3 | testcase-data { | ||
| 4 | changeset { | ||
| 5 | prop-update = "hello"; | ||
| 6 | prop-remove = "world"; | ||
| 7 | node-remove { | ||
| 8 | }; | ||
| 9 | }; | ||
| 10 | }; | ||
| 11 | }; | ||
| 12 | #include "tests-phandle.dtsi" | ||
| 13 | #include "tests-interrupts.dtsi" | ||
| 14 | #include "tests-match.dtsi" | ||
| 15 | #include "tests-platform.dtsi" | ||
diff --git a/drivers/of/testcase-data/testcases.dtsi b/drivers/of/testcase-data/testcases.dtsi deleted file mode 100644 index 6d8d980ac858..000000000000 --- a/drivers/of/testcase-data/testcases.dtsi +++ /dev/null | |||
| @@ -1,4 +0,0 @@ | |||
| 1 | #include "tests-phandle.dtsi" | ||
| 2 | #include "tests-interrupts.dtsi" | ||
| 3 | #include "tests-match.dtsi" | ||
| 4 | #include "tests-platform.dtsi" | ||
