diff options
author | Nathan Fontenot <nfont@linux.vnet.ibm.com> | 2012-10-02 12:57:57 -0400 |
---|---|---|
committer | Benjamin Herrenschmidt <benh@kernel.crashing.org> | 2012-11-14 20:56:41 -0500 |
commit | 1cf3d8b3d24cd383ddfd5442c83ec5c355ffc2f7 (patch) | |
tree | 0f4790e95f917c6b76d95c88b7b3d67445261893 | |
parent | f59497208363f3dd9d62b79b7f7eafc95432de79 (diff) |
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>
-rw-r--r-- | arch/powerpc/include/asm/pSeries_reconfig.h | 32 | ||||
-rw-r--r-- | arch/powerpc/kernel/prom.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/dlpar.c | 14 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/hotplug-cpu.c | 8 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/hotplug-memory.c | 60 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/iommu.c | 6 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/reconfig.c | 68 | ||||
-rw-r--r-- | arch/powerpc/platforms/pseries/setup.c | 6 | ||||
-rw-r--r-- | drivers/crypto/nx/nx-842.c | 20 | ||||
-rw-r--r-- | drivers/crypto/nx/nx.c | 1 | ||||
-rw-r--r-- | drivers/of/base.c | 74 | ||||
-rw-r--r-- | include/linux/of.h | 22 |
12 files changed, 163 insertions, 154 deletions
diff --git a/arch/powerpc/include/asm/pSeries_reconfig.h b/arch/powerpc/include/asm/pSeries_reconfig.h index c07edfe98b98..adc00d2e75b0 100644 --- a/arch/powerpc/include/asm/pSeries_reconfig.h +++ b/arch/powerpc/include/asm/pSeries_reconfig.h | |||
@@ -2,43 +2,11 @@ | |||
2 | #define _PPC64_PSERIES_RECONFIG_H | 2 | #define _PPC64_PSERIES_RECONFIG_H |
3 | #ifdef __KERNEL__ | 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 | #ifdef CONFIG_PPC_PSERIES | 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 | /* Not the best place to put this, will be fixed when we move some | 6 | /* Not the best place to put this, will be fixed when we move some |
34 | * of the rtas suspend-me stuff to pseries */ | 7 | * of the rtas suspend-me stuff to pseries */ |
35 | extern void pSeries_coalesce_init(void); | 8 | extern void pSeries_coalesce_init(void); |
36 | #else /* !CONFIG_PPC_PSERIES */ | 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 | static inline void pSeries_coalesce_init(void) { } | 10 | static inline void pSeries_coalesce_init(void) { } |
43 | #endif /* CONFIG_PPC_PSERIES */ | 11 | #endif /* CONFIG_PPC_PSERIES */ |
44 | 12 | ||
diff --git a/arch/powerpc/kernel/prom.c b/arch/powerpc/kernel/prom.c index 37725e86651e..6feb60c3c6e3 100644 --- a/arch/powerpc/kernel/prom.c +++ b/arch/powerpc/kernel/prom.c | |||
@@ -32,6 +32,7 @@ | |||
32 | #include <linux/debugfs.h> | 32 | #include <linux/debugfs.h> |
33 | #include <linux/irq.h> | 33 | #include <linux/irq.h> |
34 | #include <linux/memblock.h> | 34 | #include <linux/memblock.h> |
35 | #include <linux/of.h> | ||
35 | 36 | ||
36 | #include <asm/prom.h> | 37 | #include <asm/prom.h> |
37 | #include <asm/rtas.h> | 38 | #include <asm/rtas.h> |
@@ -49,7 +50,6 @@ | |||
49 | #include <asm/btext.h> | 50 | #include <asm/btext.h> |
50 | #include <asm/sections.h> | 51 | #include <asm/sections.h> |
51 | #include <asm/machdep.h> | 52 | #include <asm/machdep.h> |
52 | #include <asm/pSeries_reconfig.h> | ||
53 | #include <asm/pci-bridge.h> | 53 | #include <asm/pci-bridge.h> |
54 | #include <asm/kexec.h> | 54 | #include <asm/kexec.h> |
55 | #include <asm/opal.h> | 55 | #include <asm/opal.h> |
@@ -802,7 +802,7 @@ static int prom_reconfig_notifier(struct notifier_block *nb, | |||
802 | int err; | 802 | int err; |
803 | 803 | ||
804 | switch (action) { | 804 | switch (action) { |
805 | case PSERIES_RECONFIG_ADD: | 805 | case OF_RECONFIG_ATTACH_NODE: |
806 | err = of_finish_dynamic_node(node); | 806 | err = of_finish_dynamic_node(node); |
807 | if (err < 0) | 807 | if (err < 0) |
808 | printk(KERN_ERR "finish_node returned %d\n", err); | 808 | printk(KERN_ERR "finish_node returned %d\n", err); |
@@ -821,7 +821,7 @@ static struct notifier_block prom_reconfig_nb = { | |||
821 | 821 | ||
822 | static int __init prom_reconfig_setup(void) | 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 | __initcall(prom_reconfig_setup); | 826 | __initcall(prom_reconfig_setup); |
827 | #endif | 827 | #endif |
diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c index e36789bd4e6c..a1a7b9a67ffd 100644 --- a/arch/powerpc/platforms/pseries/dlpar.c +++ b/arch/powerpc/platforms/pseries/dlpar.c | |||
@@ -16,13 +16,13 @@ | |||
16 | #include <linux/spinlock.h> | 16 | #include <linux/spinlock.h> |
17 | #include <linux/cpu.h> | 17 | #include <linux/cpu.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/of.h> | ||
19 | #include "offline_states.h" | 20 | #include "offline_states.h" |
20 | 21 | ||
21 | #include <asm/prom.h> | 22 | #include <asm/prom.h> |
22 | #include <asm/machdep.h> | 23 | #include <asm/machdep.h> |
23 | #include <asm/uaccess.h> | 24 | #include <asm/uaccess.h> |
24 | #include <asm/rtas.h> | 25 | #include <asm/rtas.h> |
25 | #include <asm/pSeries_reconfig.h> | ||
26 | 26 | ||
27 | struct cc_workarea { | 27 | struct cc_workarea { |
28 | u32 drc_index; | 28 | u32 drc_index; |
@@ -262,24 +262,26 @@ int dlpar_attach_node(struct device_node *dn) | |||
262 | if (!dn->parent) | 262 | if (!dn->parent) |
263 | return -ENOMEM; | 263 | return -ENOMEM; |
264 | 264 | ||
265 | rc = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, dn); | 265 | rc = of_attach_node(dn); |
266 | if (rc) { | 266 | if (rc) { |
267 | printk(KERN_ERR "Failed to add device node %s\n", | 267 | printk(KERN_ERR "Failed to add device node %s\n", |
268 | dn->full_name); | 268 | dn->full_name); |
269 | return rc; | 269 | return rc; |
270 | } | 270 | } |
271 | 271 | ||
272 | of_attach_node(dn); | ||
273 | of_node_put(dn->parent); | 272 | of_node_put(dn->parent); |
274 | return 0; | 273 | return 0; |
275 | } | 274 | } |
276 | 275 | ||
277 | int dlpar_detach_node(struct device_node *dn) | 276 | int dlpar_detach_node(struct device_node *dn) |
278 | { | 277 | { |
279 | pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, dn); | 278 | int rc; |
280 | of_detach_node(dn); | 279 | |
281 | of_node_put(dn); /* Must decrement the refcount */ | 280 | rc = of_detach_node(dn); |
281 | if (rc) | ||
282 | return rc; | ||
282 | 283 | ||
284 | of_node_put(dn); /* Must decrement the refcount */ | ||
283 | return 0; | 285 | return 0; |
284 | } | 286 | } |
285 | 287 | ||
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index 64c97d8ac0c5..a38956269fbf 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c | |||
@@ -23,12 +23,12 @@ | |||
23 | #include <linux/delay.h> | 23 | #include <linux/delay.h> |
24 | #include <linux/sched.h> /* for idle_task_exit */ | 24 | #include <linux/sched.h> /* for idle_task_exit */ |
25 | #include <linux/cpu.h> | 25 | #include <linux/cpu.h> |
26 | #include <linux/of.h> | ||
26 | #include <asm/prom.h> | 27 | #include <asm/prom.h> |
27 | #include <asm/rtas.h> | 28 | #include <asm/rtas.h> |
28 | #include <asm/firmware.h> | 29 | #include <asm/firmware.h> |
29 | #include <asm/machdep.h> | 30 | #include <asm/machdep.h> |
30 | #include <asm/vdso_datapage.h> | 31 | #include <asm/vdso_datapage.h> |
31 | #include <asm/pSeries_reconfig.h> | ||
32 | #include <asm/xics.h> | 32 | #include <asm/xics.h> |
33 | #include "plpar_wrappers.h" | 33 | #include "plpar_wrappers.h" |
34 | #include "offline_states.h" | 34 | #include "offline_states.h" |
@@ -333,10 +333,10 @@ static int pseries_smp_notifier(struct notifier_block *nb, | |||
333 | int err = 0; | 333 | int err = 0; |
334 | 334 | ||
335 | switch (action) { | 335 | switch (action) { |
336 | case PSERIES_RECONFIG_ADD: | 336 | case OF_RECONFIG_ATTACH_NODE: |
337 | err = pseries_add_processor(node); | 337 | err = pseries_add_processor(node); |
338 | break; | 338 | break; |
339 | case PSERIES_RECONFIG_REMOVE: | 339 | case OF_RECONFIG_DETACH_NODE: |
340 | pseries_remove_processor(node); | 340 | pseries_remove_processor(node); |
341 | break; | 341 | break; |
342 | } | 342 | } |
@@ -399,7 +399,7 @@ static int __init pseries_cpu_hotplug_init(void) | |||
399 | 399 | ||
400 | /* Processors can be added/removed only on LPAR */ | 400 | /* Processors can be added/removed only on LPAR */ |
401 | if (firmware_has_feature(FW_FEATURE_LPAR)) { | 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 | cpu_maps_update_begin(); | 403 | cpu_maps_update_begin(); |
404 | if (cede_offline_enabled && parse_cede_parameters() == 0) { | 404 | if (cede_offline_enabled && parse_cede_parameters() == 0) { |
405 | default_offline_state = CPU_STATE_INACTIVE; | 405 | default_offline_state = CPU_STATE_INACTIVE; |
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index ecdb0a6b3171..2372c609fa2b 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c | |||
@@ -16,7 +16,6 @@ | |||
16 | 16 | ||
17 | #include <asm/firmware.h> | 17 | #include <asm/firmware.h> |
18 | #include <asm/machdep.h> | 18 | #include <asm/machdep.h> |
19 | #include <asm/pSeries_reconfig.h> | ||
20 | #include <asm/sparsemem.h> | 19 | #include <asm/sparsemem.h> |
21 | 20 | ||
22 | static unsigned long get_memblock_size(void) | 21 | static unsigned long get_memblock_size(void) |
@@ -187,42 +186,69 @@ static int pseries_add_memory(struct device_node *np) | |||
187 | return (ret < 0) ? -EINVAL : 0; | 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 | unsigned long memblock_size; | 192 | unsigned long memblock_size; |
193 | int rc; | 193 | u32 entries; |
194 | u32 *p; | ||
195 | int i, rc = -EINVAL; | ||
194 | 196 | ||
195 | memblock_size = get_memblock_size(); | 197 | memblock_size = get_memblock_size(); |
196 | if (!memblock_size) | 198 | if (!memblock_size) |
197 | return -EINVAL; | 199 | return -EINVAL; |
198 | 200 | ||
199 | if (action == PSERIES_DRCONF_MEM_ADD) { | 201 | p = (u32 *)of_get_property(pr->dn, "ibm,dynamic-memory", NULL); |
200 | rc = memblock_add(*base, memblock_size); | 202 | if (!p) |
201 | rc = (rc < 0) ? -EINVAL : 0; | 203 | return -EINVAL; |
202 | } else if (action == PSERIES_DRCONF_MEM_REMOVE) { | 204 | |
203 | rc = pseries_remove_memblock(*base, memblock_size); | 205 | /* The first int of the property is the number of lmb's described |
204 | } else { | 206 | * by the property. This is followed by an array of of_drconf_cell |
205 | rc = -EINVAL; | 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 | return rc; | 232 | return rc; |
209 | } | 233 | } |
210 | 234 | ||
211 | static int pseries_memory_notifier(struct notifier_block *nb, | 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 | int err = 0; | 239 | int err = 0; |
215 | 240 | ||
216 | switch (action) { | 241 | switch (action) { |
217 | case PSERIES_RECONFIG_ADD: | 242 | case OF_RECONFIG_ATTACH_NODE: |
218 | err = pseries_add_memory(node); | 243 | err = pseries_add_memory(node); |
219 | break; | 244 | break; |
220 | case PSERIES_RECONFIG_REMOVE: | 245 | case OF_RECONFIG_DETACH_NODE: |
221 | err = pseries_remove_memory(node); | 246 | err = pseries_remove_memory(node); |
222 | break; | 247 | break; |
223 | case PSERIES_DRCONF_MEM_ADD: | 248 | case OF_RECONFIG_UPDATE_PROPERTY: |
224 | case PSERIES_DRCONF_MEM_REMOVE: | 249 | pr = (struct of_prop_reconfig *)node; |
225 | err = pseries_drconf_memory(node, action); | 250 | if (!strcmp(pr->prop->name, "ibm,dynamic-memory")) |
251 | err = pseries_update_drconf_memory(pr); | ||
226 | break; | 252 | break; |
227 | } | 253 | } |
228 | return notifier_from_errno(err); | 254 | return notifier_from_errno(err); |
@@ -235,7 +261,7 @@ static struct notifier_block pseries_mem_nb = { | |||
235 | static int __init pseries_memory_hotplug_init(void) | 261 | static int __init pseries_memory_hotplug_init(void) |
236 | { | 262 | { |
237 | if (firmware_has_feature(FW_FEATURE_LPAR)) | 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 | return 0; | 266 | return 0; |
241 | } | 267 | } |
diff --git a/arch/powerpc/platforms/pseries/iommu.c b/arch/powerpc/platforms/pseries/iommu.c index 6153eea27ce7..da5594c441e4 100644 --- a/arch/powerpc/platforms/pseries/iommu.c +++ b/arch/powerpc/platforms/pseries/iommu.c | |||
@@ -36,13 +36,13 @@ | |||
36 | #include <linux/dma-mapping.h> | 36 | #include <linux/dma-mapping.h> |
37 | #include <linux/crash_dump.h> | 37 | #include <linux/crash_dump.h> |
38 | #include <linux/memory.h> | 38 | #include <linux/memory.h> |
39 | #include <linux/of.h> | ||
39 | #include <asm/io.h> | 40 | #include <asm/io.h> |
40 | #include <asm/prom.h> | 41 | #include <asm/prom.h> |
41 | #include <asm/rtas.h> | 42 | #include <asm/rtas.h> |
42 | #include <asm/iommu.h> | 43 | #include <asm/iommu.h> |
43 | #include <asm/pci-bridge.h> | 44 | #include <asm/pci-bridge.h> |
44 | #include <asm/machdep.h> | 45 | #include <asm/machdep.h> |
45 | #include <asm/pSeries_reconfig.h> | ||
46 | #include <asm/firmware.h> | 46 | #include <asm/firmware.h> |
47 | #include <asm/tce.h> | 47 | #include <asm/tce.h> |
48 | #include <asm/ppc-pci.h> | 48 | #include <asm/ppc-pci.h> |
@@ -1294,7 +1294,7 @@ static int iommu_reconfig_notifier(struct notifier_block *nb, unsigned long acti | |||
1294 | struct direct_window *window; | 1294 | struct direct_window *window; |
1295 | 1295 | ||
1296 | switch (action) { | 1296 | switch (action) { |
1297 | case PSERIES_RECONFIG_REMOVE: | 1297 | case OF_RECONFIG_DETACH_NODE: |
1298 | if (pci && pci->iommu_table) | 1298 | if (pci && pci->iommu_table) |
1299 | iommu_free_table(pci->iommu_table, np->full_name); | 1299 | iommu_free_table(pci->iommu_table, np->full_name); |
1300 | 1300 | ||
@@ -1357,7 +1357,7 @@ void iommu_init_early_pSeries(void) | |||
1357 | } | 1357 | } |
1358 | 1358 | ||
1359 | 1359 | ||
1360 | pSeries_reconfig_notifier_register(&iommu_reconfig_nb); | 1360 | of_reconfig_notifier_register(&iommu_reconfig_nb); |
1361 | register_memory_notifier(&iommu_mem_nb); | 1361 | register_memory_notifier(&iommu_mem_nb); |
1362 | 1362 | ||
1363 | set_pci_dma_ops(&dma_iommu_ops); | 1363 | set_pci_dma_ops(&dma_iommu_ops); |
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c index f99f1ca8035b..720a0cc2e69f 100644 --- a/arch/powerpc/platforms/pseries/reconfig.c +++ b/arch/powerpc/platforms/pseries/reconfig.c | |||
@@ -16,11 +16,11 @@ | |||
16 | #include <linux/notifier.h> | 16 | #include <linux/notifier.h> |
17 | #include <linux/proc_fs.h> | 17 | #include <linux/proc_fs.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/of.h> | ||
19 | 20 | ||
20 | #include <asm/prom.h> | 21 | #include <asm/prom.h> |
21 | #include <asm/machdep.h> | 22 | #include <asm/machdep.h> |
22 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
23 | #include <asm/pSeries_reconfig.h> | ||
24 | #include <asm/mmu.h> | 24 | #include <asm/mmu.h> |
25 | 25 | ||
26 | /** | 26 | /** |
@@ -55,28 +55,6 @@ static struct device_node *derive_parent(const char *path) | |||
55 | return parent; | 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 | static int pSeries_reconfig_add_node(const char *path, struct property *proplist) | 58 | static int pSeries_reconfig_add_node(const char *path, struct property *proplist) |
81 | { | 59 | { |
82 | struct device_node *np; | 60 | struct device_node *np; |
@@ -100,13 +78,12 @@ static int pSeries_reconfig_add_node(const char *path, struct property *proplist | |||
100 | goto out_err; | 78 | goto out_err; |
101 | } | 79 | } |
102 | 80 | ||
103 | err = pSeries_reconfig_notify(PSERIES_RECONFIG_ADD, np); | 81 | err = of_attach_node(np); |
104 | if (err) { | 82 | if (err) { |
105 | printk(KERN_ERR "Failed to add device node %s\n", path); | 83 | printk(KERN_ERR "Failed to add device node %s\n", path); |
106 | goto out_err; | 84 | goto out_err; |
107 | } | 85 | } |
108 | 86 | ||
109 | of_attach_node(np); | ||
110 | of_node_put(np->parent); | 87 | of_node_put(np->parent); |
111 | 88 | ||
112 | return 0; | 89 | return 0; |
@@ -134,9 +111,7 @@ static int pSeries_reconfig_remove_node(struct device_node *np) | |||
134 | return -EBUSY; | 111 | return -EBUSY; |
135 | } | 112 | } |
136 | 113 | ||
137 | pSeries_reconfig_notify(PSERIES_RECONFIG_REMOVE, np); | ||
138 | of_detach_node(np); | 114 | of_detach_node(np); |
139 | |||
140 | of_node_put(parent); | 115 | of_node_put(parent); |
141 | of_node_put(np); /* Must decrement the refcount */ | 116 | of_node_put(np); /* Must decrement the refcount */ |
142 | return 0; | 117 | return 0; |
@@ -381,10 +356,9 @@ static int do_remove_property(char *buf, size_t bufsize) | |||
381 | static int do_update_property(char *buf, size_t bufsize) | 356 | static int do_update_property(char *buf, size_t bufsize) |
382 | { | 357 | { |
383 | struct device_node *np; | 358 | struct device_node *np; |
384 | struct pSeries_reconfig_prop_update upd_value; | ||
385 | unsigned char *value; | 359 | unsigned char *value; |
386 | char *name, *end, *next_prop; | 360 | char *name, *end, *next_prop; |
387 | int rc, length; | 361 | int length; |
388 | struct property *newprop; | 362 | struct property *newprop; |
389 | buf = parse_node(buf, bufsize, &np); | 363 | buf = parse_node(buf, bufsize, &np); |
390 | end = buf + bufsize; | 364 | end = buf + bufsize; |
@@ -406,41 +380,7 @@ static int do_update_property(char *buf, size_t bufsize) | |||
406 | if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size")) | 380 | if (!strcmp(name, "slb-size") || !strcmp(name, "ibm,slb-size")) |
407 | slb_set_size(*(int *)value); | 381 | slb_set_size(*(int *)value); |
408 | 382 | ||
409 | upd_value.node = np; | 383 | return prom_update_property(np, newprop); |
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; | ||
444 | } | 384 | } |
445 | 385 | ||
446 | /** | 386 | /** |
diff --git a/arch/powerpc/platforms/pseries/setup.c b/arch/powerpc/platforms/pseries/setup.c index e3cb7ae61658..e1a5b8a32d25 100644 --- a/arch/powerpc/platforms/pseries/setup.c +++ b/arch/powerpc/platforms/pseries/setup.c | |||
@@ -40,6 +40,7 @@ | |||
40 | #include <linux/seq_file.h> | 40 | #include <linux/seq_file.h> |
41 | #include <linux/root_dev.h> | 41 | #include <linux/root_dev.h> |
42 | #include <linux/cpuidle.h> | 42 | #include <linux/cpuidle.h> |
43 | #include <linux/of.h> | ||
43 | 44 | ||
44 | #include <asm/mmu.h> | 45 | #include <asm/mmu.h> |
45 | #include <asm/processor.h> | 46 | #include <asm/processor.h> |
@@ -63,7 +64,6 @@ | |||
63 | #include <asm/smp.h> | 64 | #include <asm/smp.h> |
64 | #include <asm/firmware.h> | 65 | #include <asm/firmware.h> |
65 | #include <asm/eeh.h> | 66 | #include <asm/eeh.h> |
66 | #include <asm/pSeries_reconfig.h> | ||
67 | 67 | ||
68 | #include "plpar_wrappers.h" | 68 | #include "plpar_wrappers.h" |
69 | #include "pseries.h" | 69 | #include "pseries.h" |
@@ -258,7 +258,7 @@ static int pci_dn_reconfig_notifier(struct notifier_block *nb, unsigned long act | |||
258 | int err = NOTIFY_OK; | 258 | int err = NOTIFY_OK; |
259 | 259 | ||
260 | switch (action) { | 260 | switch (action) { |
261 | case PSERIES_RECONFIG_ADD: | 261 | case OF_RECONFIG_ATTACH_NODE: |
262 | pci = np->parent->data; | 262 | pci = np->parent->data; |
263 | if (pci) { | 263 | if (pci) { |
264 | update_dn_pci_info(np, pci->phb); | 264 | update_dn_pci_info(np, pci->phb); |
@@ -389,7 +389,7 @@ static void __init pSeries_setup_arch(void) | |||
389 | /* Find and initialize PCI host bridges */ | 389 | /* Find and initialize PCI host bridges */ |
390 | init_pci_config_tokens(); | 390 | init_pci_config_tokens(); |
391 | find_and_init_phbs(); | 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 | pSeries_nvram_init(); | 394 | pSeries_nvram_init(); |
395 | 395 | ||
diff --git a/drivers/crypto/nx/nx-842.c b/drivers/crypto/nx/nx-842.c index 0ce625738677..6c4c000671c5 100644 --- a/drivers/crypto/nx/nx-842.c +++ b/drivers/crypto/nx/nx-842.c | |||
@@ -28,7 +28,6 @@ | |||
28 | #include <linux/slab.h> | 28 | #include <linux/slab.h> |
29 | 29 | ||
30 | #include <asm/page.h> | 30 | #include <asm/page.h> |
31 | #include <asm/pSeries_reconfig.h> | ||
32 | #include <asm/vio.h> | 31 | #include <asm/vio.h> |
33 | 32 | ||
34 | #include "nx_csbcpb.h" /* struct nx_csbcpb */ | 33 | #include "nx_csbcpb.h" /* struct nx_csbcpb */ |
@@ -1014,26 +1013,23 @@ error_out: | |||
1014 | * NOTIFY_BAD encoded with error number on failure, use | 1013 | * NOTIFY_BAD encoded with error number on failure, use |
1015 | * notifier_to_errno() to decode this value | 1014 | * notifier_to_errno() to decode this value |
1016 | */ | 1015 | */ |
1017 | static int nx842_OF_notifier(struct notifier_block *np, | 1016 | static int nx842_OF_notifier(struct notifier_block *np, unsigned long action, |
1018 | unsigned long action, | 1017 | void *update) |
1019 | void *update) | ||
1020 | { | 1018 | { |
1021 | struct pSeries_reconfig_prop_update *upd; | 1019 | struct of_prop_reconfig *upd = update; |
1022 | struct nx842_devdata *local_devdata; | 1020 | struct nx842_devdata *local_devdata; |
1023 | struct device_node *node = NULL; | 1021 | struct device_node *node = NULL; |
1024 | 1022 | ||
1025 | upd = (struct pSeries_reconfig_prop_update *)update; | ||
1026 | |||
1027 | rcu_read_lock(); | 1023 | rcu_read_lock(); |
1028 | local_devdata = rcu_dereference(devdata); | 1024 | local_devdata = rcu_dereference(devdata); |
1029 | if (local_devdata) | 1025 | if (local_devdata) |
1030 | node = local_devdata->dev->of_node; | 1026 | node = local_devdata->dev->of_node; |
1031 | 1027 | ||
1032 | if (local_devdata && | 1028 | if (local_devdata && |
1033 | action == PSERIES_UPDATE_PROPERTY && | 1029 | action == OF_RECONFIG_UPDATE_PROPERTY && |
1034 | !strcmp(upd->node->name, node->name)) { | 1030 | !strcmp(upd->dn->name, node->name)) { |
1035 | rcu_read_unlock(); | 1031 | rcu_read_unlock(); |
1036 | nx842_OF_upd(upd->property); | 1032 | nx842_OF_upd(upd->prop); |
1037 | } else | 1033 | } else |
1038 | rcu_read_unlock(); | 1034 | rcu_read_unlock(); |
1039 | 1035 | ||
@@ -1182,7 +1178,7 @@ static int __init nx842_probe(struct vio_dev *viodev, | |||
1182 | synchronize_rcu(); | 1178 | synchronize_rcu(); |
1183 | kfree(old_devdata); | 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 | ret = nx842_OF_upd(NULL); | 1183 | ret = nx842_OF_upd(NULL); |
1188 | if (ret && ret != -ENODEV) { | 1184 | if (ret && ret != -ENODEV) { |
@@ -1228,7 +1224,7 @@ static int __exit nx842_remove(struct vio_dev *viodev) | |||
1228 | spin_lock_irqsave(&devdata_mutex, flags); | 1224 | spin_lock_irqsave(&devdata_mutex, flags); |
1229 | old_devdata = rcu_dereference_check(devdata, | 1225 | old_devdata = rcu_dereference_check(devdata, |
1230 | lockdep_is_held(&devdata_mutex)); | 1226 | lockdep_is_held(&devdata_mutex)); |
1231 | pSeries_reconfig_notifier_unregister(&nx842_of_nb); | 1227 | of_reconfig_notifier_unregister(&nx842_of_nb); |
1232 | rcu_assign_pointer(devdata, NULL); | 1228 | rcu_assign_pointer(devdata, NULL); |
1233 | spin_unlock_irqrestore(&devdata_mutex, flags); | 1229 | spin_unlock_irqrestore(&devdata_mutex, flags); |
1234 | synchronize_rcu(); | 1230 | synchronize_rcu(); |
diff --git a/drivers/crypto/nx/nx.c b/drivers/crypto/nx/nx.c index 638110efae9b..f7a8a16aa7d3 100644 --- a/drivers/crypto/nx/nx.c +++ b/drivers/crypto/nx/nx.c | |||
@@ -33,7 +33,6 @@ | |||
33 | #include <linux/scatterlist.h> | 33 | #include <linux/scatterlist.h> |
34 | #include <linux/device.h> | 34 | #include <linux/device.h> |
35 | #include <linux/of.h> | 35 | #include <linux/of.h> |
36 | #include <asm/pSeries_reconfig.h> | ||
37 | #include <asm/hvcall.h> | 36 | #include <asm/hvcall.h> |
38 | #include <asm/vio.h> | 37 | #include <asm/vio.h> |
39 | 38 | ||
diff --git a/drivers/of/base.c b/drivers/of/base.c index bbd073f53c9f..87b63850e8dc 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c | |||
@@ -1028,6 +1028,24 @@ int of_parse_phandle_with_args(struct device_node *np, const char *list_name, | |||
1028 | } | 1028 | } |
1029 | EXPORT_SYMBOL(of_parse_phandle_with_args); | 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 | * prom_add_property - Add a property to a node | 1050 | * prom_add_property - Add a property to a node |
1033 | */ | 1051 | */ |
@@ -1035,6 +1053,11 @@ int prom_add_property(struct device_node *np, struct property *prop) | |||
1035 | { | 1053 | { |
1036 | struct property **next; | 1054 | struct property **next; |
1037 | unsigned long flags; | 1055 | unsigned long flags; |
1056 | int rc; | ||
1057 | |||
1058 | rc = of_property_notify(OF_RECONFIG_ADD_PROPERTY, np, prop); | ||
1059 | if (rc) | ||
1060 | return rc; | ||
1038 | 1061 | ||
1039 | prop->next = NULL; | 1062 | prop->next = NULL; |
1040 | write_lock_irqsave(&devtree_lock, flags); | 1063 | write_lock_irqsave(&devtree_lock, flags); |
@@ -1072,6 +1095,11 @@ int prom_remove_property(struct device_node *np, struct property *prop) | |||
1072 | struct property **next; | 1095 | struct property **next; |
1073 | unsigned long flags; | 1096 | unsigned long flags; |
1074 | int found = 0; | 1097 | int found = 0; |
1098 | int rc; | ||
1099 | |||
1100 | rc = of_property_notify(OF_RECONFIG_REMOVE_PROPERTY, np, prop); | ||
1101 | if (rc) | ||
1102 | return rc; | ||
1075 | 1103 | ||
1076 | write_lock_irqsave(&devtree_lock, flags); | 1104 | write_lock_irqsave(&devtree_lock, flags); |
1077 | next = &np->properties; | 1105 | next = &np->properties; |
@@ -1114,7 +1142,11 @@ int prom_update_property(struct device_node *np, | |||
1114 | { | 1142 | { |
1115 | struct property **next, *oldprop; | 1143 | struct property **next, *oldprop; |
1116 | unsigned long flags; | 1144 | unsigned long flags; |
1117 | int found = 0; | 1145 | int rc, found = 0; |
1146 | |||
1147 | rc = of_property_notify(OF_RECONFIG_UPDATE_PROPERTY, np, newprop); | ||
1148 | if (rc) | ||
1149 | return rc; | ||
1118 | 1150 | ||
1119 | if (!newprop->name) | 1151 | if (!newprop->name) |
1120 | return -EINVAL; | 1152 | return -EINVAL; |
@@ -1160,6 +1192,26 @@ int prom_update_property(struct device_node *np, | |||
1160 | * device tree nodes. | 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 | #ifdef CONFIG_PROC_DEVICETREE | 1215 | #ifdef CONFIG_PROC_DEVICETREE |
1164 | static void of_add_proc_dt_entry(struct device_node *dn) | 1216 | static void of_add_proc_dt_entry(struct device_node *dn) |
1165 | { | 1217 | { |
@@ -1179,9 +1231,14 @@ static void of_add_proc_dt_entry(struct device_node *dn) | |||
1179 | /** | 1231 | /** |
1180 | * of_attach_node - Plug a device node into the tree and global list. | 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 | unsigned long flags; | 1236 | unsigned long flags; |
1237 | int rc; | ||
1238 | |||
1239 | rc = of_reconfig_notify(OF_RECONFIG_ATTACH_NODE, np); | ||
1240 | if (rc) | ||
1241 | return rc; | ||
1185 | 1242 | ||
1186 | write_lock_irqsave(&devtree_lock, flags); | 1243 | write_lock_irqsave(&devtree_lock, flags); |
1187 | np->sibling = np->parent->child; | 1244 | np->sibling = np->parent->child; |
@@ -1191,6 +1248,7 @@ void of_attach_node(struct device_node *np) | |||
1191 | write_unlock_irqrestore(&devtree_lock, flags); | 1248 | write_unlock_irqrestore(&devtree_lock, flags); |
1192 | 1249 | ||
1193 | of_add_proc_dt_entry(np); | 1250 | of_add_proc_dt_entry(np); |
1251 | return 0; | ||
1194 | } | 1252 | } |
1195 | 1253 | ||
1196 | #ifdef CONFIG_PROC_DEVICETREE | 1254 | #ifdef CONFIG_PROC_DEVICETREE |
@@ -1220,23 +1278,28 @@ static void of_remove_proc_dt_entry(struct device_node *dn) | |||
1220 | * The caller must hold a reference to the node. The memory associated with | 1278 | * The caller must hold a reference to the node. The memory associated with |
1221 | * the node is not freed until its refcount goes to zero. | 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 | struct device_node *parent; | 1283 | struct device_node *parent; |
1226 | unsigned long flags; | 1284 | unsigned long flags; |
1285 | int rc = 0; | ||
1286 | |||
1287 | rc = of_reconfig_notify(OF_RECONFIG_DETACH_NODE, np); | ||
1288 | if (rc) | ||
1289 | return rc; | ||
1227 | 1290 | ||
1228 | write_lock_irqsave(&devtree_lock, flags); | 1291 | write_lock_irqsave(&devtree_lock, flags); |
1229 | 1292 | ||
1230 | if (of_node_check_flag(np, OF_DETACHED)) { | 1293 | if (of_node_check_flag(np, OF_DETACHED)) { |
1231 | /* someone already detached it */ | 1294 | /* someone already detached it */ |
1232 | write_unlock_irqrestore(&devtree_lock, flags); | 1295 | write_unlock_irqrestore(&devtree_lock, flags); |
1233 | return; | 1296 | return rc; |
1234 | } | 1297 | } |
1235 | 1298 | ||
1236 | parent = np->parent; | 1299 | parent = np->parent; |
1237 | if (!parent) { | 1300 | if (!parent) { |
1238 | write_unlock_irqrestore(&devtree_lock, flags); | 1301 | write_unlock_irqrestore(&devtree_lock, flags); |
1239 | return; | 1302 | return rc; |
1240 | } | 1303 | } |
1241 | 1304 | ||
1242 | if (allnodes == np) | 1305 | if (allnodes == np) |
@@ -1265,6 +1328,7 @@ void of_detach_node(struct device_node *np) | |||
1265 | write_unlock_irqrestore(&devtree_lock, flags); | 1328 | write_unlock_irqrestore(&devtree_lock, flags); |
1266 | 1329 | ||
1267 | of_remove_proc_dt_entry(np); | 1330 | of_remove_proc_dt_entry(np); |
1331 | return rc; | ||
1268 | } | 1332 | } |
1269 | #endif /* defined(CONFIG_OF_DYNAMIC) */ | 1333 | #endif /* defined(CONFIG_OF_DYNAMIC) */ |
1270 | 1334 | ||
diff --git a/include/linux/of.h b/include/linux/of.h index 72843b72a2b2..fb5d87b66e3e 100644 --- a/include/linux/of.h +++ b/include/linux/of.h | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/mod_devicetable.h> | 22 | #include <linux/mod_devicetable.h> |
23 | #include <linux/spinlock.h> | 23 | #include <linux/spinlock.h> |
24 | #include <linux/topology.h> | 24 | #include <linux/topology.h> |
25 | #include <linux/notifier.h> | ||
25 | 26 | ||
26 | #include <asm/byteorder.h> | 27 | #include <asm/byteorder.h> |
27 | #include <asm/errno.h> | 28 | #include <asm/errno.h> |
@@ -272,11 +273,24 @@ extern int prom_remove_property(struct device_node *np, struct property *prop); | |||
272 | extern int prom_update_property(struct device_node *np, | 273 | extern int prom_update_property(struct device_node *np, |
273 | struct property *newprop); | 274 | struct property *newprop); |
274 | 275 | ||
275 | #if defined(CONFIG_OF_DYNAMIC) | ||
276 | /* For updating the device tree at runtime */ | 276 | /* For updating the device tree at runtime */ |
277 | extern void of_attach_node(struct device_node *); | 277 | #define OF_RECONFIG_ATTACH_NODE 0x0001 |
278 | extern void of_detach_node(struct device_node *); | 278 | #define OF_RECONFIG_DETACH_NODE 0x0002 |
279 | #endif | 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 | #define of_match_ptr(_ptr) (_ptr) | 295 | #define of_match_ptr(_ptr) (_ptr) |
282 | 296 | ||