mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-09-06 02:50:43 +00:00
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>
This commit is contained in:
parent
92ecd1790b
commit
3c3f67eafa
3 changed files with 104 additions and 33 deletions
|
@ -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));
|
||||
|
@ -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;
|
||||
|
||||
/*
|
||||
|
@ -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,
|
||||
|
@ -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;
|
||||
|
|
|
@ -422,8 +422,8 @@ 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;
|
||||
|
@ -431,7 +431,8 @@ static int do_update_property(char *buf, size_t 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);
|
||||
|
@ -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;
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
@ -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 *);
|
||||
|
|
Loading…
Reference in a new issue