Commit 1cf3d8b3d24cd383ddfd5442c83ec5c355ffc2f7

Authored by Nathan Fontenot
Committed by Benjamin Herrenschmidt
1 parent f594972083

powerpc+of: Add of node/property notification chain for adds and removes

This patch moves the notification chain for updates to the device tree
from the powerpc/pseries code to the base OF code. This makes this
functionality available to all architectures.

Additionally the notification chain is updated to allow notifications
for property add/remove/update. To make this work a pointer to a new
struct (of_prop_reconfig) is passed to the routines in the notification chain.
The of_prop_reconfig property contains a pointer to the node containing the
property and a pointer to the property itself. In the case of property
updates, the property pointer refers to the new property.

Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
Acked-by: Rob Herring <rob.herring@calxeda.com>
Acked-by: Grant Likely <grant.likely@secretlab.ca>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>

Showing 12 changed files with 163 additions and 154 deletions Side-by-side Diff

arch/powerpc/include/asm/pSeries_reconfig.h
... ... @@ -2,43 +2,11 @@
2 2 #define _PPC64_PSERIES_RECONFIG_H
3 3 #ifdef __KERNEL__
4 4  
5   -#include <linux/notifier.h>
6   -
7   -/*
8   - * Use this API if your code needs to know about OF device nodes being
9   - * added or removed on pSeries systems.
10   - */
11   -
12   -#define PSERIES_RECONFIG_ADD 0x0001
13   -#define PSERIES_RECONFIG_REMOVE 0x0002
14   -#define PSERIES_DRCONF_MEM_ADD 0x0003
15   -#define PSERIES_DRCONF_MEM_REMOVE 0x0004
16   -#define PSERIES_UPDATE_PROPERTY 0x0005
17   -
18   -/**
19   - * pSeries_reconfig_notify - Notifier value structure for OFDT property updates
20   - *
21   - * @node: Device tree node which owns the property being updated
22   - * @property: Updated property
23   - */
24   -struct pSeries_reconfig_prop_update {
25   - struct device_node *node;
26   - struct property *property;
27   -};
28   -
29 5 #ifdef CONFIG_PPC_PSERIES
30   -extern int pSeries_reconfig_notifier_register(struct notifier_block *);
31   -extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
32   -extern int pSeries_reconfig_notify(unsigned long action, void *p);
33 6 /* Not the best place to put this, will be fixed when we move some
34 7 * of the rtas suspend-me stuff to pseries */
35 8 extern void pSeries_coalesce_init(void);
36 9 #else /* !CONFIG_PPC_PSERIES */
37   -static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
38   -{
39   - return 0;
40   -}
41   -static inline void pSeries_reconfig_notifier_unregister(struct notifier_block *nb) { }
42 10 static inline void pSeries_coalesce_init(void) { }
43 11 #endif /* CONFIG_PPC_PSERIES */
44 12  
arch/powerpc/kernel/prom.c
... ... @@ -32,6 +32,7 @@
32 32 #include <linux/debugfs.h>
33 33 #include <linux/irq.h>
34 34 #include <linux/memblock.h>
  35 +#include <linux/of.h>
