Skip to content

Commit

Permalink
powerpc/pseries: Update the device tree correctly for drconf memory a…
Browse files Browse the repository at this point in the history
…dd/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>
  • Loading branch information
Nathan Fontenot authored and Paul Mackerras committed Jul 3, 2008
1 parent 92ecd17 commit 3c3f67e
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 33 deletions.
95 changes: 68 additions & 27 deletions arch/powerpc/platforms/pseries/hotplug-memory.c
Original file line number Diff line number Diff line change
Expand Up @@ -15,32 +15,11 @@
#include <asm/machdep.h>
#include <asm/pSeries_reconfig.h>

static int pseries_remove_memory(struct device_node *np)
static int pseries_remove_lmb(unsigned long base, unsigned int lmb_size)
{
const char *type;
const unsigned int *regs;
unsigned long base;
unsigned int lmb_size;
u64 start_pfn, start;
unsigned long start, start_pfn;
struct zone *zone;
int ret = -EINVAL;

/*
* Check to see if we are actually removing memory
*/
type = of_get_property(np, "device_type", NULL);
if (type == NULL || strcmp(type, "memory") != 0)
return 0;

/*
* Find the bae address and size of the lmb
*/
regs = of_get_property(np, "reg", NULL);
if (!regs)
return ret;

base = *(unsigned long *)regs;
lmb_size = regs[3];
int ret;

start_pfn = base >> PFN_SECTION_SHIFT;
zone = page_zone(pfn_to_page(start_pfn));
Expand Down Expand Up @@ -71,13 +50,41 @@ static int pseries_remove_memory(struct device_node *np)
return ret;
}

static int pseries_remove_memory(struct device_node *np)
{
const char *type;
const unsigned int *regs;
unsigned long base;
unsigned int lmb_size;
int ret = -EINVAL;

/*
* Check to see if we are actually removing memory
*/
type = of_get_property(np, "device_type", NULL);
if (type == NULL || strcmp(type, "memory") != 0)
return 0;

/*
* Find the bae address and size of the lmb
*/
regs = of_get_property(np, "reg", NULL);
if (!regs)
return ret;

base = *(unsigned long *)regs;
lmb_size = regs[3];

ret = pseries_remove_lmb(base, lmb_size);
return ret;
}

static int pseries_add_memory(struct device_node *np)
{
const char *type;
const unsigned int *regs;
unsigned long base;
unsigned int lmb_size;
u64 start_pfn;
int ret = -EINVAL;

/*
Expand All @@ -100,8 +107,37 @@ static int pseries_add_memory(struct device_node *np)
/*
* Update memory region to represent the memory add
*/
lmb_add(base, lmb_size);
return 0;
ret = lmb_add(base, lmb_size);
return (ret < 0) ? -EINVAL : 0;
}

static int pseries_drconf_memory(unsigned long *base, unsigned int action)
{
struct device_node *np;
const unsigned long *lmb_size;
int rc;

np = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
if (!np)
return -EINVAL;

lmb_size = of_get_property(np, "ibm,lmb-size", NULL);
if (!lmb_size) {
of_node_put(np);
return -EINVAL;
}

if (action == PSERIES_DRCONF_MEM_ADD) {
rc = lmb_add(*base, *lmb_size);
rc = (rc < 0) ? -EINVAL : 0;
} else if (action == PSERIES_DRCONF_MEM_REMOVE) {
rc = pseries_remove_lmb(*base, *lmb_size);
} else {
rc = -EINVAL;
}

of_node_put(np);
return rc;
}

static int pseries_memory_notifier(struct notifier_block *nb,
Expand All @@ -118,6 +154,11 @@ static int pseries_memory_notifier(struct notifier_block *nb,
if (pseries_remove_memory(node))
err = NOTIFY_BAD;
break;
case PSERIES_DRCONF_MEM_ADD:
case PSERIES_DRCONF_MEM_REMOVE:
if (pseries_drconf_memory(node, action))
err = NOTIFY_BAD;
break;
default:
err = NOTIFY_DONE;
break;
Expand Down
36 changes: 32 additions & 4 deletions arch/powerpc/platforms/pseries/reconfig.c
Original file line number Diff line number Diff line change
Expand Up @@ -422,16 +422,17 @@ static int do_update_property(char *buf, size_t bufsize)
{
struct device_node *np;
unsigned char *value;
char *name, *end;
int length;
char *name, *end, *next_prop;
int rc, length;
struct property *newprop, *oldprop;
buf = parse_node(buf, bufsize, &np);
end = buf + bufsize;

if (!np)
return -ENODEV;

if (parse_next_property(buf, end, &name, &length, &value) == NULL)
next_prop = parse_next_property(buf, end, &name, &length, &value);
if (!next_prop)
return -EINVAL;

newprop = new_property(name, length, value, NULL);
Expand All @@ -442,7 +443,34 @@ static int do_update_property(char *buf, size_t bufsize)
if (!oldprop)
return -ENODEV;

return prom_update_property(np, newprop, oldprop);
rc = prom_update_property(np, newprop, oldprop);
if (rc)
return rc;

/* For memory under the ibm,dynamic-reconfiguration-memory node
* of the device tree, adding and removing memory is just an update
* to the ibm,dynamic-memory property instead of adding/removing a
* memory node in the device tree. For these cases we still need to
* involve the notifier chain.
*/
if (!strcmp(name, "ibm,dynamic-memory")) {
int action;

next_prop = parse_next_property(next_prop, end, &name,
&length, &value);
if (!next_prop)
return -EINVAL;

if (!strcmp(name, "add"))
action = PSERIES_DRCONF_MEM_ADD;
else
action = PSERIES_DRCONF_MEM_REMOVE;

blocking_notifier_call_chain(&pSeries_reconfig_chain,
action, value);
}

return 0;
}

/**
Expand Down
6 changes: 4 additions & 2 deletions include/asm-powerpc/pSeries_reconfig.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,10 @@
* added or removed on pSeries systems.
*/

#define PSERIES_RECONFIG_ADD 0x0001
#define PSERIES_RECONFIG_REMOVE 0x0002
#define PSERIES_RECONFIG_ADD 0x0001
#define PSERIES_RECONFIG_REMOVE 0x0002
#define PSERIES_DRCONF_MEM_ADD 0x0003
#define PSERIES_DRCONF_MEM_REMOVE 0x0004

#ifdef CONFIG_PPC_PSERIES
extern int pSeries_reconfig_notifier_register(struct notifier_block *);
Expand Down

0 comments on commit 3c3f67e

Please sign in to comment.