aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorNathan Fontenot <nfont@austin.ibm.com>2008-07-02 23:22:39 -0400
committerPaul Mackerras <paulus@samba.org>2008-07-03 02:58:16 -0400
commit3c3f67eafad12d4ccabe491c6c8a50bf6e75b89a (patch)
treebe4081be92d8a7c165281242384cb79cb8c2d06d
parent92ecd1790b10e12015070e33a0f70493d51aca50 (diff)
powerpc/pseries: Update the device tree correctly for drconf memory add/remove
This updates the device tree manipulation routines so that memory add/remove of lmbs represented under the ibm,dynamic-reconfiguration-memory node of the device tree invokes the hotplug notifier chain. This change is needed because of the change in the way memory is represented under the ibm,dynamic-reconfiguration-memory node. All lmbs are described in the ibm,dynamic-memory property instead of having a separate node for each lmb as in previous device tree layouts. This requires the update_node() routine to check for updates to the ibm,dynamic-memory property and invoke the hotplug notifier chain. This also updates the pseries hotplug notifier to be able to gather information for lmbs represented under the ibm,dynamic-reconfiguration-memory node and have the lmbs added/removed. Signed-off-by: Nathan Fontenot <nfont@austin.ibm.com> Signed-off-by: Paul Mackerras <paulus@samba.org>
-rw-r--r--arch/powerpc/platforms/pseries/hotplug-memory.c95
-rw-r--r--arch/powerpc/platforms/pseries/reconfig.c36
-rw-r--r--include/asm-powerpc/pSeries_reconfig.h6
3 files changed, 104 insertions, 33 deletions
diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c
index 18a8138ef99f..a1a368dd2d99 100644
--- a/arch/powerpc/platforms/pseries/hotplug-memory.c
+++ b/arch/powerpc/platforms/pseries/hotplug-memory.c
@@ -15,32 +15,11 @@
15#include <asm/machdep.h> 15#include <asm/machdep.h>
16#include <asm/pSeries_reconfig.h> 16#include <asm/pSeries_reconfig.h>
17 17
18static int pseries_remove_memory(struct device_node *np) 18static int pseries_remove_lmb(unsigned long base, unsigned int lmb_size)
19{ 19{
20 const char *type; 20 unsigned long start, start_pfn;
21 const unsigned int *regs;
22 unsigned long base;
23 unsigned int lmb_size;
24 u64 start_pfn, start;
25 struct zone *zone; 21 struct zone *zone;
26 int ret = -EINVAL; 22 int ret;
27
28 /*
29 * Check to see if we are actually removing memory
30 */
31 type = of_get_property(np, "device_type", NULL);
32 if (type == NULL || strcmp(type, "memory") != 0)
33 return 0;
34
35 /*
36 * Find the bae address and size of the lmb
37 */
38 regs = of_get_property(np, "reg", NULL);
39 if (!regs)
40 return ret;
41
42 base = *(unsigned long *)regs;
43 lmb_size = regs[3];
44 23
45 start_pfn = base >> PFN_SECTION_SHIFT; 24 start_pfn = base >> PFN_SECTION_SHIFT;
46 zone = page_zone(pfn_to_page(start_pfn)); 25 zone = page_zone(pfn_to_page(start_pfn));
@@ -71,13 +50,41 @@ static int pseries_remove_memory(struct device_node *np)
71 return ret; 50 return ret;
72} 51}
73 52
53static int pseries_remove_memory(struct device_node *np)
54{
55 const char *type;
56 const unsigned int *regs;
57 unsigned long base;
58 unsigned int lmb_size;
59 int ret = -EINVAL;
60
61 /*
62 * Check to see if we are actually removing memory
63 */
64 type = of_get_property(np, "device_type", NULL);
65 if (type == NULL || strcmp(type, "memory") != 0)
66 return 0;
67
68 /*
69 * Find the bae address and size of the lmb
70 */
71 regs = of_get_property(np, "reg", NULL);
72 if (!regs)
73 return ret;
74
75 base = *(unsigned long *)regs;
76 lmb_size = regs[3];
77
78 ret = pseries_remove_lmb(base, lmb_size);
79 return ret;
80}
81
74static int pseries_add_memory(struct device_node *np) 82static int pseries_add_memory(struct device_node *np)
75{ 83{
76 const char *type; 84 const char *type;
77 const unsigned int *regs; 85 const unsigned int *regs;
78 unsigned long base; 86 unsigned long base;
79 unsigned int lmb_size; 87 unsigned int lmb_size;
80 u64 start_pfn;
81 int ret = -EINVAL; 88 int ret = -EINVAL;
82 89
83 /* 90 /*
@@ -100,8 +107,37 @@ static int pseries_add_memory(struct device_node *np)
100 /* 107 /*
101 * Update memory region to represent the memory add 108 * Update memory region to represent the memory add
102 */ 109 */
103 lmb_add(base, lmb_size); 110 ret = lmb_add(base, lmb_size);
104 return 0; 111 return (ret < 0) ? -EINVAL : 0;
112}
113
114static int pseries_drconf_memory(unsigned long *base, unsigned int action)
115{
116 struct device_node *np;
117 const unsigned long *lmb_size;
118 int rc;
119
120 np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
121 if (!np)
122 return -EINVAL;
123
124 lmb_size = of_get_property(np, "ibm,lmb-size", NULL);
125 if (!lmb_size) {
126 of_node_put(np);
127 return -EINVAL;
128 }
129
130 if (action == PSERIES_DRCONF_MEM_ADD) {
131 rc = lmb_add(*base, *lmb_size);
132 rc = (rc < 0) ? -EINVAL : 0;
133 } else if (action == PSERIES_DRCONF_MEM_REMOVE) {
134 rc = pseries_remove_lmb(*base, *lmb_size);
135 } else {
136 rc = -EINVAL;
137 }
138
139 of_node_put(np);
140 return rc;
105} 141}
106 142
107static int pseries_memory_notifier(struct notifier_block *nb, 143static int pseries_memory_notifier(struct notifier_block *nb,
@@ -118,6 +154,11 @@ static int pseries_memory_notifier(struct notifier_block *nb,
118 if (pseries_remove_memory(node)) 154 if (pseries_remove_memory(node))
119 err = NOTIFY_BAD; 155 err = NOTIFY_BAD;
120 break; 156 break;
157 case PSERIES_DRCONF_MEM_ADD:
158 case PSERIES_DRCONF_MEM_REMOVE:
159 if (pseries_drconf_memory(node, action))
160 err = NOTIFY_BAD;
161 break;
121 default: 162 default:
122 err = NOTIFY_DONE; 163 err = NOTIFY_DONE;
123 break; 164 break;
diff --git a/arch/powerpc/platforms/pseries/reconfig.c b/arch/powerpc/platforms/pseries/reconfig.c
index dfa2ebd2deb5..7637bd38c795 100644
--- a/arch/powerpc/platforms/pseries/reconfig.c
+++ b/arch/powerpc/platforms/pseries/reconfig.c
@@ -422,8 +422,8 @@ static int do_update_property(char *buf, size_t bufsize)
422{ 422{
423 struct device_node *np; 423 struct device_node *np;
424 unsigned char *value; 424 unsigned char *value;
425 char *name, *end; 425 char *name, *end, *next_prop;
426 int length; 426 int rc, length;
427 struct property *newprop, *oldprop; 427 struct property *newprop, *oldprop;
428 buf = parse_node(buf, bufsize, &np); 428 buf = parse_node(buf, bufsize, &np);
429 end = buf + bufsize; 429 end = buf + bufsize;
@@ -431,7 +431,8 @@ static int do_update_property(char *buf, size_t bufsize)
431 if (!np) 431 if (!np)
432 return -ENODEV; 432 return -ENODEV;
433 433
434 if (parse_next_property(buf, end, &name, &length, &value) == NULL) 434 next_prop = parse_next_property(buf, end, &name, &length, &value);
435 if (!next_prop)
435 return -EINVAL; 436 return -EINVAL;
436 437
437 newprop = new_property(name, length, value, NULL); 438 newprop = new_property(name, length, value, NULL);
@@ -442,7 +443,34 @@ static int do_update_property(char *buf, size_t bufsize)
442 if (!oldprop) 443 if (!oldprop)
443 return -ENODEV; 444 return -ENODEV;
444 445
445 return prom_update_property(np, newprop, oldprop); 446 rc = prom_update_property(np, newprop, oldprop);
447 if (rc)
448 return rc;
449
450 /* For memory under the ibm,dynamic-reconfiguration-memory node
451 * of the device tree, adding and removing memory is just an update
452 * to the ibm,dynamic-memory property instead of adding/removing a
453 * memory node in the device tree. For these cases we still need to
454 * involve the notifier chain.
455 */
456 if (!strcmp(name, "ibm,dynamic-memory")) {
457 int action;
458
459 next_prop = parse_next_property(next_prop, end, &name,
460 &length, &value);
461 if (!next_prop)
462 return -EINVAL;
463
464 if (!strcmp(name, "add"))
465 action = PSERIES_DRCONF_MEM_ADD;
466 else
467 action = PSERIES_DRCONF_MEM_REMOVE;
468
469 blocking_notifier_call_chain(&pSeries_reconfig_chain,
470 action, value);
471 }
472
473 return 0;
446} 474}
447 475
448/** 476/**
diff --git a/include/asm-powerpc/pSeries_reconfig.h b/include/asm-powerpc/pSeries_reconfig.h
index ea6cfb8efb84..e482e5352e69 100644
--- a/include/asm-powerpc/pSeries_reconfig.h
+++ b/include/asm-powerpc/pSeries_reconfig.h
@@ -9,8 +9,10 @@
9 * added or removed on pSeries systems. 9 * added or removed on pSeries systems.
10 */ 10 */
11 11
12#define PSERIES_RECONFIG_ADD 0x0001 12#define PSERIES_RECONFIG_ADD 0x0001
13#define PSERIES_RECONFIG_REMOVE 0x0002 13#define PSERIES_RECONFIG_REMOVE 0x0002
14#define PSERIES_DRCONF_MEM_ADD 0x0003
15#define PSERIES_DRCONF_MEM_REMOVE 0x0004
14 16
15#ifdef CONFIG_PPC_PSERIES 17#ifdef CONFIG_PPC_PSERIES
16extern int pSeries_reconfig_notifier_register(struct notifier_block *); 18extern int pSeries_reconfig_notifier_register(struct notifier_block *);