diff options
| author | Grant Likely <grant.likely@linaro.org> | 2014-08-11 09:06:23 -0400 |
|---|---|---|
| committer | Grant Likely <grant.likely@linaro.org> | 2014-08-11 09:06:23 -0400 |
| commit | 663d3f7c2e5e1b018a4c53277ccfde40329d98ca (patch) | |
| tree | a3afcc2d8fe682bdcc4c2e39b47ab3987b38c69a | |
| parent | b775e642bf958a02210ac4d4edd1a1b7067c49fa (diff) | |
| parent | b6ae5dc54b0a5c542d06d46b9083ceb70bf7e083 (diff) | |
Merge branch 'devicetree/next-overlay' into devicetree/next
Conflicts:
drivers/of/testcase-data/testcases.dts
| -rw-r--r-- | Documentation/devicetree/changesets.txt | 40 | ||||
| -rw-r--r-- | arch/powerpc/kernel/prom.c | 70 | ||||
| -rw-r--r-- | arch/powerpc/platforms/pseries/hotplug-memory.c | 2 | ||||
| -rw-r--r-- | drivers/crypto/nx/nx-842.c | 30 | ||||
| -rw-r--r-- | drivers/of/Makefile | 1 | ||||
| -rw-r--r-- | drivers/of/base.c | 423 | ||||
| -rw-r--r-- | drivers/of/device.c | 4 | ||||
| -rw-r--r-- | drivers/of/dynamic.c | 660 | ||||
| -rw-r--r-- | drivers/of/of_private.h | 59 | ||||
| -rw-r--r-- | drivers/of/platform.c | 32 | ||||
| -rw-r--r-- | drivers/of/selftest.c | 79 | ||||
| -rw-r--r-- | drivers/of/testcase-data/testcases.dts | 10 | ||||
| -rw-r--r-- | include/linux/of.h | 80 | ||||
| -rw-r--r-- | include/linux/of_platform.h | 7 |
14 files changed, 1054 insertions, 443 deletions
diff --git a/Documentation/devicetree/changesets.txt b/Documentation/devicetree/changesets.txt new file mode 100644 index 000000000000..935ba5acc34e --- /dev/null +++ b/Documentation/devicetree/changesets.txt | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | A DT changeset is a method which allows one to apply changes | ||
| 2 | in the live tree in such a way that either the full set of changes | ||
| 3 | will be applied, or none of them will be. If an error occurs partway | ||
| 4 | through applying the changeset, then the tree will be rolled back to the | ||
| 5 | previous state. A changeset can also be removed after it has been | ||
| 6 | applied. | ||
| 7 | |||
| 8 | When a changeset is applied, all of the changes get applied to the tree | ||
| 9 | at once before emitting OF_RECONFIG notifiers. This is so that the | ||
| 10 | receiver sees a complete and consistent state of the tree when it | ||
| 11 | receives the notifier. | ||
| 12 | |||
| 13 | The sequence of a changeset is as follows. | ||
| 14 | |||
| 15 | 1. of_changeset_init() - initializes a changeset | ||
| 16 | |||
| 17 | 2. A number of DT tree change calls, of_changeset_attach_node(), | ||
| 18 | of_changeset_detach_node(), of_changeset_add_property(), | ||
| 19 | of_changeset_remove_property, of_changeset_update_property() to prepare | ||
| 20 | a set of changes. No changes to the active tree are made at this point. | ||
| 21 | All the change operations are recorded in the of_changeset 'entries' | ||
| 22 | list. | ||
| 23 | |||
| 24 | 3. mutex_lock(of_mutex) - starts a changeset; The global of_mutex | ||
| 25 | ensures there can only be one editor at a time. | ||
| 26 | |||
| 27 | 4. of_changeset_apply() - Apply the changes to the tree. Either the | ||
| 28 | entire changeset will get applied, or if there is an error the tree will | ||
| 29 | be restored to the previous state | ||
| 30 | |||
| 31 | 5. mutex_unlock(of_mutex) - All operations complete, release the mutex | ||
| 32 | |||
| 33 | If a successfully applied changeset needs to be removed, it can be done | ||
| 34 | with the following sequence. | ||
| 35 | |||
| 36 | 1. mutex_lock(of_mutex) | ||
| 37 | |||
| 38 | 2. of_changeset_revert() | ||
| 39 | |||
| 40 | 3. mutex_unlock(of_mutex) | ||
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index b694b0730971..9e8d8a880d6f 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
| @@ -821,76 +821,6 @@ int cpu_to_chip_id(int cpu) | |||
| 821 | } | 821 | } |
| 822 | EXPORT_SYMBOL(cpu_to_chip_id); | 822 | EXPORT_SYMBOL(cpu_to_chip_id); |
| 823 | 823 | ||
| 824 | #ifdef CONFIG_PPC_PSERIES | ||
| 825 | /* | ||
| 826 | * Fix up the uninitialized fields in a new device node: | ||
| 827 | * name, type and pci-specific fields | ||
| 828 | */ | ||
| 829 | |||
| 830 | static int of_finish_dynamic_node(struct device_node *node) | ||
| 831 | { | ||
| 832 | struct device_node *parent = of_get_parent(node); | ||
| 833 | int err = 0; | ||
| 834 | const phandle *ibm_phandle; | ||
| 835 | |||
| 836 | node->name = of_get_property(node, "name", NULL); | ||
| 837 | node->type = of_get_property(node, "device_type", NULL); | ||
| 838 | |||
| 839 | if (!node->name) | ||
| 840 | node->name = "<NULL>"; | ||
| 841 | if (!node->type) | ||
| 842 | node->type = "<NULL>"; | ||
| 843 | |||
| 844 | if (!parent) { | ||
| 845 | err = -ENODEV; | ||
| 846 | goto out; | ||
| 847 | } | ||
| 848 | |||
| 849 | /* We don't support that function on PowerMac, at least | ||
| 850 | * not yet | ||
| 851 | */ | ||
| 852 | if (machine_is(powermac)) | ||
| 853 | return -ENODEV; | ||
| 854 | |||
| 855 | /* fix up new node's phandle field */ | ||
| 856 | if ((ibm_phandle = of_get_property(node, "ibm,phandle", NULL))) | ||
| 857 | node->phandle = *ibm_phandle; | ||
| 858 | |||
| 859 | out: | ||
| 860 | of_node_put(parent); | ||
| 861 | return err; | ||
| 862 | } | ||
| 863 | |||
| 864 | static int prom_reconfig_notifier(struct notifier_block *nb, | ||
| 865 | unsigned long action, void *node) | ||
| 866 | { | ||
| 867 | int err; | ||
| 868 | |||
| 869 | switch (action) { | ||
| 870 | case OF_RECONFIG_ATTACH_NODE: | ||
| 871 | err = of_finish_dynamic_node(node); | ||
| 872 | if (err < 0) | ||
| 873 | printk(KERN_ERR "finish_node returned %d\n", err); | ||
| 874 | break; | ||
| 875 | default: | ||
| 876 | err = 0; | ||
| 877 | break; | ||
| 878 | } | ||
| 879 | return notifier_from_errno(err); | ||
| 880 | } | ||
| 881 | |||
| 882 | static struct notifier_block prom_reconfig_nb = { | ||
| 883 | .notifier_call = prom_reconfig_notifier, | ||
| 884 | .priority = 10, /* This one needs to run first */ | ||
| 885 | }; | ||
| 886 | |||
| 887 | static int __init prom_reconfig_setup(void) | ||
| 888 | { | ||
| 889 | return of_reconfig_notifier_register(&prom_reconfig_nb); | ||
| 890 | } | ||
| 891 | __initcall(prom_reconfig_setup); | ||
| 892 | #endif | ||
| 893 | |||
| 894 | bool arch_match_cpu_phys_id(int cpu, u64 phys_id) | 824 | bool arch_match_cpu_phys_id(int cpu, u64 phys_id) |
| 895 | { | 825 | { |
| 896 | return (int)phys_id == get_hard_smp_processor_id(cpu); | 826 | return (int)phys_id == get_hard_smp_processor_id(cpu); |
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index 7995135170a3..ac01e188faef 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c | |||
| @@ -194,7 +194,7 @@ static int pseries_update_drconf_memory(struct of_prop_reconfig *pr) | |||
| 194 | if (!memblock_size) | 194 | if (!memblock_size) |
| 195 | return -EINVAL; | 195 | return -EINVAL; |
| 196 | 196 | ||
| 197 | p = (u32 *)of_get_property(pr->dn, "ibm,dynamic-memory", NULL); | 197 | p = (u32 *) pr->old_prop->value; |
| 198 | if (!p) | 198 | if (!p) |
| 199 | return -EINVAL; | 199 | return -EINVAL; |
| 200 | 200 | ||
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 502edf0a2933..c897c3a5ee17 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c | |||
| @@ -936,28 +936,14 @@ static int nx842_OF_upd(struct property *new_prop) | |||
| 936 | goto error_out; | 936 | goto error_out; |
| 937 | } | 937 | } |
| 938 | 938 | ||
| 939 | /* Set ptr to new property if provided */ | 939 | /* |
| 940 | if (new_prop) { | 940 | * If this is a property update, there are only certain properties that |
| 941 | /* Single property */ | 941 | * we care about. Bail if it isn't in the below list |
| 942 | if (!strncmp(new_prop->name, "status", new_prop->length)) { | 942 | */ |
| 943 | status = new_prop; | 943 | if (new_prop && (strncmp(new_prop->name, "status", new_prop->length) || |
| 944 | 944 | strncmp(new_prop->name, "ibm,max-sg-len", new_prop->length) || | |
| 945 | } else if (!strncmp(new_prop->name, "ibm,max-sg-len", | 945 | strncmp(new_prop->name, "ibm,max-sync-cop", new_prop->length))) |
| 946 | new_prop->length)) { | 946 | goto out; |
| 947 | maxsglen = new_prop; | ||
| 948 | |||
| 949 | } else if (!strncmp(new_prop->name, "ibm,max-sync-cop", | ||
| 950 | new_prop->length)) { | ||
| 951 | maxsyncop = new_prop; | ||
| 952 | |||
| 953 | } else { | ||
| 954 | /* | ||
| 955 | * Skip the update, the property being updated | ||
| 956 | * has no impact. | ||
| 957 | */ | ||
| 958 | goto out; | ||
| 959 | } | ||
| 960 | } | ||
| 961 | 947 | ||
| 962 | /* Perform property updates */ | 948 | /* Perform property updates */ |
| 963 | ret = nx842_OF_upd_status(new_devdata, status); | 949 | ret = nx842_OF_upd_status(new_devdata, status); |
diff --git a/drivers/of/Makefile b/drivers/of/Makefile index b9e753b56964..2b6a7b129d10 100644 --- a/drivers/of/Makefile +++ b/drivers/of/Makefile | |||
| @@ -1,4 +1,5 @@ | |||
| 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 |
diff --git a/drivers/of/base.c b/drivers/of/base.c index e4f95ba0a3eb..d8574adf0d62 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
| @@ -38,13 +38,15 @@ struct device_node *of_chosen; | |||
| 38 | struct device_node *of_aliases; | 38 | struct device_node *of_aliases; |
| 39 | struct device_node *of_stdout; | 39 | struct device_node *of_stdout; |
| 40 | 40 | ||
| 41 | static struct kset *of_kset; | 41 | struct kset *of_kset; |
| 42 | 42 | ||
| 43 | /* | 43 | /* |
| 44 | * 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. |
| 45 | * 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. | ||
| 46 | */ | 48 | */ |
| 47 | DEFINE_MUTEX(of_aliases_mutex); | 49 | DEFINE_MUTEX(of_mutex); |
| 48 | 50 | ||
| 49 | /* use when traversing tree through the allnext, child, sibling, | 51 | /* use when traversing tree through the allnext, child, sibling, |
| 50 | * or parent members of struct device_node. | 52 | * or parent members of struct device_node. |
| @@ -90,79 +92,7 @@ int __weak of_node_to_nid(struct device_node *np) | |||
| 90 | } | 92 | } |
| 91 | #endif | 93 | #endif |
| 92 | 94 | ||
| 93 | #if defined(CONFIG_OF_DYNAMIC) | 95 | #ifndef CONFIG_OF_DYNAMIC |
| 94 | /** | ||
| 95 | * of_node_get - Increment refcount of a node | ||
| 96 | * @node: Node to inc refcount, NULL is supported to | ||
| 97 | * simplify writing of callers | ||
| 98 | * | ||
| 99 | * Returns node. | ||
| 100 | */ | ||
| 101 | struct device_node *of_node_get(struct device_node *node) | ||
| 102 | { | ||
| 103 | if (node) | ||
| 104 | kobject_get(&node->kobj); | ||
| 105 | return node; | ||
| 106 | } | ||
| 107 | EXPORT_SYMBOL(of_node_get); | ||
| 108 | |||
| 109 | static inline struct device_node *kobj_to_device_node(struct kobject *kobj) | ||
| 110 | { | ||
| 111 | return container_of(kobj, struct device_node, kobj); | ||
| 112 | } | ||
| 113 | |||
| 114 | /** | ||
| 115 | * of_node_release - release a dynamically allocated node | ||
| 116 | * @kref: kref element of the node to be released | ||
| 117 | * | ||
| 118 | * In of_node_put() this function is passed to kref_put() | ||
| 119 | * as the destructor. | ||
| 120 | */ | ||
| 121 | static void of_node_release(struct kobject *kobj) | ||
| 122 | { | ||
| 123 | struct device_node *node = kobj_to_device_node(kobj); | ||
| 124 | struct property *prop = node->properties; | ||
| 125 | |||
| 126 | /* We should never be releasing nodes that haven't been detached. */ | ||
| 127 | if (!of_node_check_flag(node, OF_DETACHED)) { | ||
| 128 | pr_err("ERROR: Bad of_node_put() on %s\n", node->full_name); | ||
| 129 | dump_stack(); | ||
| 130 | return; | ||
| 131 | } | ||
| 132 | |||
| 133 | if (!of_node_check_flag(node, OF_DYNAMIC)) | ||
| 134 | return; | ||
| 135 | |||
| 136 | while (prop) { | ||
| 137 | struct property *next = prop->next; | ||
| 138 | kfree(prop->name); | ||
| 139 | kfree(prop->value); | ||
| 140 | kfree(prop); | ||
| 141 | prop = next; | ||
| 142 | |||
| 143 | if (!prop) { | ||
| 144 | prop = node->deadprops; | ||
| 145 | node->deadprops = NULL; | ||
| 146 | } | ||
| 147 | } | ||
| 148 | kfree(node->full_name); | ||
| 149 | kfree(node->data); | ||
| 150 | kfree(node); | ||
| 151 | } | ||
| 152 | |||
| 153 | /** | ||
| 154 | * of_node_put - Decrement refcount of a node | ||
| 155 | * @node: Node to dec refcount, NULL is supported to | ||
| 156 | * simplify writing of callers | ||
| 157 | * | ||
| 158 | */ | ||
| 159 | void of_node_put(struct device_node *node) | ||
| 160 | { | ||
| 161 | if (node) | ||
| 162 | kobject_put(&node->kobj); | ||
| 163 | } | ||
| 164 | EXPORT_SYMBOL(of_node_put); | ||
| 165 | #else | ||
| 166 | static void of_node_release(struct kobject *kobj) | 96 | static void of_node_release(struct kobject *kobj) |
| 167 | { | 97 | { |
| 168 | /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ | 98 | /* Without CONFIG_OF_DYNAMIC, no nodes gets freed */ |
| @@ -201,13 +131,16 @@ static const char *safe_name(struct kobject *kobj, const char *orig_name) | |||
| 201 | return name; | 131 | return name; |
| 202 | } | 132 | } |
| 203 | 133 | ||
| 204 | 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) |
| 205 | { | 135 | { |
| 206 | int rc; | 136 | int rc; |
| 207 | 137 | ||
| 208 | /* Important: Don't leak passwords */ | 138 | /* Important: Don't leak passwords */ |
| 209 | bool secure = strncmp(pp->name, "security-", 9) == 0; | 139 | bool secure = strncmp(pp->name, "security-", 9) == 0; |
| 210 | 140 | ||
| 141 | if (!of_kset || !of_node_is_attached(np)) | ||
| 142 | return 0; | ||
| 143 | |||
| 211 | sysfs_bin_attr_init(&pp->attr); | 144 | sysfs_bin_attr_init(&pp->attr); |
| 212 | pp->attr.attr.name = safe_name(&np->kobj, pp->name); | 145 | pp->attr.attr.name = safe_name(&np->kobj, pp->name); |
| 213 | pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; | 146 | pp->attr.attr.mode = secure ? S_IRUSR : S_IRUGO; |
| @@ -219,12 +152,15 @@ static int __of_add_property_sysfs(struct device_node *np, struct property *pp) | |||
| 219 | return rc; | 152 | return rc; |
| 220 | } | 153 | } |
| 221 | 154 | ||
| 222 | static int __of_node_add(struct device_node *np) | 155 | int __of_attach_node_sysfs(struct device_node *np) |
| 223 | { | 156 | { |
| 224 | const char *name; | 157 | const char *name; |
| 225 | struct property *pp; | 158 | struct property *pp; |
| 226 | int rc; | 159 | int rc; |
| 227 | 160 | ||
| 161 | if (!of_kset) | ||
| 162 | return 0; | ||
| 163 | |||
| 228 | np->kobj.kset = of_kset; | 164 | np->kobj.kset = of_kset; |
| 229 | if (!np->parent) { | 165 | if (!np->parent) { |
| 230 | /* Nodes without parents are new top level trees */ | 166 | /* Nodes without parents are new top level trees */ |
| @@ -246,59 +182,20 @@ static int __of_node_add(struct device_node *np) | |||
| 246 | return 0; | 182 | return 0; |
| 247 | } | 183 | } |
| 248 | 184 | ||
| 249 | int of_node_add(struct device_node *np) | ||
| 250 | { | ||
| 251 | int rc = 0; | ||
| 252 | |||
| 253 | BUG_ON(!of_node_is_initialized(np)); | ||
| 254 | |||
| 255 | /* | ||
| 256 | * Grab the mutex here so that in a race condition between of_init() and | ||
| 257 | * of_node_add(), node addition will still be consistent. | ||
| 258 | */ | ||
| 259 | mutex_lock(&of_aliases_mutex); | ||
| 260 | if (of_kset) | ||
| 261 | rc = __of_node_add(np); | ||
| 262 | else | ||
| 263 | /* This scenario may be perfectly valid, but report it anyway */ | ||
| 264 | pr_info("of_node_add(%s) before of_init()\n", np->full_name); | ||
| 265 | mutex_unlock(&of_aliases_mutex); | ||
| 266 | return rc; | ||
| 267 | } | ||
| 268 | |||
| 269 | #if defined(CONFIG_OF_DYNAMIC) | ||
| 270 | static void of_node_remove(struct device_node *np) | ||
| 271 | { | ||
| 272 | struct property *pp; | ||
| 273 | |||
| 274 | BUG_ON(!of_node_is_initialized(np)); | ||
| 275 | |||
| 276 | /* only remove properties if on sysfs */ | ||
| 277 | if (of_node_is_attached(np)) { | ||
| 278 | for_each_property_of_node(np, pp) | ||
| 279 | sysfs_remove_bin_file(&np->kobj, &pp->attr); | ||
| 280 | kobject_del(&np->kobj); | ||
| 281 | } | ||
| 282 | |||
| 283 | /* finally remove the kobj_init ref */ | ||
| 284 | of_node_put(np); | ||
| 285 | } | ||
| 286 | #endif | ||
| 287 | |||
| 288 | static int __init of_init(void) | 185 | static int __init of_init(void) |
| 289 | { | 186 | { |
| 290 | struct device_node *np; | 187 | struct device_node *np; |
| 291 | 188 | ||
| 292 | /* Create the kset, and register existing nodes */ | 189 | /* Create the kset, and register existing nodes */ |
| 293 | mutex_lock(&of_aliases_mutex); | 190 | mutex_lock(&of_mutex); |
| 294 | of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); | 191 | of_kset = kset_create_and_add("devicetree", NULL, firmware_kobj); |
| 295 | if (!of_kset) { | 192 | if (!of_kset) { |
| 296 | mutex_unlock(&of_aliases_mutex); | 193 | mutex_unlock(&of_mutex); |
| 297 | return -ENOMEM; | 194 | return -ENOMEM; |
| 298 | } | 195 | } |
| 299 | for_each_of_allnodes(np) | 196 | for_each_of_allnodes(np) |
| 300 | __of_node_add(np); | 197 | __of_attach_node_sysfs(np); |
| 301 | mutex_unlock(&of_aliases_mutex); | 198 | mutex_unlock(&of_mutex); |
| 302 | 199 | ||
| 303 | /* Symlink in /proc as required by userspace ABI */ | 200 | /* Symlink in /proc as required by userspace ABI */ |
| 304 | if (of_allnodes) | 201 | if (of_allnodes) |
| @@ -370,8 +267,8 @@ EXPORT_SYMBOL(of_find_all_nodes); | |||
| 370 | * Find a property with a given name for a given node | 267 | * Find a property with a given name for a given node |
| 371 | * and return the value. | 268 | * and return the value. |
| 372 | */ | 269 | */ |
| 373 | static const void *__of_get_property(const struct device_node *np, | 270 | const void *__of_get_property(const struct device_node *np, |
| 374 | const char *name, int *lenp) | 271 | const char *name, int *lenp) |
| 375 | { | 272 | { |
| 376 | struct property *pp = __of_find_property(np, name, lenp); | 273 | struct property *pp = __of_find_property(np, name, lenp); |
| 377 | 274 | ||
| @@ -1749,32 +1646,10 @@ int of_count_phandle_with_args(const struct device_node *np, const char *list_na | |||
| 1749 | } | 1646 | } |
| 1750 | EXPORT_SYMBOL(of_count_phandle_with_args); | 1647 | EXPORT_SYMBOL(of_count_phandle_with_args); |
| 1751 | 1648 | ||
| 1752 | #if defined(CONFIG_OF_DYNAMIC) | ||
| 1753 | static int of_property_notify(int action, struct device_node *np, | ||
| 1754 | struct property *prop) | ||
| 1755 | { | ||
| 1756 | struct of_prop_reconfig pr; | ||
| 1757 | |||
| 1758 | /* only call notifiers if the node is attached */ | ||
| 1759 | if (!of_node_is_attached(np)) | ||
| 1760 | return 0; | ||
| 1761 | |||
| 1762 | pr.dn = np; | ||
| 1763 | pr.prop = prop; | ||
| 1764 | return of_reconfig_notify(action, &pr); | ||
| 1765 | } | ||
| 1766 | #else | ||
| 1767 | static int of_property_notify(int action, struct device_node *np, | ||
| 1768 | struct property *prop) | ||
| 1769 | { | ||
| 1770 | return 0; | ||
| 1771 | } | ||
| 1772 | #endif | ||
| 1773 | |||
| 1774 | /** | 1649 | /** |
| 1775 | * __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 |
| 1776 | */ | 1651 | */ |
| 1777 | static int __of_add_property(struct device_node *np, struct property *prop) | 1652 | int __of_add_property(struct device_node *np, struct property *prop) |
| 1778 | { | 1653 | { |
| 1779 | struct property **next; | 1654 | struct property **next; |
| 1780 | 1655 | ||
| @@ -1800,22 +1675,49 @@ int of_add_property(struct device_node *np, struct property *prop) | |||
| 1800 | unsigned long flags; | 1675 | unsigned long flags; |
| 1801 | int rc; | 1676 | int rc; |
| 1802 | 1677 | ||
| 1803 | rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop); | 1678 | mutex_lock(&of_mutex); |
| 1804 | if (rc) | ||
| 1805 | return rc; | ||
| 1806 | 1679 | ||
| 1807 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1680 | raw_spin_lock_irqsave(&devtree_lock, flags); |
| 1808 | rc = __of_add_property(np, prop); | 1681 | rc = __of_add_property(np, prop); |
| 1809 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1682 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 1810 | if (rc) | ||
| 1811 | return rc; | ||
| 1812 | 1683 | ||
| 1813 | if (of_node_is_attached(np)) | 1684 | if (!rc) |
| 1814 | __of_add_property_sysfs(np, prop); | 1685 | __of_add_property_sysfs(np, prop); |
| 1815 | 1686 | ||
| 1687 | mutex_unlock(&of_mutex); | ||
| 1688 | |||
| 1689 | if (!rc) | ||
| 1690 | of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop, NULL); | ||
| 1691 | |||
| 1816 | return rc; | 1692 | return rc; |
| 1817 | } | 1693 | } |
| 1818 | 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 | |||
| 1819 | /** | 1721 | /** |
| 1820 | * of_remove_property - Remove a property from a node. | 1722 | * of_remove_property - Remove a property from a node. |
| 1821 | * | 1723 | * |
| @@ -1826,211 +1728,98 @@ int of_add_property(struct device_node *np, struct property *prop) | |||
| 1826 | */ | 1728 | */ |
| 1827 | int of_remove_property(struct device_node *np, struct property *prop) | 1729 | int of_remove_property(struct device_node *np, struct property *prop) |
| 1828 | { | 1730 | { |
| 1829 | struct property **next; | ||
| 1830 | unsigned long flags; | 1731 | unsigned long flags; |
| 1831 | int found = 0; | ||
| 1832 | int rc; | 1732 | int rc; |
| 1833 | 1733 | ||
| 1834 | rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop); | 1734 | mutex_lock(&of_mutex); |
| 1835 | if (rc) | ||
| 1836 | return rc; | ||
| 1837 | 1735 | ||
| 1838 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1736 | raw_spin_lock_irqsave(&devtree_lock, flags); |
| 1839 | next = &np->properties; | 1737 | rc = __of_remove_property(np, prop); |
| 1840 | while (*next) { | ||
| 1841 | if (*next == prop) { | ||
| 1842 | /* found the node */ | ||
| 1843 | *next = prop->next; | ||
| 1844 | prop->next = np->deadprops; | ||
| 1845 | np->deadprops = prop; | ||
| 1846 | found = 1; | ||
| 1847 | break; | ||
| 1848 | } | ||
| 1849 | next = &(*next)->next; | ||
| 1850 | } | ||
| 1851 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1738 | raw_spin_unlock_irqrestore(&devtree_lock, flags); |
| 1852 | 1739 | ||
| 1853 | if (!found) | 1740 | if (!rc) |
| 1854 | return -ENODEV; | 1741 | __of_remove_property_sysfs(np, prop); |
| 1855 | 1742 | ||
| 1856 | /* at early boot, bail hear and defer setup to of_init() */ | 1743 | mutex_unlock(&of_mutex); |
| 1857 | if (!of_kset) | ||
| 1858 | return 0; | ||
| 1859 | 1744 | ||
| 1860 | sysfs_remove_bin_file(&np->kobj, &prop->attr); | 1745 | if (!rc) |
| 1746 | of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop, NULL); | ||
| 1861 | 1747 | ||
| 1862 | return 0; | 1748 | return rc; |
| 1863 | } | 1749 | } |
| 1864 | 1750 | ||
| 1865 | /* | 1751 | int __of_update_property(struct device_node *np, struct property *newprop, |
| 1866 | * of_update_property - Update a property in a node, if the property does | 1752 | struct property **oldpropp) |
| 1867 | * not exist, add it. | ||
| 1868 | * | ||
| 1869 | * Note that we don't actually remove it, since we have given out | ||
| 1870 | * who-knows-how-many pointers to the data using get-property. | ||
| 1871 | * Instead we just move the property to the "dead properties" list, | ||
| 1872 | * and add the new property to the property list | ||
| 1873 | */ | ||
| 1874 | int of_update_property(struct device_node *np, struct property *newprop) | ||
| 1875 | { | 1753 | { |
| 1876 | struct property **next, *oldprop; | 1754 | struct property **next, *oldprop; |
| 1877 | unsigned long flags; | ||
| 1878 | int rc; | ||
| 1879 | |||
| 1880 | rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); | ||
| 1881 | if (rc) | ||
| 1882 | return rc; | ||
| 1883 | 1755 | ||
| 1884 | if (!newprop->name) | 1756 | for (next = &np->properties; *next; next = &(*next)->next) { |
| 1885 | return -EINVAL; | 1757 | if (of_prop_cmp((*next)->name, newprop->name) == 0) |
| 1758 | break; | ||
| 1759 | } | ||
| 1760 | *oldpropp = oldprop = *next; | ||
| 1886 | 1761 | ||
| 1887 | raw_spin_lock_irqsave(&devtree_lock, flags); | 1762 | if (oldprop) { |
| 1888 | next = &np->properties; | ||
| 1889 | oldprop = __of_find_property(np, newprop->name, NULL); | ||
| 1890 | if (!oldprop) { | ||
| 1891 | /* add the new node */ | ||
| 1892 | rc = __of_add_property(np, newprop); | ||
| 1893 | } else while (*next) { | ||
| 1894 | /* replace the node */ | 1763 | /* replace the node */ |
| 1895 | if (*next == oldprop) { | 1764 | newprop->next = oldprop->next; |
| 1896 | newprop->next = oldprop->next; | 1765 | *next = newprop; |
| 1897 | *next = newprop; | 1766 | oldprop->next = np->deadprops; |
| 1898 | oldprop->next = np->deadprops; | 1767 | np->deadprops = oldprop; |
| 1899 | np->deadprops = oldprop; | 1768 | } else { |
| 1900 | break; | 1769 | /* new node */ |
| 1901 | } | 1770 | newprop->next = NULL; |
| 1902 | next = &(*next)->next; | 1771 | *next = newprop; |
| 1903 | } | 1772 | } |
| 1904 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 1905 | if (rc) | ||
| 1906 | return rc; | ||
| 1907 | 1773 | ||
| 1774 | return 0; | ||
| 1775 | } | ||
| 1776 | |||
| 1777 | void __of_update_property_sysfs(struct device_node *np, struct property *newprop, | ||
| 1778 | struct property *oldprop) | ||
| 1779 | { | ||
| 1908 | /* At early boot, bail out and defer setup to of_init() */ | 1780 | /* At early boot, bail out and defer setup to of_init() */ |
| 1909 | if (!of_kset) | 1781 | if (!of_kset) |
| 1910 | return 0; | 1782 | return; |
| 1911 | 1783 | ||
| 1912 | /* Update the sysfs attribute */ | ||
| 1913 | if (oldprop) | 1784 | if (oldprop) |
| 1914 | sysfs_remove_bin_file(&np->kobj, &oldprop->attr); | 1785 | sysfs_remove_bin_file(&np->kobj, &oldprop->attr); |
| 1915 | __of_add_property_sysfs(np, newprop); | 1786 | __of_add_property_sysfs(np, newprop); |
| 1916 | |||
| 1917 | return 0; | ||
| 1918 | } | 1787 | } |
| 1919 | 1788 | ||
| 1920 | #if defined(CONFIG_OF_DYNAMIC) | ||
| 1921 | /* | 1789 | /* |
| 1922 | * Support for dynamic device trees. | 1790 | * of_update_property - Update a property in a node, if the property does |
| 1791 | * not exist, add it. | ||
| 1923 | * | 1792 | * |
| 1924 | * 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 |
| 1925 | * The routines in this section support adding, removing and changing | 1794 | * who-knows-how-many pointers to the data using get-property. |
| 1926 | * device tree nodes. | 1795 | * Instead we just move the property to the "dead properties" list, |
| 1927 | */ | 1796 | * and add the new property to the property list |
| 1928 | |||
| 1929 | static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain); | ||
| 1930 | |||
| 1931 | int of_reconfig_notifier_register(struct notifier_block *nb) | ||
| 1932 | { | ||
| 1933 | return blocking_notifier_chain_register(&of_reconfig_chain, nb); | ||
| 1934 | } | ||
| 1935 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_register); | ||
| 1936 | |||
| 1937 | int of_reconfig_notifier_unregister(struct notifier_block *nb) | ||
| 1938 | { | ||
| 1939 | return blocking_notifier_chain_unregister(&of_reconfig_chain, nb); | ||
| 1940 | } | ||
| 1941 | EXPORT_SYMBOL_GPL(of_reconfig_notifier_unregister); | ||
| 1942 | |||
| 1943 | int of_reconfig_notify(unsigned long action, void *p) | ||
| 1944 | { | ||
| 1945 | int rc; | ||
| 1946 | |||
| 1947 | rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p); | ||
| 1948 | return notifier_to_errno(rc); | ||
| 1949 | } | ||
| 1950 | |||
| 1951 | /** | ||
| 1952 | * of_attach_node - Plug a device node into the tree and global list. | ||
| 1953 | */ | 1797 | */ |
| 1954 | int of_attach_node(struct device_node *np) | 1798 | int of_update_property(struct device_node *np, struct property *newprop) |
| 1955 | { | 1799 | { |
| 1800 | struct property *oldprop; | ||
| 1956 | unsigned long flags; | 1801 | unsigned long flags; |
| 1957 | int rc; | 1802 | int rc; |
| 1958 | 1803 | ||
| 1959 | rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); | 1804 | if (!newprop->name) |
| 1960 | if (rc) | 1805 | return -EINVAL; |
| 1961 | return rc; | ||
| 1962 | |||
| 1963 | raw_spin_lock_irqsave(&devtree_lock, flags); | ||
| 1964 | np->sibling = np->parent->child; | ||
| 1965 | np->allnext = np->parent->allnext; | ||
| 1966 | np->parent->allnext = np; | ||
| 1967 | np->parent->child = np; | ||
| 1968 | of_node_clear_flag(np, OF_DETACHED); | ||
| 1969 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 1970 | |||
| 1971 | of_node_add(np); | ||
| 1972 | return 0; | ||
| 1973 | } | ||
| 1974 | |||
| 1975 | /** | ||
| 1976 | * of_detach_node - "Unplug" a node from the device tree. | ||
| 1977 | * | ||
| 1978 | * The caller must hold a reference to the node. The memory associated with | ||
| 1979 | * the node is not freed until its refcount goes to zero. | ||
| 1980 | */ | ||
| 1981 | int of_detach_node(struct device_node *np) | ||
| 1982 | { | ||
| 1983 | struct device_node *parent; | ||
| 1984 | unsigned long flags; | ||
| 1985 | int rc = 0; | ||
| 1986 | 1806 | ||
| 1987 | rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); | 1807 | mutex_lock(&of_mutex); |
| 1988 | if (rc) | ||
| 1989 | return rc; | ||
| 1990 | 1808 | ||
| 1991 | 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); | ||
| 1992 | 1812 | ||
| 1993 | if (of_node_check_flag(np, OF_DETACHED)) { | 1813 | if (!rc) |
| 1994 | /* someone already detached it */ | 1814 | __of_update_property_sysfs(np, newprop, oldprop); |
| 1995 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 1996 | return rc; | ||
| 1997 | } | ||
| 1998 | |||
| 1999 | parent = np->parent; | ||
| 2000 | if (!parent) { | ||
| 2001 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | ||
| 2002 | return rc; | ||
| 2003 | } | ||
| 2004 | |||
| 2005 | if (of_allnodes == np) | ||
| 2006 | of_allnodes = np->allnext; | ||
| 2007 | else { | ||
| 2008 | struct device_node *prev; | ||
| 2009 | for (prev = of_allnodes; | ||
| 2010 | prev->allnext != np; | ||
| 2011 | prev = prev->allnext) | ||
| 2012 | ; | ||
| 2013 | prev->allnext = np->allnext; | ||
| 2014 | } | ||
| 2015 | 1815 | ||
| 2016 | if (parent->child == np) | 1816 | mutex_unlock(&of_mutex); |
| 2017 | parent->child = np->sibling; | ||
| 2018 | else { | ||
| 2019 | struct device_node *prevsib; | ||
| 2020 | for (prevsib = np->parent->child; | ||
| 2021 | prevsib->sibling != np; | ||
| 2022 | prevsib = prevsib->sibling) | ||
| 2023 | ; | ||
| 2024 | prevsib->sibling = np->sibling; | ||
| 2025 | } | ||
| 2026 | 1817 | ||
| 2027 | of_node_set_flag(np, OF_DETACHED); | 1818 | if (!rc) |
| 2028 | raw_spin_unlock_irqrestore(&devtree_lock, flags); | 1819 | of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop, oldprop); |
| 2029 | 1820 | ||
| 2030 | of_node_remove(np); | ||
| 2031 | return rc; | 1821 | return rc; |
| 2032 | } | 1822 | } |
| 2033 | #endif /* defined(CONFIG_OF_DYNAMIC) */ | ||
| 2034 | 1823 | ||
| 2035 | 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, |
| 2036 | int id, const char *stem, int stem_len) | 1825 | int id, const char *stem, int stem_len) |
| @@ -2126,7 +1915,7 @@ int of_alias_get_id(struct device_node *np, const char *stem) | |||
| 2126 | struct alias_prop *app; | 1915 | struct alias_prop *app; |
| 2127 | int id = -ENODEV; | 1916 | int id = -ENODEV; |
| 2128 | 1917 | ||
| 2129 | mutex_lock(&of_aliases_mutex); | 1918 | mutex_lock(&of_mutex); |
| 2130 | list_for_each_entry(app, &aliases_lookup, link) { | 1919 | list_for_each_entry(app, &aliases_lookup, link) { |
| 2131 | if (strcmp(app->stem, stem) != 0) | 1920 | if (strcmp(app->stem, stem) != 0) |
| 2132 | continue; | 1921 | continue; |
| @@ -2136,7 +1925,7 @@ int of_alias_get_id(struct device_node *np, const char *stem) | |||
| 2136 | break; | 1925 | break; |
| 2137 | } | 1926 | } |
| 2138 | } | 1927 | } |
| 2139 | mutex_unlock(&of_aliases_mutex); | 1928 | mutex_unlock(&of_mutex); |
| 2140 | 1929 | ||
| 2141 | return id; | 1930 | return id; |
| 2142 | } | 1931 | } |
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/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/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 df599db1554c..d41002667833 100644 --- a/drivers/of/selftest.c +++ b/drivers/of/selftest.c | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
| 18 | #include <linux/device.h> | 18 | #include <linux/device.h> |
| 19 | 19 | ||
| 20 | #include "of_private.h" | ||
| 21 | |||
| 20 | static struct selftest_results { | 22 | static struct selftest_results { |
| 21 | int passed; | 23 | int passed; |
| 22 | int failed; | 24 | int failed; |
| @@ -271,6 +273,81 @@ static void __init of_selftest_property_match_string(void) | |||
| 271 | selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); | 273 | selftest(rc == -EILSEQ, "unterminated string; rc=%i", rc); |
| 272 | } | 274 | } |
| 273 | 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 | |||
| 274 | static void __init of_selftest_parse_interrupts(void) | 351 | static void __init of_selftest_parse_interrupts(void) |
| 275 | { | 352 | { |
| 276 | struct device_node *np; | 353 | struct device_node *np; |
| @@ -685,6 +762,8 @@ static int __init of_selftest(void) | |||
| 685 | of_selftest_dynamic(); | 762 | of_selftest_dynamic(); |
| 686 | of_selftest_parse_phandle_with_args(); | 763 | of_selftest_parse_phandle_with_args(); |
| 687 | of_selftest_property_match_string(); | 764 | of_selftest_property_match_string(); |
| 765 | of_selftest_property_copy(); | ||
| 766 | of_selftest_changeset(); | ||
| 688 | of_selftest_parse_interrupts(); | 767 | of_selftest_parse_interrupts(); |
| 689 | of_selftest_parse_interrupts_extended(); | 768 | of_selftest_parse_interrupts_extended(); |
| 690 | of_selftest_match_node(); | 769 | of_selftest_match_node(); |
diff --git a/drivers/of/testcase-data/testcases.dts b/drivers/of/testcase-data/testcases.dts index 8e7568ee3175..219ef9324e9c 100644 --- a/drivers/of/testcase-data/testcases.dts +++ b/drivers/of/testcase-data/testcases.dts | |||
| @@ -1,4 +1,14 @@ | |||
| 1 | /dts-v1/; | 1 | /dts-v1/; |
| 2 | / { | ||
| 3 | testcase-data { | ||
| 4 | changeset { | ||
| 5 | prop-update = "hello"; | ||
| 6 | prop-remove = "world"; | ||
| 7 | node-remove { | ||
| 8 | }; | ||
| 9 | }; | ||
| 10 | }; | ||
| 11 | }; | ||
| 2 | #include "tests-phandle.dtsi" | 12 | #include "tests-phandle.dtsi" |
| 3 | #include "tests-interrupts.dtsi" | 13 | #include "tests-interrupts.dtsi" |
| 4 | #include "tests-match.dtsi" | 14 | #include "tests-match.dtsi" |
diff --git a/include/linux/of.h b/include/linux/of.h index f0d256273c83..6c4363b8ddc3 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
| @@ -74,8 +74,6 @@ struct of_phandle_args { | |||
| 74 | uint32_t args[MAX_PHANDLE_ARGS]; | 74 | uint32_t args[MAX_PHANDLE_ARGS]; |
| 75 | }; | 75 | }; |
| 76 | 76 | ||
| 77 | extern int of_node_add(struct device_node *node); | ||
| 78 | |||
| 79 | /* initialize a node */ | 77 | /* initialize a node */ |
| 80 | extern struct kobj_type of_node_ktype; | 78 | extern struct kobj_type of_node_ktype; |
| 81 | static inline void of_node_init(struct device_node *node) | 79 | static inline void of_node_init(struct device_node *node) |
| @@ -205,6 +203,7 @@ static inline unsigned long of_read_ulong(const __be32 *cell, int size) | |||
| 205 | #define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ | 203 | #define OF_DYNAMIC 1 /* node and properties were allocated via kmalloc */ |
| 206 | #define OF_DETACHED 2 /* node has been detached from the device tree */ | 204 | #define OF_DETACHED 2 /* node has been detached from the device tree */ |
| 207 | #define OF_POPULATED 3 /* device already created for the node */ | 205 | #define OF_POPULATED 3 /* device already created for the node */ |
| 206 | #define OF_POPULATED_BUS 4 /* of_platform_populate recursed to children of this node */ | ||
| 208 | 207 | ||
| 209 | #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) | 208 | #define OF_IS_DYNAMIC(x) test_bit(OF_DYNAMIC, &x->_flags) |
| 210 | #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) | 209 | #define OF_MARK_DYNAMIC(x) set_bit(OF_DYNAMIC, &x->_flags) |
| @@ -323,6 +322,7 @@ extern int of_update_property(struct device_node *np, struct property *newprop); | |||
| 323 | struct of_prop_reconfig { | 322 | struct of_prop_reconfig { |
| 324 | struct device_node *dn; | 323 | struct device_node *dn; |
| 325 | struct property *prop; | 324 | struct property *prop; |
| 325 | struct property *old_prop; | ||
| 326 | }; | 326 | }; |
| 327 | 327 | ||
| 328 | extern int of_reconfig_notifier_register(struct notifier_block *); | 328 | extern int of_reconfig_notifier_register(struct notifier_block *); |
| @@ -787,4 +787,80 @@ typedef void (*of_init_fn_1)(struct device_node *); | |||
| 787 | #define OF_DECLARE_2(table, name, compat, fn) \ | 787 | #define OF_DECLARE_2(table, name, compat, fn) \ |
| 788 | _OF_DECLARE(table, name, compat, fn, of_init_fn_2) | 788 | _OF_DECLARE(table, name, compat, fn, of_init_fn_2) |
| 789 | 789 | ||
| 790 | /** | ||
| 791 | * struct of_changeset_entry - Holds a changeset entry | ||
| 792 | * | ||
| 793 | * @node: list_head for the log list | ||
| 794 | * @action: notifier action | ||
| 795 | * @np: pointer to the device node affected | ||
| 796 | * @prop: pointer to the property affected | ||
| 797 | * @old_prop: hold a pointer to the original property | ||
| 798 | * | ||
| 799 | * Every modification of the device tree during a changeset | ||
| 800 | * is held in a list of of_changeset_entry structures. | ||
| 801 | * That way we can recover from a partial application, or we can | ||
| 802 | * revert the changeset | ||
| 803 | */ | ||
| 804 | struct of_changeset_entry { | ||
| 805 | struct list_head node; | ||
| 806 | unsigned long action; | ||
| 807 | struct device_node *np; | ||
| 808 | struct property *prop; | ||
| 809 | struct property *old_prop; | ||
| 810 | }; | ||
| 811 | |||
| 812 | /** | ||
| 813 | * struct of_changeset - changeset tracker structure | ||
| 814 | * | ||
| 815 | * @entries: list_head for the changeset entries | ||
| 816 | * | ||
| 817 | * changesets are a convenient way to apply bulk changes to the | ||
| 818 | * live tree. In case of an error, changes are rolled-back. | ||
| 819 | * changesets live on after initial application, and if not | ||
| 820 | * destroyed after use, they can be reverted in one single call. | ||
| 821 | */ | ||
| 822 | struct of_changeset { | ||
| 823 | struct list_head entries; | ||
| 824 | }; | ||
| 825 | |||
| 826 | #ifdef CONFIG_OF_DYNAMIC | ||
| 827 | extern void of_changeset_init(struct of_changeset *ocs); | ||
| 828 | extern void of_changeset_destroy(struct of_changeset *ocs); | ||
| 829 | extern int of_changeset_apply(struct of_changeset *ocs); | ||
| 830 | extern int of_changeset_revert(struct of_changeset *ocs); | ||
| 831 | extern int of_changeset_action(struct of_changeset *ocs, | ||
| 832 | unsigned long action, struct device_node *np, | ||
| 833 | struct property *prop); | ||
| 834 | |||
| 835 | static inline int of_changeset_attach_node(struct of_changeset *ocs, | ||
| 836 | struct device_node *np) | ||
| 837 | { | ||
| 838 | return of_changeset_action(ocs, OF_RECONFIG_ATTACH_NODE, np, NULL); | ||
| 839 | } | ||
| 840 | |||
| 841 | static inline int of_changeset_detach_node(struct of_changeset *ocs, | ||
| 842 | struct device_node *np) | ||
| 843 | { | ||
| 844 | return of_changeset_action(ocs, OF_RECONFIG_DETACH_NODE, np, NULL); | ||
| 845 | } | ||
| 846 | |||
| 847 | static inline int of_changeset_add_property(struct of_changeset *ocs, | ||
| 848 | struct device_node *np, struct property *prop) | ||
| 849 | { | ||
| 850 | return of_changeset_action(ocs, OF_RECONFIG_ADD_PROPERTY, np, prop); | ||
| 851 | } | ||
| 852 | |||
| 853 | static inline int of_changeset_remove_property(struct of_changeset *ocs, | ||
| 854 | struct device_node *np, struct property *prop) | ||
| 855 | { | ||
| 856 | return of_changeset_action(ocs, OF_RECONFIG_REMOVE_PROPERTY, np, prop); | ||
| 857 | } | ||
| 858 | |||
| 859 | static inline int of_changeset_update_property(struct of_changeset *ocs, | ||
| 860 | struct device_node *np, struct property *prop) | ||
| 861 | { | ||
| 862 | return of_changeset_action(ocs, OF_RECONFIG_UPDATE_PROPERTY, np, prop); | ||
| 863 | } | ||
| 864 | #endif | ||
| 865 | |||
| 790 | #endif /* _LINUX_OF_H */ | 866 | #endif /* _LINUX_OF_H */ |
diff --git a/include/linux/of_platform.h b/include/linux/of_platform.h index d96e1badbee0..c2b0627a2317 100644 --- a/include/linux/of_platform.h +++ b/include/linux/of_platform.h | |||
| @@ -72,7 +72,7 @@ extern int of_platform_populate(struct device_node *root, | |||
| 72 | const struct of_device_id *matches, | 72 | const struct of_device_id *matches, |
| 73 | const struct of_dev_auxdata *lookup, | 73 | const struct of_dev_auxdata *lookup, |
| 74 | struct device *parent); | 74 | struct device *parent); |
| 75 | extern int of_platform_depopulate(struct device *parent); | 75 | extern void of_platform_depopulate(struct device *parent); |
| 76 | #else | 76 | #else |
| 77 | static inline int of_platform_populate(struct device_node *root, | 77 | static inline int of_platform_populate(struct device_node *root, |
| 78 | const struct of_device_id *matches, | 78 | const struct of_device_id *matches, |
| @@ -81,10 +81,7 @@ static inline int of_platform_populate(struct device_node *root, | |||
| 81 | { | 81 | { |
| 82 | return -ENODEV; | 82 | return -ENODEV; |
| 83 | } | 83 | } |
| 84 | static inline int of_platform_depopulate(struct device *parent) | 84 | static inline void of_platform_depopulate(struct device *parent) { } |
| 85 | { | ||
| 86 | return -ENODEV; | ||
| 87 | } | ||
| 88 | #endif | 85 | #endif |
| 89 | 86 | ||
| 90 | #endif /* _LINUX_OF_PLATFORM_H */ | 87 | #endif /* _LINUX_OF_PLATFORM_H */ |