35 36  
36 37 #include <asm/prom.h>
37 38 #include <asm/rtas.h>
... ... @@ -49,7 +50,6 @@
49 50 #include <asm/btext.h>
50 51 #include <asm/sections.h>
51 52 #include <asm/machdep.h>
52   -#include <asm/pSeries_reconfig.h>
53 53 #include <asm/pci-bridge.h>
54 54 #include <asm/kexec.h>
55 55 #include <asm/opal.h>
... ... @@ -802,7 +802,7 @@
802 802 int err;
803 803  
804 804 switch (action) {
805   - case PSERIES_RECONFIG_ADD:
  805 + case OF_RECONFIG_ATTACH_NODE:
806 806 err = of_finish_dynamic_node(node);
807 807 if (err < 0)
808 808 printk(KERN_ERR "finish_node returned %d\n", err);
... ... @@ -821,7 +821,7 @@
821 821  
822 822 static int __init prom_reconfig_setup(void)
823 823 {
824   - return pSeries_reconfig_notifier_register(&prom_reconfig_nb);
  824 + return of_reconfig_notifier_register(&prom_reconfig_nb);
825 825 }
826 826 __initcall(prom_reconfig_setup);
827 827 #endif
arch/powerpc/platforms/pseries/dlpar.c
... ... @@ -16,13 +16,13 @@
16 16 #include <linux/spinlock.h>
17 17 #include <linux/cpu.h>
18 18 #include <linux/slab.h>
  19 +#include <linux/of.h>
19 20 #include "offline_states.h"
20 21  
21 22 #include <asm/prom.h>
22 23 #include <asm/machdep.h>
23 24 #include <asm/uaccess.h>
24 25 #include <asm/rtas.h>
25   -#include <asm/pSeries_reconfig.h>
26 26  
27 27 struct cc_workarea {
28 28 u32 drc_index;
29 29  
30 30  
31 31  
... ... @@ -262,24 +262,26 @@
262 262 if (!dn->parent)
263 263 return -ENOMEM;
264 264  
265   - rc = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, dn);
  265 + rc = of_attach_node(dn);
266 266 if (rc) {
267 267 printk(KERN_ERR "Failed to add device node %s\n",
268 268 dn->full_name);
269 269 return rc;
270 270 }
271 271  
272   - of_attach_node(dn);
273 272 of_node_put(dn->parent);
274 273 return 0;
275 274 }
276 275  
277 276 int dlpar_detach_node(struct device_node *dn)
278 277 {
279   - pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, dn);
280   - of_detach_node(dn);
281   - of_node_put(dn); /* Must decrement the refcount */
  278 + int rc;
282 279  
  280 + rc = of_detach_node(dn);
  281 + if (rc)
  282 + return rc;
  283 +
  284 + of_node_put(dn); /* Must decrement the refcount */
283 285 return 0;
284 286 }
285 287  
arch/powerpc/platforms/pseries/hotplug-cpu.c
... ... @@ -23,12 +23,12 @@
23 23 #include <linux/delay.h>
24 24 #include <linux/sched.h> /* for idle_task_exit */
25 25 #include <linux/cpu.h>
  26 +#include <linux/of.h>
