* [PATCH 0/5 v4] Kernel Handling of Dynamic Logical Partitioning
@ 2009-10-21 14:35 Nathan Fontenot
2009-10-21 14:40 ` [PATCH 1/5 " Nathan Fontenot
` (4 more replies)
0 siblings, 5 replies; 9+ messages in thread
From: Nathan Fontenot @ 2009-10-21 14:35 UTC (permalink / raw)
To: linuxppc-dev; +Cc: lkml
This is a re-send of the entire patch set with updates made from the comments
I have received, namely patches 1,3 and 5. I am re-sending the entire patch
set for clarity.
The Dynamic Logical Partitioning (DLPAR) capabilities of the powerpc pseries
platform allows for the addition and removal of resources (i.e. cpus,
memory, pci devices) from a partition. The removal of a resource involves
removing the resource's node from the device tree and then returning the
resource to firmware via the rtas set-indicator call. To add a resource, it
is first obtained from firmware via the rtas set-indicator call and then a
new device tree node is created using the ibm,configure-coinnector rtas call
and added to the device tree.
The following set of patches implements the needed infrastructure to have the
kernel handle the DLPAR addition and removal of memory and cpus (other
DLPAR'able items to follow in future patches). The framework for this is
to create a set of probe/release sysfs files in pseries that will add or
remove the cpu or memory to the system.
The majority of the code is powerpc/pseries specific except for PATCH 3/5, so
I am cc'ing lkml.
Patches include in this set:
1/5 - DLPAR infracstructure for powerpc/pseries platform.
2/5 - Move the of_drconf_cell struct to prom.h
3/5 - Export the memory sysdev class
4/5 - Memory DLPAR handling
5/5 - CPU DLPAR handling
-Nathan Fontenot
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 1/5 v4] Kernel Handling of Dynamic Logical Partitioning
2009-10-21 14:35 [PATCH 0/5 v4] Kernel Handling of Dynamic Logical Partitioning Nathan Fontenot
@ 2009-10-21 14:40 ` Nathan Fontenot
2009-10-21 14:42 ` [PATCH 2/5 v4] move of_drconf_cell definition to prom.h Nathan Fontenot
` (3 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Nathan Fontenot @ 2009-10-21 14:40 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-kernel
This patch provides the kernel DLPAR infrastructure in a new filed named
dlpar.c. The functionality provided is for acquiring and releasing a
resource from firmware and the parsing of information returned from the
ibm,configure-connector rtas call. Additionally this exports the
pSeries reconfiguration notifier chain so that it can be invoked when
device tree updates are made.
Signed-off-by: Nathan Fontenot <nfont at austin.ibm.com>
---
Index: powerpc/arch/powerpc/platforms/pseries/dlpar.c
===================================================================
--- /dev/null 1970-01-01 00:00:00.000000000 +0000
+++ powerpc/arch/powerpc/platforms/pseries/dlpar.c 2009-10-19 11:59:10.000000000 -0500
@@ -0,0 +1,414 @@
+/*
+ * dlpar.c - support for dynamic reconfiguration (including PCI
+ * Hotplug and Dynamic Logical Partitioning on RPA platforms).
+ *
+ * Copyright (C) 2009 Nathan Fontenot
+ * Copyright (C) 2009 IBM Corporation
+ *
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version
+ * 2 as published by the Free Software Foundation.
+ */
+
+#include <linux/kernel.h>
+#include <linux/kref.h>
+#include <linux/notifier.h>
+#include <linux/proc_fs.h>
+#include <linux/spinlock.h>
+
+#include <asm/prom.h>
+#include <asm/machdep.h>
+#include <asm/uaccess.h>
+#include <asm/rtas.h>
+#include <asm/pSeries_reconfig.h>
+
+#define CFG_CONN_WORK_SIZE 4096
+static char workarea[CFG_CONN_WORK_SIZE];
+static DEFINE_SPINLOCK(workarea_lock);
+
+struct cc_workarea {
+ u32 drc_index;
+ u32 zero;
+ u32 name_offset;
+ u32 prop_length;
+ u32 prop_offset;
+};
+
+static struct property *parse_cc_property(char *workarea)
+{
+ struct property *prop;
+ struct cc_workarea *ccwa;
+ char *name;
+ char *value;
+
+ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+ if (!prop)
+ return NULL;
+
+ ccwa = (struct cc_workarea *)workarea;
+ name = workarea + ccwa->name_offset;
+ prop->name = kzalloc(strlen(name) + 1, GFP_KERNEL);
+ if (!prop->name) {
+ kfree(prop);
+ return NULL;
+ }
+
+ strcpy(prop->name, name);
+
+ prop->length = ccwa->prop_length;
+ value = workarea + ccwa->prop_offset;
+ prop->value = kzalloc(prop->length, GFP_KERNEL);
+ if (!prop->value) {
+ kfree(prop->name);
+ kfree(prop);
+ return NULL;
+ }
+
+ memcpy(prop->value, value, prop->length);
+ return prop;
+}
+
+static void free_property(struct property *prop)
+{
+ kfree(prop->name);
+ kfree(prop->value);
+ kfree(prop);
+}
+
+static struct device_node *parse_cc_node(char *work_area)
+{
+ struct device_node *dn;
+ struct cc_workarea *ccwa;
+ char *name;
+
+ dn = kzalloc(sizeof(*dn), GFP_KERNEL);
+ if (!dn)
+ return NULL;
+
+ ccwa = (struct cc_workarea *)work_area;
+ name = work_area + ccwa->name_offset;
+ dn->full_name = kzalloc(strlen(name) + 1, GFP_KERNEL);
+ if (!dn->full_name) {
+ kfree(dn);
+ return NULL;
+ }
+
+ strcpy(dn->full_name, name);
+ return dn;
+}
+
+static void free_one_cc_node(struct device_node *dn)
+{
+ struct property *prop;
+
+ while (dn->properties) {
+ prop = dn->properties;
+ dn->properties = prop->next;
+ free_property(prop);
+ }
+
+ kfree(dn->full_name);
+ kfree(dn);
+}
+
+static void free_cc_nodes(struct device_node *dn)
+{
+ if (dn->child)
+ free_cc_nodes(dn->child);
+
+ if (dn->sibling)
+ free_cc_nodes(dn->sibling);
+
+ free_one_cc_node(dn);
+}
+
+#define NEXT_SIBLING 1
+#define NEXT_CHILD 2
+#define NEXT_PROPERTY 3
+#define PREV_PARENT 4
+#define MORE_MEMORY 5
+#define CALL_AGAIN -2
+#define ERR_CFG_USE -9003
+
+struct device_node *configure_connector(u32 drc_index)
+{
+ struct device_node *dn;
+ struct device_node *first_dn = NULL;
+ struct device_node *last_dn = NULL;
+ struct property *property;
+ struct property *last_property = NULL;
+ struct cc_workarea *ccwa;
+ int cc_token;
+ int rc;
+
+ cc_token = rtas_token("ibm,configure-connector");
+ if (cc_token == RTAS_UNKNOWN_SERVICE)
+ return NULL;
+
+ spin_lock(&workarea_lock);
+
+ ccwa = (struct cc_workarea *)&workarea[0];
+ ccwa->drc_index = drc_index;
+ ccwa->zero = 0;
+
+ rc = rtas_call(cc_token, 2, 1, NULL, workarea, NULL);
+ while (rc) {
+ switch (rc) {
+ case NEXT_SIBLING:
+ dn = parse_cc_node(workarea);
+ if (!dn)
+ goto cc_error;
+
+ dn->parent = last_dn->parent;
+ last_dn->sibling = dn;
+ last_dn = dn;
+ break;
+
+ case NEXT_CHILD:
+ dn = parse_cc_node(workarea);
+ if (!dn)
+ goto cc_error;
+
+ if (!first_dn)
+ first_dn = dn;
+ else {
+ dn->parent = last_dn;
+ if (last_dn)
+ last_dn->child = dn;
+ }
+
+ last_dn = dn;
+ break;
+
+ case NEXT_PROPERTY:
+ property = parse_cc_property(workarea);
+ if (!property)
+ goto cc_error;
+
+ if (!last_dn->properties)
+ last_dn->properties = property;
+ else
+ last_property->next = property;
+
+ last_property = property;
+ break;
+
+ case PREV_PARENT:
+ last_dn = last_dn->parent;
+ break;
+
+ case CALL_AGAIN:
+ break;
+
+ case MORE_MEMORY:
+ case ERR_CFG_USE:
+ default:
+ printk(KERN_ERR "Unexpected Error (%d) "
+ "returned from configure-connector\n", rc);
+ goto cc_error;
+ }
+
+ rc = rtas_call(cc_token, 2, 1, NULL, workarea, NULL);
+ }
+
+ spin_unlock(&workarea_lock);
+ return first_dn;
+
+cc_error:
+ spin_unlock(&workarea_lock);
+
+ if (first_dn)
+ free_cc_nodes(first_dn);
+
+ return NULL;
+}
+
+static struct device_node *derive_parent(const char *path)
+{
+ struct device_node *parent;
+ char parent_path[128];
+ int parent_path_len;
+
+ parent_path_len = strrchr(path, '/') - path + 1;
+ strlcpy(parent_path, path, parent_path_len);
+
+ parent = of_find_node_by_path(parent_path);
+
+ return parent;
+}
+
+static int add_one_node(struct device_node *dn)
+{
+ struct proc_dir_entry *ent;
+ int rc;
+
+ of_node_set_flag(dn, OF_DYNAMIC);
+ kref_init(&dn->kref);
+ dn->parent = derive_parent(dn->full_name);
+
+ rc = blocking_notifier_call_chain(&pSeries_reconfig_chain,
+ PSERIES_RECONFIG_ADD, dn);
+ if (rc == NOTIFY_BAD) {
+ printk(KERN_ERR "Failed to add device node %s\n",
+ dn->full_name);
+ return -ENOMEM; /* For now, safe to assume kmalloc failure */
+ }
+
+ of_attach_node(dn);
+
+#ifdef CONFIG_PROC_DEVICETREE
+ ent = proc_mkdir(strrchr(dn->full_name, '/') + 1, dn->parent->pde);
+ if (ent)
+ proc_device_tree_add_node(dn, ent);
+#endif
+
+ of_node_put(dn->parent);
+ return 0;
+}
+
+int add_device_tree_nodes(struct device_node *dn)
+{
+ struct device_node *child = dn->child;
+ struct device_node *sibling = dn->sibling;
+ int rc;
+
+ dn->child = NULL;
+ dn->sibling = NULL;
+ dn->parent = NULL;
+
+ rc = add_one_node(dn);
+ if (rc)
+ return rc;
+
+ if (child) {
+ rc = add_device_tree_nodes(child);
+ if (rc)
+ return rc;
+ }
+
+ if (sibling)
+ rc = add_device_tree_nodes(sibling);
+
+ return rc;
+}
+
+static int remove_one_node(struct device_node *dn)
+{
+ struct device_node *parent = dn->parent;
+ struct property *prop = dn->properties;
+
+#ifdef CONFIG_PROC_DEVICETREE
+ while (prop) {
+ remove_proc_entry(prop->name, dn->pde);
+ prop = prop->next;
+ }
+
+ if (dn->pde)
+ remove_proc_entry(dn->pde->name, parent->pde);
+#endif
+
+ blocking_notifier_call_chain(&pSeries_reconfig_chain,
+ PSERIES_RECONFIG_REMOVE, dn);
+ of_detach_node(dn);
+ of_node_put(dn); /* Must decrement the refcount */
+
+ return 0;
+}
+
+static int _remove_device_tree_nodes(struct device_node *dn)
+{
+ int rc;
+
+ if (dn->child) {
+ rc = _remove_device_tree_nodes(dn->child);
+ if (rc)
+ return rc;
+ }
+
+ if (dn->sibling) {
+ rc = _remove_device_tree_nodes(dn->sibling);
+ if (rc)
+ return rc;
+ }
+
+ rc = remove_one_node(dn);
+ return rc;
+}
+
+int remove_device_tree_nodes(struct device_node *dn)
+{
+ int rc;
+
+ if (dn->child) {
+ rc = _remove_device_tree_nodes(dn->child);
+ if (rc)
+ return rc;
+ }
+
+ rc = remove_one_node(dn);
+ return rc;
+}
+
+#define DR_ENTITY_SENSE 9003
+#define DR_ENTITY_PRESENT 1
+#define DR_ENTITY_UNUSABLE 2
+#define ALLOCATION_STATE 9003
+#define ALLOC_UNUSABLE 0
+#define ALLOC_USABLE 1
+#define ISOLATION_STATE 9001
+#define ISOLATE 0
+#define UNISOLATE 1
+
+int acquire_drc(u32 drc_index)
+{
+ int dr_status, rc;
+
+ rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
+ DR_ENTITY_SENSE, drc_index);
+ if (rc || dr_status != DR_ENTITY_UNUSABLE)
+ return -1;
+
+ rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_USABLE);
+ if (rc)
+ return rc;
+
+ rc = rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
+ if (rc) {
+ rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
+ return rc;
+ }
+
+ return 0;
+}
+
+int release_drc(u32 drc_index)
+{
+ int dr_status, rc;
+
+ rc = rtas_call(rtas_token("get-sensor-state"), 2, 2, &dr_status,
+ DR_ENTITY_SENSE, drc_index);
+ if (rc || dr_status != DR_ENTITY_PRESENT)
+ return -1;
+
+ rc = rtas_set_indicator(ISOLATION_STATE, drc_index, ISOLATE);
+ if (rc)
+ return rc;
+
+ rc = rtas_set_indicator(ALLOCATION_STATE, drc_index, ALLOC_UNUSABLE);
+ if (rc) {
+ rtas_set_indicator(ISOLATION_STATE, drc_index, UNISOLATE);
+ return rc;
+ }
+
+ return 0;
+}
+
+static int pseries_dlpar_init(void)
+{
+ if (!machine_is(pseries))
+ return 0;
+
+ return 0;
+}
+device_initcall(pseries_dlpar_init);
Index: powerpc/arch/powerpc/platforms/pseries/Makefile
===================================================================
--- powerpc.orig/arch/powerpc/platforms/pseries/Makefile 2009-10-19 11:56:51.000000000 -0500
+++ powerpc/arch/powerpc/platforms/pseries/Makefile 2009-10-19 11:59:10.000000000 -0500
@@ -8,7 +8,7 @@
obj-y := lpar.o hvCall.o nvram.o reconfig.o \
setup.o iommu.o ras.o rtasd.o \
- firmware.o power.o
+ firmware.o power.o dlpar.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_XICS) += xics.o
obj-$(CONFIG_SCANLOG) += scanlog.o
Index: powerpc/arch/powerpc/include/asm/pSeries_reconfig.h
===================================================================
--- powerpc.orig/arch/powerpc/include/asm/pSeries_reconfig.h 2009-10-19 11:56:51.000000000 -0500
+++ powerpc/arch/powerpc/include/asm/pSeries_reconfig.h 2009-10-19 11:59:10.000000000 -0500
@@ -17,6 +17,7 @@
#ifdef CONFIG_PPC_PSERIES
extern int pSeries_reconfig_notifier_register(struct notifier_block *);
extern void pSeries_reconfig_notifier_unregister(struct notifier_block *);
+extern struct blocking_notifier_head pSeries_reconfig_chain;
#else /* !CONFIG_PPC_PSERIES */
static inline int pSeries_reconfig_notifier_register(struct notifier_block *nb)
{
Index: powerpc/arch/powerpc/platforms/pseries/reconfig.c
===================================================================
--- powerpc.orig/arch/powerpc/platforms/pseries/reconfig.c 2009-10-19 11:58:38.000000000 -0500
+++ powerpc/arch/powerpc/platforms/pseries/reconfig.c 2009-10-19 11:59:10.000000000 -0500
@@ -96,7 +96,7 @@
return parent;
}
-static BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain);
+BLOCKING_NOTIFIER_HEAD(pSeries_reconfig_chain);
int pSeries_reconfig_notifier_register(struct notifier_block *nb)
{
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 2/5 v4] move of_drconf_cell definition to prom.h
2009-10-21 14:35 [PATCH 0/5 v4] Kernel Handling of Dynamic Logical Partitioning Nathan Fontenot
2009-10-21 14:40 ` [PATCH 1/5 " Nathan Fontenot
@ 2009-10-21 14:42 ` Nathan Fontenot
2009-10-21 14:44 ` [PATCH 3/5 v4] Export memory_sysdev_class Nathan Fontenot
` (2 subsequent siblings)
4 siblings, 0 replies; 9+ messages in thread
From: Nathan Fontenot @ 2009-10-21 14:42 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-kernel
Move the definition of the of_drconf_cell struct from numa.c to prom.h. This
is needed so that we can parse the ibm,dynamic-memory device-tree property
when DLPAR adding and removing memory.
Signed-off-by: Nathan Fontenot <nfont at austin.ibm.com>
---
Index: powerpc/arch/powerpc/include/asm/prom.h
===================================================================
--- powerpc.orig/arch/powerpc/include/asm/prom.h 2009-10-19 11:56:51.000000000 -0500
+++ powerpc/arch/powerpc/include/asm/prom.h 2009-10-19 11:59:31.000000000 -0500
@@ -349,6 +349,18 @@
*/
extern void __iomem *of_iomap(struct device_node *device, int index);
+struct of_drconf_cell {
+ u64 base_addr;
+ u32 drc_index;
+ u32 reserved;
+ u32 aa_index;
+ u32 flags;
+};
+
+#define DRCONF_MEM_ASSIGNED 0x00000008
+#define DRCONF_MEM_AI_INVALID 0x00000040
+#define DRCONF_MEM_RESERVED 0x00000080
+
/*
* NB: This is here while we transition from using asm/prom.h
* to linux/of.h
Index: powerpc/arch/powerpc/mm/numa.c
===================================================================
--- powerpc.orig/arch/powerpc/mm/numa.c 2009-10-19 11:56:51.000000000 -0500
+++ powerpc/arch/powerpc/mm/numa.c 2009-10-19 11:59:31.000000000 -0500
@@ -296,18 +296,6 @@
return result;
}
-struct of_drconf_cell {
- u64 base_addr;
- u32 drc_index;
- u32 reserved;
- u32 aa_index;
- u32 flags;
-};
-
-#define DRCONF_MEM_ASSIGNED 0x00000008
-#define DRCONF_MEM_AI_INVALID 0x00000040
-#define DRCONF_MEM_RESERVED 0x00000080
-
/*
* Read the next lmb list entry from the ibm,dynamic-memory property
* and return the information in the provided of_drconf_cell structure.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 3/5 v4] Export memory_sysdev_class
2009-10-21 14:35 [PATCH 0/5 v4] Kernel Handling of Dynamic Logical Partitioning Nathan Fontenot
2009-10-21 14:40 ` [PATCH 1/5 " Nathan Fontenot
2009-10-21 14:42 ` [PATCH 2/5 v4] move of_drconf_cell definition to prom.h Nathan Fontenot
@ 2009-10-21 14:44 ` Nathan Fontenot
2009-10-21 16:03 ` Dave Hansen
2009-10-21 14:46 ` [PATCH 4/5 v4] Kernel Handling of memory DLPAR Nathan Fontenot
2009-10-21 14:47 ` [PATCH 5/5 v4] Kernel Handling of cpu DLPAR Nathan Fontenot
4 siblings, 1 reply; 9+ messages in thread
From: Nathan Fontenot @ 2009-10-21 14:44 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-kernel
Export the memory_sysdev_class structure. This is needed so we can create
a 'release' file in sysfs in addition to the existing 'probe' file in
order to support DLPAR removal of memory on the powerpc/pseries platform.
The new 'release' file will be powerpc/pseries only.
Signed-off-by: Nathan Fontenot <nfont at austin.ibm.com>
---
Index: powerpc/drivers/base/memory.c
===================================================================
--- powerpc.orig/drivers/base/memory.c 2009-10-19 11:56:51.000000000 -0500
+++ powerpc/drivers/base/memory.c 2009-10-19 11:59:36.000000000 -0500
@@ -28,9 +28,10 @@
#define MEMORY_CLASS_NAME "memory"
-static struct sysdev_class memory_sysdev_class = {
+struct sysdev_class memory_sysdev_class = {
.name = MEMORY_CLASS_NAME,
};
+EXPORT_SYMBOL(memory_sysdev_class);
static const char *memory_uevent_name(struct kset *kset, struct kobject *kobj)
{
Index: powerpc/include/linux/memory_hotplug.h
===================================================================
--- powerpc.orig/include/linux/memory_hotplug.h 2009-10-19 11:58:43.000000000 -0500
+++ powerpc/include/linux/memory_hotplug.h 2009-10-19 11:59:36.000000000 -0500
@@ -12,6 +12,8 @@
#ifdef CONFIG_MEMORY_HOTPLUG
+extern struct sysdev_class memory_sysdev_class;
+
/*
* Types for free bootmem.
* The normal smallest mapcount is -1. Here is smaller value than it.
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 4/5 v4] Kernel Handling of memory DLPAR
2009-10-21 14:35 [PATCH 0/5 v4] Kernel Handling of Dynamic Logical Partitioning Nathan Fontenot
` (2 preceding siblings ...)
2009-10-21 14:44 ` [PATCH 3/5 v4] Export memory_sysdev_class Nathan Fontenot
@ 2009-10-21 14:46 ` Nathan Fontenot
2009-10-21 14:47 ` [PATCH 5/5 v4] Kernel Handling of cpu DLPAR Nathan Fontenot
4 siblings, 0 replies; 9+ messages in thread
From: Nathan Fontenot @ 2009-10-21 14:46 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-kernel
This adds the capability to DLPAR add and remove memory from the kernel. The
patch extends the powerpc handling of memory_add_physaddr_to_nid(), which is
called from the sysfs memory 'probe' file to first ensure that the memory
has been added to the system. This is done by creating a platform specific
callout from the routine. The pseries implementation of this handles the
DLPAR work to add the memory to the system and update the device tree.
The patch also creates a pseries only 'release' sys file,
/sys/devices/system/memory/release. This file handles the DLPAR release of
memory back to firmware and updating of the device-tree.
Signed-off-by: Nathan Fontenot <nfont at austin.ibm.com>
---
Index: powerpc/arch/powerpc/platforms/pseries/dlpar.c
===================================================================
--- powerpc.orig/arch/powerpc/platforms/pseries/dlpar.c 2009-10-19 11:59:10.000000000 -0500
+++ powerpc/arch/powerpc/platforms/pseries/dlpar.c 2009-10-19 11:59:43.000000000 -0500
@@ -16,6 +16,10 @@
#include <linux/notifier.h>
#include <linux/proc_fs.h>
#include <linux/spinlock.h>
+#include <linux/memory_hotplug.h>
+#include <linux/sysdev.h>
+#include <linux/sysfs.h>
+
#include <asm/prom.h>
#include <asm/machdep.h>
@@ -404,11 +408,186 @@
return 0;
}
+#ifdef CONFIG_MEMORY_HOTPLUG
+
+static struct property *clone_property(struct property *old_prop)
+{
+ struct property *new_prop;
+
+ new_prop = kzalloc((sizeof *new_prop), GFP_KERNEL);
+ if (!new_prop)
+ return NULL;
+
+ new_prop->name = kstrdup(old_prop->name, GFP_KERNEL);
+ new_prop->value = kzalloc(old_prop->length + 1, GFP_KERNEL);
+ if (!new_prop->name || !new_prop->value) {
+ free_property(new_prop);
+ return NULL;
+ }
+
+ memcpy(new_prop->value, old_prop->value, old_prop->length);
+ new_prop->length = old_prop->length;
+
+ return new_prop;
+}
+
+int platform_probe_memory(u64 phys_addr)
+{
+ struct device_node *dn = NULL;
+ struct property *new_prop;
+ struct property *old_prop;
+ struct of_drconf_cell *drmem;
+ const u64 *lmb_size;
+ int num_entries, i;
+ int rc = -EINVAL;
+
+ if (!phys_addr)
+ goto memory_probe_exit;
+
+ dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+ if (!dn)
+ goto memory_probe_exit;
+
+ lmb_size = of_get_property(dn, "ibm,lmb-size", NULL);
+ if (!lmb_size)
+ goto memory_probe_exit;
+
+ old_prop = of_find_property(dn, "ibm,dynamic-memory", NULL);
+ if (!old_prop)
+ goto memory_probe_exit;
+
+ num_entries = *(u32 *)old_prop->value;
+ drmem = (struct of_drconf_cell *)
+ ((char *)old_prop->value + sizeof(u32));
+
+ for (i = 0; i < num_entries; i++) {
+ u64 lmb_end_addr = drmem[i].base_addr + *lmb_size;
+ if (phys_addr >= drmem[i].base_addr
+ && phys_addr < lmb_end_addr)
+ break;
+ }
+
+ if (i >= num_entries)
+ goto memory_probe_exit;
+
+ if (drmem[i].flags & DRCONF_MEM_ASSIGNED) {
+ /* This lmb is already adssigned to the system, nothing to do */
+ rc = 0;
+ goto memory_probe_exit;
+ }
+
+ rc = acquire_drc(drmem[i].drc_index);
+ if (rc) {
+ rc = -EINVAL;
+ goto memory_probe_exit;
+ }
+
+ new_prop = clone_property(old_prop);
+ drmem = (struct of_drconf_cell *)
+ ((char *)new_prop->value + sizeof(u32));
+
+ drmem[i].flags |= DRCONF_MEM_ASSIGNED;
+ rc = prom_update_property(dn, new_prop, old_prop);
+ if (rc) {
+ free_property(new_prop);
+ rc = -EINVAL;
+ goto memory_probe_exit;
+ }
+
+ rc = blocking_notifier_call_chain(&pSeries_reconfig_chain,
+ PSERIES_DRCONF_MEM_ADD,
+ &drmem[i].base_addr);
+ if (rc == NOTIFY_BAD) {
+ prom_update_property(dn, old_prop, new_prop);
+ release_drc(drmem[i].drc_index);
+ rc = -EINVAL;
+ } else
+ rc = 0;
+
+memory_probe_exit:
+ of_node_put(dn);
+ return rc;
+}
+
+static ssize_t memory_release_store(struct class *class, const char *buf,
+ size_t count)
+{
+ unsigned long drc_index;
+ struct device_node *dn;
+ struct property *new_prop, *old_prop;
+ struct of_drconf_cell *drmem;
+ int num_entries;
+ int i;
+ int rc = -EINVAL;
+
+ rc = strict_strtoul(buf, 0, &drc_index);
+ if (rc)
+ return rc;
+
+ dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+ if (!dn)
+ return rc;
+
+ old_prop = of_find_property(dn, "ibm,dynamic-memory", NULL);
+ if (!old_prop)
+ goto memory_release_exit;
+
+ num_entries = *(u32 *)old_prop->value;
+ drmem = (struct of_drconf_cell *)
+ ((char *)old_prop->value + sizeof(u32));
+
+ for (i = 0; i < num_entries; i++) {
+ if (drmem[i].drc_index == drc_index)
+ break;
+ }
+
+ if (i >= num_entries)
+ goto memory_release_exit;
+
+ new_prop = clone_property(old_prop);
+ drmem = (struct of_drconf_cell *)
+ ((char *)new_prop->value + sizeof(u32));
+
+ drmem[i].flags &= ~DRCONF_MEM_ASSIGNED;
+ rc = prom_update_property(dn, new_prop, old_prop);
+ if (rc) {
+ free_property(new_prop);
+ rc = -EINVAL;
+ goto memory_release_exit;
+ }
+
+ rc = blocking_notifier_call_chain(&pSeries_reconfig_chain,
+ PSERIES_DRCONF_MEM_REMOVE,
+ &drmem[i].base_addr);
+ if (rc != NOTIFY_BAD)
+ rc = release_drc(drc_index);
+
+ if (rc) {
+ prom_update_property(dn, old_prop, new_prop);
+ rc = -EINVAL;
+ }
+
+memory_release_exit:
+ of_node_put(dn);
+ return rc ? rc : count;
+}
+
+static struct class_attribute class_attr_mem_release =
+ __ATTR(release, S_IWUSR, NULL, memory_release_store);
+#endif
+
static int pseries_dlpar_init(void)
{
if (!machine_is(pseries))
return 0;
+#ifdef CONFIG_MEMORY_HOTPLUG
+ if (sysfs_create_file(&memory_sysdev_class.kset.kobj,
+ &class_attr_mem_release.attr))
+ printk(KERN_INFO "DLPAR: Could not create sysfs memory "
+ "release file\n");
+#endif
+
return 0;
}
device_initcall(pseries_dlpar_init);
Index: powerpc/arch/powerpc/mm/mem.c
===================================================================
--- powerpc.orig/arch/powerpc/mm/mem.c 2009-10-19 11:58:38.000000000 -0500
+++ powerpc/arch/powerpc/mm/mem.c 2009-10-19 11:59:43.000000000 -0500
@@ -111,8 +111,19 @@
#ifdef CONFIG_MEMORY_HOTPLUG
#ifdef CONFIG_NUMA
+int __attribute ((weak)) platform_probe_memory(u64 start)
+{
+ return 0;
+}
+
int memory_add_physaddr_to_nid(u64 start)
{
+ int rc;
+
+ rc = platform_probe_memory(start);
+ if (rc)
+ return rc;
+
return hot_add_scn_to_nid(start);
}
#endif
^ permalink raw reply [flat|nested] 9+ messages in thread
* [PATCH 5/5 v4] Kernel Handling of cpu DLPAR
2009-10-21 14:35 [PATCH 0/5 v4] Kernel Handling of Dynamic Logical Partitioning Nathan Fontenot
` (3 preceding siblings ...)
2009-10-21 14:46 ` [PATCH 4/5 v4] Kernel Handling of memory DLPAR Nathan Fontenot
@ 2009-10-21 14:47 ` Nathan Fontenot
4 siblings, 0 replies; 9+ messages in thread
From: Nathan Fontenot @ 2009-10-21 14:47 UTC (permalink / raw)
To: linuxppc-dev; +Cc: linux-kernel
This adds the capability to DLPAR add and remove CPUs from the kernel. The
creates two new files /sys/devices/system/cpu/probe and
/sys/devices/system/cpu/release to handle the DLPAR addition and removal of
CPUs respectively.
CPU DLPAR add is accomplished by writing the drc-index of the CPU to the
probe file, and removal is done by writing the device-tree path of the cpu
to the release file.
Signed-off-by: Nathan Fontenot <nfont at austin.ibm.com>
---
Index: powerpc/arch/powerpc/platforms/pseries/dlpar.c
===================================================================
--- powerpc.orig/arch/powerpc/platforms/pseries/dlpar.c 2009-10-19 11:59:43.000000000 -0500
+++ powerpc/arch/powerpc/platforms/pseries/dlpar.c 2009-10-19 11:59:48.000000000 -0500
@@ -1,11 +1,10 @@
/*
- * dlpar.c - support for dynamic reconfiguration (including PCI
- * Hotplug and Dynamic Logical Partitioning on RPA platforms).
+ * Support for dynamic reconfiguration (including PCI, Memory, and CPU
+ * Hotplug and Dynamic Logical Partitioning on PAPR platforms).
*
* Copyright (C) 2009 Nathan Fontenot
* Copyright (C) 2009 IBM Corporation
*
- *
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
@@ -19,7 +18,7 @@
#include <linux/memory_hotplug.h>
#include <linux/sysdev.h>
#include <linux/sysfs.h>
-
+#include <linux/cpu.h>
#include <asm/prom.h>
#include <asm/machdep.h>
@@ -408,6 +407,82 @@
return 0;
}
+#ifdef CONFIG_HOTPLUG_CPU
+static ssize_t cpu_probe_store(struct class *class, const char *buf,
+ size_t count)
+{
+ struct device_node *dn;
+ unsigned long drc_index;
+ char *cpu_name;
+ int rc;
+
+ rc = strict_strtoul(buf, 0, &drc_index);
+ if (rc)
+ return -EINVAL;
+
+ rc = acquire_drc(drc_index);
+ if (rc)
+ return -EINVAL;
+
+ dn = configure_connector(drc_index);
+ if (!dn) {
+ release_drc(drc_index);
+ return -EINVAL;
+ }
+
+ /* fixup dn name */
+ cpu_name = kzalloc(strlen(dn->full_name) + strlen("/cpus/") + 1,
+ GFP_KERNEL);
+ if (!cpu_name) {
+ free_cc_nodes(dn);
+ release_drc(drc_index);
+ return -ENOMEM;
+ }
+
+ sprintf(cpu_name, "/cpus/%s", dn->full_name);
+ kfree(dn->full_name);
+ dn->full_name = cpu_name;
+
+ rc = add_device_tree_nodes(dn);
+ if (rc)
+ release_drc(drc_index);
+
+ return rc ? -EINVAL : count;
+}
+
+static ssize_t cpu_release_store(struct class *class, const char *buf,
+ size_t count)
+{
+ struct device_node *dn;
+ const u32 *drc_index;
+ int rc;
+
+ dn = of_find_node_by_path(buf);
+ if (!dn)
+ return -EINVAL;
+
+ drc_index = of_get_property(dn, "ibm,my-drc-index", NULL);
+ if (!drc_index) {
+ of_node_put(dn);
+ return -EINVAL;
+ }
+
+ rc = release_drc(*drc_index);
+ if (rc) {
+ of_node_put(dn);
+ return -EINVAL;
+ }
+
+ rc = remove_device_tree_nodes(dn);
+ if (rc)
+ acquire_drc(*drc_index);
+
+ of_node_put(dn);
+ return rc ? -EINVAL : count;
+}
+
+#endif /* CONFIG_HOTPLUG_CPU */
+
#ifdef CONFIG_MEMORY_HOTPLUG
static struct property *clone_property(struct property *old_prop)
@@ -574,6 +649,13 @@
static struct class_attribute class_attr_mem_release =
__ATTR(release, S_IWUSR, NULL, memory_release_store);
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
+#ifdef CONFIG_HOTPLUG_CPU
+static struct class_attribute class_attr_cpu_probe =
+ __ATTR(probe, S_IWUSR, NULL, cpu_probe_store);
+static struct class_attribute class_attr_cpu_release =
+ __ATTR(release, S_IWUSR, NULL, cpu_release_store);
#endif
static int pseries_dlpar_init(void)
@@ -588,6 +670,18 @@
"release file\n");
#endif
+#ifdef CONFIG_HOTPLUG_CPU
+ if (sysfs_create_file(&cpu_sysdev_class.kset.kobj,
+ &class_attr_cpu_probe.attr))
+ printk(KERN_INFO "DLPAR: Could not create sysfs cpu "
+ "probe file\n");
+
+ if (sysfs_create_file(&cpu_sysdev_class.kset.kobj,
+ &class_attr_cpu_release.attr))
+ printk(KERN_INFO "DLPAR: Could not create sysfs cpu "
+ "release file\n");
+#endif
+
return 0;
}
device_initcall(pseries_dlpar_init);
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/5 v4] Export memory_sysdev_class
2009-10-21 14:44 ` [PATCH 3/5 v4] Export memory_sysdev_class Nathan Fontenot
@ 2009-10-21 16:03 ` Dave Hansen
2009-10-22 15:31 ` Nathan Fontenot
0 siblings, 1 reply; 9+ messages in thread
From: Dave Hansen @ 2009-10-21 16:03 UTC (permalink / raw)
To: Nathan Fontenot; +Cc: linuxppc-dev, linux-kernel
On Wed, 2009-10-21 at 09:44 -0500, Nathan Fontenot wrote:
> Export the memory_sysdev_class structure. This is needed so we can create
> a 'release' file in sysfs in addition to the existing 'probe' file in
> order to support DLPAR removal of memory on the powerpc/pseries platform.
> The new 'release' file will be powerpc/pseries only.
Please do it in generic code. You may only need it on ppc today, but
somebody else is going to want the same thing tomorrow on another arch.
It's also nice to keep all of the stuff doing the actual sysfs munging
in one place. I know it'll cost a few stubs for calling in and out of
arch code, but it should save some work down the road for somebody else.
-- Dave
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/5 v4] Export memory_sysdev_class
2009-10-21 16:03 ` Dave Hansen
@ 2009-10-22 15:31 ` Nathan Fontenot
2009-10-22 15:56 ` Dave Hansen
0 siblings, 1 reply; 9+ messages in thread
From: Nathan Fontenot @ 2009-10-22 15:31 UTC (permalink / raw)
To: Dave Hansen; +Cc: linuxppc-dev, linux-kernel
Dave Hansen wrote:
> On Wed, 2009-10-21 at 09:44 -0500, Nathan Fontenot wrote:
>> Export the memory_sysdev_class structure. This is needed so we can create
>> a 'release' file in sysfs in addition to the existing 'probe' file in
>> order to support DLPAR removal of memory on the powerpc/pseries platform.
>> The new 'release' file will be powerpc/pseries only.
>
> Please do it in generic code. You may only need it on ppc today, but
> somebody else is going to want the same thing tomorrow on another arch.
I thought about this but wasn't sure if having the probe/release sysfs files
for memory and cpu be in generic code would be accepted.
Would it be acceptable to put the new release file for memory under the
ARCH_MEMORY_PROBE config option? This would reduce the number of arch'es
that would require stubs as it appears only powerpc and x86 define this.
I could do the same thing for the cpu probe/release files and a new
ARCH_CPU_PROBE config option which would eliminate the required stubs
in arch'es other than powerpc right now.
-Nathan Fontenot
>
> It's also nice to keep all of the stuff doing the actual sysfs munging
> in one place. I know it'll cost a few stubs for calling in and out of
> arch code, but it should save some work down the road for somebody else.
>
> -- Dave
>
^ permalink raw reply [flat|nested] 9+ messages in thread
* Re: [PATCH 3/5 v4] Export memory_sysdev_class
2009-10-22 15:31 ` Nathan Fontenot
@ 2009-10-22 15:56 ` Dave Hansen
0 siblings, 0 replies; 9+ messages in thread
From: Dave Hansen @ 2009-10-22 15:56 UTC (permalink / raw)
To: Nathan Fontenot; +Cc: linuxppc-dev, linux-kernel
On Thu, 2009-10-22 at 10:31 -0500, Nathan Fontenot wrote:
> Dave Hansen wrote:
> > On Wed, 2009-10-21 at 09:44 -0500, Nathan Fontenot wrote:
> >> Export the memory_sysdev_class structure. This is needed so we can create
> >> a 'release' file in sysfs in addition to the existing 'probe' file in
> >> order to support DLPAR removal of memory on the powerpc/pseries platform.
> >> The new 'release' file will be powerpc/pseries only.
> >
> > Please do it in generic code. You may only need it on ppc today, but
> > somebody else is going to want the same thing tomorrow on another arch.
>
> I thought about this but wasn't sure if having the probe/release sysfs files
> for memory and cpu be in generic code would be accepted.
Although we don't want to pollute the generic code with lots of per-arch
cruft, this still looks pretty generic to me. It is also really nice to
have all of the sysfs files for one directory be in a single place in
the source.
> Would it be acceptable to put the new release file for memory under the
> ARCH_MEMORY_PROBE config option?
That sounds fine to me. It may need a slightly tuned name if you can
think of anything better. I can't off the top of my head.
x86's is really only there for testing reasons. I would use mem= to
shrink a machine's memory at boot then use the probe file to re-add it
later. I did that before I had hardware that could do real hotplug.
> This would reduce the number of arch'es
> that would require stubs as it appears only powerpc and x86 define this.
Yeah, that'd be a nice side-effect I guess.
-- Dave
^ permalink raw reply [flat|nested] 9+ messages in thread
end of thread, other threads:[~2009-10-22 15:56 UTC | newest]
Thread overview: 9+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2009-10-21 14:35 [PATCH 0/5 v4] Kernel Handling of Dynamic Logical Partitioning Nathan Fontenot
2009-10-21 14:40 ` [PATCH 1/5 " Nathan Fontenot
2009-10-21 14:42 ` [PATCH 2/5 v4] move of_drconf_cell definition to prom.h Nathan Fontenot
2009-10-21 14:44 ` [PATCH 3/5 v4] Export memory_sysdev_class Nathan Fontenot
2009-10-21 16:03 ` Dave Hansen
2009-10-22 15:31 ` Nathan Fontenot
2009-10-22 15:56 ` Dave Hansen
2009-10-21 14:46 ` [PATCH 4/5 v4] Kernel Handling of memory DLPAR Nathan Fontenot
2009-10-21 14:47 ` [PATCH 5/5 v4] Kernel Handling of cpu DLPAR Nathan Fontenot
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).