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 /arch/powerpc/platforms/pseries/hotplug-memory.c | |
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>
Diffstat (limited to 'arch/powerpc/platforms/pseries/hotplug-memory.c')
-rw-r--r-- | arch/powerpc/platforms/pseries/hotplug-memory.c | 60 |
1 files changed, 43 insertions, 17 deletions
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 | } |