26 27 #include <asm/prom.h>
27 28 #include <asm/rtas.h>
28 29 #include <asm/firmware.h>
29 30 #include <asm/machdep.h>
30 31 #include <asm/vdso_datapage.h>
31   -#include <asm/pSeries_reconfig.h>
32 32 #include <asm/xics.h>
33 33 #include "plpar_wrappers.h"
34 34 #include "offline_states.h"
35 35  
... ... @@ -333,10 +333,10 @@
333 333 int err = 0;
334 334  
335 335 switch (action) {
336   - case PSERIES_RECONFIG_ADD:
  336 + case OF_RECONFIG_ATTACH_NODE:
337 337 err = pseries_add_processor(node);
338 338 break;
339   - case PSERIES_RECONFIG_REMOVE:
  339 + case OF_RECONFIG_DETACH_NODE:
340 340 pseries_remove_processor(node);
341 341 break;
342 342 }
... ... @@ -399,7 +399,7 @@
399 399  
400 400 /* Processors can be added/removed only on LPAR */
401 401 if (firmware_has_feature(FW_FEATURE_LPAR)) {
402   - pSeries_reconfig_notifier_register(&pseries_smp_nb);
  402 + of_reconfig_notifier_register(&pseries_smp_nb);
403 403 cpu_maps_update_begin();
404 404 if (cede_offline_enabled && parse_cede_parameters() == 0) {
405 405 default_offline_state = CPU_STATE_INACTIVE;
arch/powerpc/platforms/pseries/hotplug-memory.c
... ... @@ -16,7 +16,6 @@
16 16  
17 17 #include <asm/firmware.h>
18 18 #include <asm/machdep.h>
19   -#include <asm/pSeries_reconfig.h>
20 19 #include <asm/sparsemem.h>
21 20  
22 21 static unsigned long get_memblock_size(void)
23 22  
24 23  
25 24  
26 25  
27 26  
28 27  
29 28  
30 29  
... ... @@ -187,42 +186,69 @@
187 186 return (ret < 0) ? -EINVAL : 0;
188 187 }
189 188  
190   -static int pseries_drconf_memory(unsigned long *base, unsigned int action)
  189 +static int pseries_update_drconf_memory(struct of_prop_reconfig *pr)
191 190 {
  191 + struct of_drconf_cell *new_drmem, *old_drmem;
192 192 unsigned long memblock_size;
193   - int rc;
  193 + u32 entries;
  194 + u32 *p;
  195 + int i, rc = -EINVAL;
194 196  
195 197 memblock_size = get_memblock_size();
196 198 if (!memblock_size)
197 199 return -EINVAL;
198 200  
199   - if (action == PSERIES_DRCONF_MEM_ADD) {
200   - rc = memblock_add(*base, memblock_size);
201   - rc = (rc < 0) ? -EINVAL : 0;
202   - } else if (action == PSERIES_DRCONF_MEM_REMOVE) {
203   - rc = pseries_remove_memblock(*base, memblock_size);
204   - } else {
205   - rc = -EINVAL;
  201 + p = (u32 *)of_get_property(pr->dn, "ibm,dynamic-memory", NULL);
  202 + if (!p)
  203 + return -EINVAL;
  204 +
  205 + /* The first int of the property is the number of lmb's described
  206 + * by the property. This is followed by an array of of_drconf_cell
  207 + * entries. Get the niumber of entries and skip to the array of
  208 + * of_drconf_cell's.
  209 + */
  210 + entries = *p++;
  211 + old_drmem = (struct of_drconf_cell *)p;
  212 +
  213 + p = (u32 *)pr->prop->value;
  214 + p++;
  215 + new_drmem = (struct of_drconf_cell *)p;
  216 +
  217 + for (i = 0; i < entries; i++) {
  218 + if ((old_drmem[i].flags & DRCONF_MEM_ASSIGNED) &&
  219 + (!(new_drmem[i].flags & DRCONF_MEM_ASSIGNED))) {
  220 + rc = pseries_remove_memblock(old_drmem[i].base_addr,
  221 + memblock_size);
  222 + break;
  223 + } else if ((!(old_drmem[i].flags & DRCONF_MEM_ASSIGNED)) &&
  224 + (new_drmem[i].flags & DRCONF_MEM_ASSIGNED)) {
  225 + rc = memblock_add(old_drmem[i].base_addr,
  226 + memblock_size);
  227 + rc = (rc < 0) ? -EINVAL : 0;
  228 + break;
  229 + }
206 230 }
207 231  
208 232 return rc;
209 233 }
210 234  
211 235 static int pseries_memory_notifier(struct notifier_block *nb,
212   - unsigned long action, void *node)
  236 + unsigned long action, void *node)
213 237 {
  238 + struct of_prop_reconfig *pr;
214 239 int err = 0;
215 240  
216 241 switch (action) {
217   - case PSERIES_RECONFIG_ADD:
  242 + case OF_RECONFIG_ATTACH_NODE:
218 243 err = pseries_add_memory(node);
219 244 break;
220   - case PSERIES_RECONFIG_REMOVE:
  245 + case OF_RECONFIG_DETACH_NODE:
221 246 err = pseries_remove_memory(node);
222 247 break;
223   - case PSERIES_DRCONF_MEM_ADD:
224   - case PSERIES_DRCONF_MEM_REMOVE:
225   - err = pseries_drconf_memory(node, action);
  248 + case OF_RECONFIG_UPDATE_PROPERTY:
  249 + pr = (struct of_prop_reconfig *)node;
  250 + if (!strcmp(pr->prop->name, "ibm,dynamic-memory"))
  251 + err = pseries_update_drconf_memory(pr);
226 252 break;
227 253 }
228 254 return notifier_from_errno(err);
... ... @@ -235,7 +261,7 @@
235 261 static int __init pseries_memory_hotplug_init(void)
236 262 {
237 263 if (firmware_has_feature(FW_FEATURE_LPAR))
238   - pSeries_reconfig_notifier_register(&pseries_mem_nb);
  264 + of_reconfig_notifier_register(&pseries_mem_nb);
239 265  
240 266 return 0;
241 267 }
arch/powerpc/platforms/pseries/iommu.c
... ... @@ -36,13 +36,13 @@
36 36 #include <linux/dma-mapping.h>
37 37 #include <linux/crash_dump.h>
38 38 #include <linux/memory.h>
  39 +#include <linux/of.h>
39 40 #include <asm/io.h>
40 41 #include <asm/prom.h>
41 42 #include <asm/rtas.h>
42 43 #include <asm/iommu.h>
43 44 #include <asm/pci-bridge.h>
44 45 #include <asm/machdep.h>
45   -#include <asm/pSeries_reconfig.h>
46 46 #include <asm/firmware.h>
47 47 #include <asm/tce.h>
48 48 #include <asm/ppc-pci.h>
... ... @@ -1294,7 +1294,7 @@
1294 1294 struct direct_window *window;
1295 1295  
1296 1296 switch (action) {
1297   - case PSERIES_RECONFIG_REMOVE:
  1297 + case OF_RECONFIG_DETACH_NODE:
1298 1298 if (pci && pci->iommu_table)
1299 1299 iommu_free_table(pci->iommu_table, np->full_name);
1300 1300  
... ... @@ -1357,7 +1357,7 @@
1357 1357 }
1358 1358  
1359 1359  
1360   - pSeries_reconfig_notifier_register(&iommu_reconfig_nb);
  1360 + of_reconfig_notifier_register(&iommu_reconfig_nb);
1361 1361 register_memory_notifier(&iommu_mem_nb);
1362 1362  
1363 1363 set_pci_dma_ops(&dma_iommu_ops);
arch/powerpc/platforms/pseries/reconfig.c
... ... @@ -16,11 +16,11 @@
16 16 #include <linux/notifier.h>
17 17 #include <linux/proc_fs.h>
18 18 #include <linux/slab.h>
  19 +#include <linux/of.h>
19 20  
20 21 #include <asm/prom.h>
21 22 #include <asm/machdep.h>
22 23 #include <asm/uaccess.h>
23   -#include <asm/pSeries_reconfig.h>
24 24 #include <asm/mmu.h>
25 25  
26 26 /**
... ... @@ -55,28 +55,6 @@
55 55 return parent;
56 56 }
57 57  
58   -static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain);
59   -
60   -int pSeries_reconfig_notifier_register(struct notifier_block *nb)
61   -{
62   - return blocking_notifier_chain_register(&pSeries_reconfig_chain, nb);
63   -}
64   -EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_register);
65   -
66   -void pSeries_reconfig_notifier_unregister(struct notifier_block *nb)
67   -{
68   - blocking_notifier_chain_unregister(&pSeries_reconfig_chain, nb);
69   -}
70   -EXPORT_SYMBOL_GPL(pSeries_reconfig_notifier_unregister);
71   -
72   -int pSeries_reconfig_notify(unsigned long action, void *p)
73   -{
74   - int err = blocking_notifier_call_chain(&pSeries_reconfig_chain,
75   - action, p);
76   -
77   - return notifier_to_errno(err);
78   -}
79   -
80 58 static int pSeries_reconfig_add_node(const char *path, struct property *proplist)
81 59 {
82 60 struct device_node *np;
83 61  
... ... @@ -100,13 +78,12 @@
100 78 goto out_err;
101 79 }
102 80  
103   - err = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, np);
  81 + err = of_attach_node(np);
104 82 if (err) {
105 83 printk(KERN_ERR "Failed to add device node %s\n", path);
106 84 goto out_err;
107 85 }
108 86  
109   - of_attach_node(np);
110 87 of_node_put(np->parent);
111 88  
112 89 return 0;
113 90  
... ... @@ -134,9 +111,7 @@
134 111 return -EBUSY;
135 112 }
136 113  
137   - pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, np);
138 114 of_detach_node(np);
139   -
140 115 of_node_put(parent);
141 116 of_node_put(np); /* Must decrement the refcount */
142 117 return 0;
143 118  
... ... @@ -381,10 +356,9 @@
381 356 static int do_update_property(char *buf, size_t bufsize)
382 357 {
383 358 struct device_node *np;
384   - struct pSeries_reconfig_prop_update upd_value;
385 359 unsigned char *value;
386 360 char *name, *end, *next_prop;
387   - int rc, length;
  361 + int length;
388 362 struct property *newprop;
389 363 buf = parse_node(buf, bufsize, &np);
390 364 end = buf + bufsize;
... ... @@ -406,41 +380,7 @@
406 380 if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size"))
407 381 slb_set_size(*(int *)value);
408 382  
409   - upd_value.node = np;
410   - upd_value.property = newprop;
411   - pSeries_reconfig_notify(PSERIES_UPDATE_PROPERTY, &upd_value);
412   -
413   - rc = prom_update_property(np, newprop);
414   - if (rc)
415   - return rc;
416   -
417   - /* For memory under the ibm,dynamic-reconfiguration-memory node
418   - * of the device tree, adding and removing memory is just an update
419   - * to the ibm,dynamic-memory property instead of adding/removing a
420   - * memory node in the device tree. For these cases we still need to
421   - * involve the notifier chain.
422   - */
423   - if (!strcmp(name, "ibm,dynamic-memory")) {
424   - int action;
425   -
426   - next_prop = parse_next_property(next_prop, end, &name,
427   - &length, &value);
428   - if (!next_prop)
429   - return -EINVAL;
430   -
431   - if (!strcmp(name, "add"))
432   - action = PSERIES_DRCONF_MEM_ADD;
433   - else
434   - action = PSERIES_DRCONF_MEM_REMOVE;
435   -
436   - rc = pSeries_reconfig_notify(action, value);
437   - if (rc) {
438   - prom_update_property(np, newprop);
439   - return rc;
440   - }
441   - }
442   -
443   - return 0;
  383 + return prom_update_property(np, newprop);
444 384 }
445 385  
446 386 /**
arch/powerpc/platforms/pseries/setup.c
... ... @@ -40,6 +40,7 @@
40 40 #include <linux/seq_file.h>
41 41 #include <linux/root_dev.h>
42 42 #include <linux/cpuidle.h>
  43 +#include <linux/of.h>
43 44  
44 45 #include <asm/mmu.h>
45 46 #include <asm/processor.h>
... ... @@ -63,7 +64,6 @@
63 64 #include <asm/smp.h>
64 65 #include <asm/firmware.h>
65 66 #include <asm/eeh.h>
66   -#include <asm/pSeries_reconfig.h>
67 67  
68 68 #include "plpar_wrappers.h"
69 69 #include "pseries.h"
... ... @@ -258,7 +258,7 @@
258 258 int err = NOTIFY_OK;
259 259  
260 260 switch (action) {
261   - case PSERIES_RECONFIG_ADD:
  261 + case OF_RECONFIG_ATTACH_NODE:
262 262 pci = np->parent->data;
263 263 if (pci) {
264 264 update_dn_pci_info(np, pci->phb);
... ... @@ -389,7 +389,7 @@
389 389 /* Find and initialize PCI host bridges */
390 390 init_pci_config_tokens();
391 391 find_and_init_phbs();
392   - pSeries_reconfig_notifier_register(&pci_dn_reconfig_nb);
  392 + of_reconfig_notifier_register(&pci_dn_reconfig_nb);
393 393  
394 394 pSeries_nvram_init();
395 395  
drivers/crypto/nx/nx-842.c
... ... @@ -28,7 +28,6 @@
28 28 #include <linux/slab.h>
29 29  
30 30 #include <asm/page.h>
31   -#include <asm/pSeries_reconfig.h>
32 31 #include <asm/vio.h>
33 32  
34 33 #include "nx_csbcpb.h" /* struct nx_csbcpb */
35 34  
36 35  
37 36  
38 37  
... ... @@ -1014,26 +1013,23 @@
1014 1013 * NOTIFY_BAD encoded with error number on failure, use
1015 1014 * notifier_to_errno() to decode this value
1016 1015 */
1017   -static int nx842_OF_notifier(struct notifier_block *np,
1018   - unsigned long action,
1019   - void *update)
  1016 +static int nx842_OF_notifier(struct notifier_block *np, unsigned long action,
  1017 + void *update)
1020 1018 {
1021   - struct pSeries_reconfig_prop_update *upd;
  1019 + struct of_prop_reconfig *upd = update;
1022 1020 struct nx842_devdata *local_devdata;
1023 1021 struct device_node *node = NULL;
1024 1022  
1025   - upd = (struct pSeries_reconfig_prop_update *)update;
1026   -
1027 1023 rcu_read_lock();
1028 1024 local_devdata = rcu_dereference(devdata);
1029 1025 if (local_devdata)
1030 1026 node = local_devdata->dev->of_node;
1031 1027  
1032 1028 if (local_devdata &&
1033   - action == PSERIES_UPDATE_PROPERTY &&
1034   - !strcmp(upd->node->name, node->name)) {
  1029 + action == OF_RECONFIG_UPDATE_PROPERTY &&
  1030 + !strcmp(upd->dn->name, node->name)) {
1035 1031 rcu_read_unlock();
1036   - nx842_OF_upd(upd->property);
  1032 + nx842_OF_upd(upd->prop);
1037 1033 } else
1038 1034 rcu_read_unlock();
1039 1035  
... ... @@ -1182,7 +1178,7 @@
1182 1178 synchronize_rcu();
1183 1179 kfree(old_devdata);
1184 1180  
1185   - pSeries_reconfig_notifier_register(&nx842_of_nb);
  1181 + of_reconfig_notifier_register(&nx842_of_nb);
1186 1182  
1187 1183 ret = nx842_OF_upd(NULL);
1188 1184 if (ret && ret != -ENODEV) {
... ... @@ -1228,7 +1224,7 @@
1228 1224 spin_lock_irqsave(&devdata_mutex, flags);
1229 1225 old_devdata = rcu_dereference_check(devdata,
1230 1226 lockdep_is_held(&devdata_mutex));
1231   - pSeries_reconfig_notifier_unregister(&nx842_of_nb);
  1227 + of_reconfig_notifier_unregister(&nx842_of_nb);
1232 1228 rcu_assign_pointer(devdata, NULL);
1233 1229 spin_unlock_irqrestore(&devdata_mutex, flags);
1234 1230 synchronize_rcu();
drivers/crypto/nx/nx.c
... ... @@ -33,7 +33,6 @@
33 33 #include <linux/scatterlist.h>
34 34 #include <linux/device.h>
35 35 #include <linux/of.h>
36   -#include <asm/pSeries_reconfig.h>
37 36 #include <asm/hvcall.h>
38 37 #include <asm/vio.h>
39 38  
... ... @@ -1028,6 +1028,24 @@
1028 1028 }
1029 1029 EXPORT_SYMBOL(of_parse_phandle_with_args);
1030 1030  
  1031 +#if defined(CONFIG_OF_DYNAMIC)
  1032 +static int of_property_notify(int action, struct device_node *np,
  1033 + struct property *prop)
  1034 +{
  1035 + struct of_prop_reconfig pr;
  1036 +
  1037 + pr.dn = np;
  1038 + pr.prop = prop;
  1039 + return of_reconfig_notify(action, &pr);
  1040 +}
  1041 +#else
  1042 +static int of_property_notify(int action, struct device_node *np,
  1043 + struct property *prop)
  1044 +{
  1045 + return 0;
  1046 +}
  1047 +#endif
  1048 +
1031 1049 /**
1032 1050 * prom_add_property - Add a property to a node
1033 1051 */
1034 1052  
... ... @@ -1035,7 +1053,12 @@
1035 1053 {
1036 1054 struct property **next;
1037 1055 unsigned long flags;
  1056 + int rc;
1038 1057  
  1058 + rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop);
  1059 + if (rc)
  1060 + return rc;
  1061 +
1039 1062 prop->next = NULL;
1040 1063 write_lock_irqsave(&devtree_lock, flags);
1041 1064 next = &np->properties;
1042 1065  
... ... @@ -1072,7 +1095,12 @@
1072 1095 struct property **next;
1073 1096 unsigned long flags;
1074 1097 int found = 0;
  1098 + int rc;
1075 1099  
  1100 + rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop);
  1101 + if (rc)
  1102 + return rc;
  1103 +
1076 1104 write_lock_irqsave(&devtree_lock, flags);
1077 1105 next = &np->properties;
1078 1106 while (*next) {
1079 1107  
... ... @@ -1114,8 +1142,12 @@
1114 1142 {
1115 1143 struct property **next, *oldprop;
1116 1144 unsigned long flags;
1117   - int found = 0;
  1145 + int rc, found = 0;
1118 1146  
  1147 + rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop);
  1148 + if (rc)
  1149 + return rc;
  1150 +
1119 1151 if (!newprop->name)
1120 1152 return -EINVAL;
1121 1153  
... ... @@ -1160,6 +1192,26 @@
1160 1192 * device tree nodes.
1161 1193 */
1162 1194  
  1195 +static BLOCKING_NOTIFIER_HEAD(of_reconfig_chain);
  1196 +
  1197 +int of_reconfig_notifier_register(struct notifier_block *nb)
  1198 +{
  1199 + return blocking_notifier_chain_register(&of_reconfig_chain, nb);
  1200 +}
  1201 +
  1202 +int of_reconfig_notifier_unregister(struct notifier_block *nb)
  1203 +{
  1204 + return blocking_notifier_chain_unregister(&of_reconfig_chain, nb);
  1205 +}
  1206 +
  1207 +int of_reconfig_notify(unsigned long action, void *p)
  1208 +{
  1209 + int rc;
  1210 +
  1211 + rc = blocking_notifier_call_chain(&of_reconfig_chain, action, p);
  1212 + return notifier_to_errno(rc);
  1213 +}
  1214 +
1163 1215 #ifdef CONFIG_PROC_DEVICETREE
1164 1216 static void of_add_proc_dt_entry(struct device_node *dn)
1165 1217 {
1166 1218  
1167 1219  
... ... @@ -1179,10 +1231,15 @@
1179 1231 /**
1180 1232 * of_attach_node - Plug a device node into the tree and global list.
1181 1233 */
1182   -void of_attach_node(struct device_node *np)
  1234 +int of_attach_node(struct device_node *np)
1183 1235 {
1184 1236 unsigned long flags;
  1237 + int rc;
1185 1238  
  1239 + rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np);
  1240 + if (rc)
  1241 + return rc;
  1242 +
1186 1243 write_lock_irqsave(&devtree_lock, flags);
1187 1244 np->sibling = np->parent->child;
1188 1245 np->allnext = allnodes;
... ... @@ -1191,6 +1248,7 @@
1191 1248 write_unlock_irqrestore(&devtree_lock, flags);
1192 1249  
1193 1250 of_add_proc_dt_entry(np);
  1251 + return 0;
1194 1252 }
1195 1253  
1196 1254 #ifdef CONFIG_PROC_DEVICETREE
1197 1255  
1198 1256  
1199 1257  
1200 1258  
... ... @@ -1220,23 +1278,28 @@
1220 1278 * The caller must hold a reference to the node. The memory associated with
1221 1279 * the node is not freed until its refcount goes to zero.
1222 1280 */
1223   -void of_detach_node(struct device_node *np)
  1281 +int of_detach_node(struct device_node *np)
1224 1282 {
1225 1283 struct device_node *parent;
1226 1284 unsigned long flags;
  1285 + int rc = 0;
1227 1286  
  1287 + rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np);
  1288 + if (rc)
  1289 + return rc;
  1290 +
1228 1291 write_lock_irqsave(&devtree_lock, flags);
1229 1292  
1230 1293 if (of_node_check_flag(np, OF_DETACHED)) {
1231 1294 /* someone already detached it */
1232 1295 write_unlock_irqrestore(&devtree_lock, flags);
1233   - return;
  1296 + return rc;
1234 1297 }
1235 1298  
1236 1299 parent = np->parent;
1237 1300 if (!parent) {
1238 1301 write_unlock_irqrestore(&devtree_lock, flags);
1239   - return;
  1302 + return rc;
1240 1303 }
1241 1304  
1242 1305 if (allnodes == np)
... ... @@ -1265,6 +1328,7 @@
1265 1328 write_unlock_irqrestore(&devtree_lock, flags);
1266 1329  
1267 1330 of_remove_proc_dt_entry(np);
  1331 + return rc;
1268 1332 }
1269 1333 #endif /* defined(CONFIG_OF_DYNAMIC) */
1270 1334  
... ... @@ -22,6 +22,7 @@
22 22 #include <linux/mod_devicetable.h>
23 23 #include <linux/spinlock.h>
24 24 #include <linux/topology.h>
  25 +#include <linux/notifier.h>
25 26  
26 27 #include <asm/byteorder.h>
27 28 #include <asm/errno.h>
28 29  
... ... @@ -272,11 +273,24 @@
272 273 extern int prom_update_property(struct device_node *np,
273 274 struct property *newprop);
274 275  
275   -#if defined(CONFIG_OF_DYNAMIC)
276 276 /* For updating the device tree at runtime */
277   -extern void of_attach_node(struct device_node *);
278   -extern void of_detach_node(struct device_node *);
279   -#endif
  277 +#define OF_RECONFIG_ATTACH_NODE 0x0001
  278 +#define OF_RECONFIG_DETACH_NODE 0x0002
  279 +#define OF_RECONFIG_ADD_PROPERTY 0x0003
  280 +#define OF_RECONFIG_REMOVE_PROPERTY 0x0004
  281 +#define OF_RECONFIG_UPDATE_PROPERTY 0x0005
  282 +
  283 +struct of_prop_reconfig {
  284 + struct device_node *dn;
  285 + struct property *prop;
  286 +};
  287 +
  288 +extern int of_reconfig_notifier_register(struct notifier_block *);
  289 +extern int of_reconfig_notifier_unregister(struct notifier_block *);
  290 +extern int of_reconfig_notify(unsigned long, void *);
  291 +
  292 +extern int of_attach_node(struct device_node *);
  293 +extern int of_detach_node(struct device_node *);
280 294  
281 295 #define of_match_ptr(_ptr) (_ptr)
282 296