linuxppc-dev.lists.ozlabs.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 0/6] powerpc/pseries: Move CPU DLPAR into the kernel
@ 2015-10-27 18:21 Nathan Fontenot
  2015-10-27 18:23 ` [PATCH v2 1/6] powerpc/pseries: Consolidate CPU hotplug code to hotplug-cpu.c Nathan Fontenot
                   ` (5 more replies)
  0 siblings, 6 replies; 11+ messages in thread
From: Nathan Fontenot @ 2015-10-27 18:21 UTC (permalink / raw)
  To: linuxppc-dev

To better support CPU hotplug in PowerKVM and PowerVM environments, the
handling of CPU dlpar should be done entirely in the kernel. This will allow
a common entry point to be used for PowerVM and PowerKVM CPU dlpar requests.

For both environments the entry point is the same one introduced in a previous
patch set that moved memory hotplug into the kernel. This entry point accepts
a rtas hotplug event which is either constructed when using the 
/sys/kernel/dlpar interface or is passed to the kernel when handling a
ras epow interrupt.

Note: The patches are based on top of two previous patches I sent out;

[PATCH] powerpc/pseries: Verify CPU doesn't exist before adding
https://lists.ozlabs.org/pipermail/linuxppc-dev/2015-October/135550.html 

[PATCH v2] powerpc/pseries: Correct string length in pseries_of_derive_parent()
https://lists.ozlabs.org/pipermail/linuxppc-dev/2015-October/135667.html

-Nathan

Patch 1/6:
- Consolidate cpu hotplug code from pseries/dlpar.c to pseries/hotplug-cpu.c

Patch 2/6:
- Factor out common code pieces for both environments

Patch 3/6:
- Update cpu dlpar error recovery

Patch 4/6:
- Add cpu hotplug remove capability

Patch 5/6:
- Add cpu hotplug add capability

Patch 6/6:
- Enable sysfs interface for cpu hotplug

 dlpar.c       |  232 ----------------------
 hotplug-cpu.c |  596 +++++++++++++++++++++++++++++++++++++++++++++++++++++-----
 pseries.h     |    9 
 3 files changed, 568 insertions(+), 269 deletions(-)

^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH v2 1/6] powerpc/pseries: Consolidate CPU hotplug code to hotplug-cpu.c
  2015-10-27 18:21 [PATCH v2 0/6] powerpc/pseries: Move CPU DLPAR into the kernel Nathan Fontenot
@ 2015-10-27 18:23 ` Nathan Fontenot
  2015-10-27 18:24 ` [PATCH v2 2/6] powerpc/pseries: Factor out common cpu hotplug code Nathan Fontenot
                   ` (4 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Nathan Fontenot @ 2015-10-27 18:23 UTC (permalink / raw)
  To: linuxppc-dev

No functional changes, this patch is simply a move of the cpu hotplug
code from pseries/dlpar.c to pseries/hotplug-cpu.c. This is in an effort
to consolidate all of the cpu hotplug code in a common place.

Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/pseries/dlpar.c       |  226 --------------------------
 arch/powerpc/platforms/pseries/hotplug-cpu.c |  218 +++++++++++++++++++++++++
 2 files changed, 219 insertions(+), 225 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index fe6320d..438fdbd 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -20,7 +20,6 @@
 #include <linux/of.h>
 
 #include "of_helpers.h"
-#include "offline_states.h"
 #include "pseries.h"
 
 #include <asm/prom.h>
@@ -338,220 +337,6 @@ int dlpar_release_drc(u32 drc_index)
 	return 0;
 }
 
-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
-
-static int dlpar_online_cpu(struct device_node *dn)
-{
-	int rc = 0;
-	unsigned int cpu;
-	int len, nthreads, i;
-	const __be32 *intserv;
-	u32 thread;
-
-	intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
-	if (!intserv)
-		return -EINVAL;
-
-	nthreads = len / sizeof(u32);
-
-	cpu_maps_update_begin();
-	for (i = 0; i < nthreads; i++) {
-		thread = be32_to_cpu(intserv[i]);
-		for_each_present_cpu(cpu) {
-			if (get_hard_smp_processor_id(cpu) != thread)
-				continue;
-			BUG_ON(get_cpu_current_state(cpu)
-					!= CPU_STATE_OFFLINE);
-			cpu_maps_update_done();
-			rc = device_online(get_cpu_device(cpu));
-			if (rc)
-				goto out;
-			cpu_maps_update_begin();
-
-			break;
-		}
-		if (cpu == num_possible_cpus())
-			printk(KERN_WARNING "Could not find cpu to online "
-			       "with physical id 0x%x\n", thread);
-	}
-	cpu_maps_update_done();
-
-out:
-	return rc;
-
-}
-
-static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index)
-{
-	struct device_node *child = NULL;
-	u32 my_drc_index;
-	bool found;
-	int rc;
-
-	/* Assume cpu doesn't exist */
-	found = false;
-
-	for_each_child_of_node(parent, child) {
-		rc = of_property_read_u32(child, "ibm,my-drc-index",
-					  &my_drc_index);
-		if (rc)
-			continue;
-
-		if (my_drc_index == drc_index) {
-			of_node_put(child);
-			found = true;
-			break;
-		}
-	}
-
-	return found;
-}
-
-static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
-{
-	struct device_node *dn, *parent;
-	u32 drc_index;
-	int rc;
-
-	rc = kstrtou32(buf, 0, &drc_index);
-	if (rc)
-		return -EINVAL;
-
-	parent = of_find_node_by_path("/cpus");
-	if (!parent)
-		return -ENODEV;
-
-	if (dlpar_cpu_exists(parent, drc_index)) {
-		of_node_put(parent);
-		printk(KERN_WARNING "CPU with drc index %x already exists\n",
-		       drc_index);
-		return -EINVAL;
-	}
-
-	rc = dlpar_acquire_drc(drc_index);
-	if (rc) {
-		of_node_put(parent);
-		return -EINVAL;
-	}
-
-	dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
-	of_node_put(parent);
-	if (!dn) {
-		dlpar_release_drc(drc_index);
-		return -EINVAL;
-	}
-
-	rc = dlpar_attach_node(dn);
-	if (rc) {
-		dlpar_release_drc(drc_index);
-		dlpar_free_cc_nodes(dn);
-		return rc;
-	}
-
-	rc = dlpar_online_cpu(dn);
-	if (rc)
-		return rc;
-
-	return count;
-}
-
-static int dlpar_offline_cpu(struct device_node *dn)
-{
-	int rc = 0;
-	unsigned int cpu;
-	int len, nthreads, i;
-	const __be32 *intserv;
-	u32 thread;
-
-	intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
-	if (!intserv)
-		return -EINVAL;
-
-	nthreads = len / sizeof(u32);
-
-	cpu_maps_update_begin();
-	for (i = 0; i < nthreads; i++) {
-		thread = be32_to_cpu(intserv[i]);
-		for_each_present_cpu(cpu) {
-			if (get_hard_smp_processor_id(cpu) != thread)
-				continue;
-
-			if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE)
-				break;
-
-			if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) {
-				set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
-				cpu_maps_update_done();
-				rc = device_offline(get_cpu_device(cpu));
-				if (rc)
-					goto out;
-				cpu_maps_update_begin();
-				break;
-
-			}
-
-			/*
-			 * The cpu is in CPU_STATE_INACTIVE.
-			 * Upgrade it's state to CPU_STATE_OFFLINE.
-			 */
-			set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
-			BUG_ON(plpar_hcall_norets(H_PROD, thread)
-								!= H_SUCCESS);
-			__cpu_die(cpu);
-			break;
-		}
-		if (cpu == num_possible_cpus())
-			printk(KERN_WARNING "Could not find cpu to offline "
-			       "with physical id 0x%x\n", thread);
-	}
-	cpu_maps_update_done();
-
-out:
-	return rc;
-
-}
-
-static ssize_t dlpar_cpu_release(const char *buf, size_t count)
-{
-	struct device_node *dn;
-	u32 drc_index;
-	int rc;
-
-	dn = of_find_node_by_path(buf);
-	if (!dn)
-		return -EINVAL;
-
-	rc = of_property_read_u32(dn, "ibm,my-drc-index", &drc_index);
-	if (rc) {
-		of_node_put(dn);
-		return -EINVAL;
-	}
-
-	rc = dlpar_offline_cpu(dn);
-	if (rc) {
-		of_node_put(dn);
-		return -EINVAL;
-	}
-
-	rc = dlpar_release_drc(drc_index);
-	if (rc) {
-		of_node_put(dn);
-		return rc;
-	}
-
-	rc = dlpar_detach_node(dn);
-	if (rc) {
-		dlpar_acquire_drc(drc_index);
-		return rc;
-	}
-
-	of_node_put(dn);
-
-	return count;
-}
-
-#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
-
 static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
 {
 	int rc;
@@ -659,16 +444,7 @@ static CLASS_ATTR(dlpar, S_IWUSR, NULL, dlpar_store);
 
 static int __init pseries_dlpar_init(void)
 {
-	int rc;
-
-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
-	ppc_md.cpu_probe = dlpar_cpu_probe;
-	ppc_md.cpu_release = dlpar_cpu_release;
-#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
-
-	rc = sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
-
-	return rc;
+	return sysfs_create_file(kernel_kobj, &class_attr_dlpar.attr);
 }
 machine_device_initcall(pseries, pseries_dlpar_init);
 
diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 6247544..10c2942 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -32,6 +32,7 @@
 #include <asm/xics.h>
 #include <asm/plpar_wrappers.h>
 
+#include "pseries.h"
 #include "offline_states.h"
 
 /* This version can't take the spinlock, because it never returns */
@@ -339,6 +340,218 @@ static void pseries_remove_processor(struct device_node *np)
 	cpu_maps_update_done();
 }
 
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
+
+static int dlpar_online_cpu(struct device_node *dn)
+{
+	int rc = 0;
+	unsigned int cpu;
+	int len, nthreads, i;
+	const __be32 *intserv;
+	u32 thread;
+
+	intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+	if (!intserv)
+		return -EINVAL;
+
+	nthreads = len / sizeof(u32);
+
+	cpu_maps_update_begin();
+	for (i = 0; i < nthreads; i++) {
+		thread = be32_to_cpu(intserv[i]);
+		for_each_present_cpu(cpu) {
+			if (get_hard_smp_processor_id(cpu) != thread)
+				continue;
+			BUG_ON(get_cpu_current_state(cpu)
+					!= CPU_STATE_OFFLINE);
+			cpu_maps_update_done();
+			rc = device_online(get_cpu_device(cpu));
+			if (rc)
+				goto out;
+			cpu_maps_update_begin();
+
+			break;
+		}
+		if (cpu == num_possible_cpus())
+			printk(KERN_WARNING "Could not find cpu to online "
+			       "with physical id 0x%x\n", thread);
+	}
+	cpu_maps_update_done();
+
+out:
+	return rc;
+
+}
+
+static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index)
+{
+	struct device_node *child = NULL;
+	u32 my_drc_index;
+	bool found;
+	int rc;
+
+	/* Assume cpu doesn't exist */
+	found = false;
+
+	for_each_child_of_node(parent, child) {
+		rc = of_property_read_u32(child, "ibm,my-drc-index",
+					  &my_drc_index);
+		if (rc)
+			continue;
+
+		if (my_drc_index == drc_index) {
+			of_node_put(child);
+			found = true;
+			break;
+		}
+	}
+
+	return found;
+}
+
+static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
+{
+	struct device_node *dn, *parent;
+	u32 drc_index;
+	int rc;
+
+	rc = kstrtou32(buf, 0, &drc_index);
+	if (rc)
+		return -EINVAL;
+
+	parent = of_find_node_by_path("/cpus");
+	if (!parent)
+		return -ENODEV;
+
+	if (dlpar_cpu_exists(parent, drc_index)) {
+		of_node_put(parent);
+		printk(KERN_WARNING "CPU with drc index %x already exists\n",
+		       drc_index);
+		return -EINVAL;
+	}
+
+	rc = dlpar_acquire_drc(drc_index);
+	if (rc) {
+		of_node_put(parent);
+		return -EINVAL;
+	}
+
+	dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
+	of_node_put(parent);
+	if (!dn)
+		return -EINVAL;
+
+	rc = dlpar_attach_node(dn);
+	if (rc) {
+		dlpar_release_drc(drc_index);
+		dlpar_free_cc_nodes(dn);
+		return rc;
+	}
+
+	rc = dlpar_online_cpu(dn);
+	if (rc)
+		return rc;
+
+	return count;
+}
+
+static int dlpar_offline_cpu(struct device_node *dn)
+{
+	int rc = 0;
+	unsigned int cpu;
+	int len, nthreads, i;
+	const __be32 *intserv;
+	u32 thread;
+
+	intserv = of_get_property(dn, "ibm,ppc-interrupt-server#s", &len);
+	if (!intserv)
+		return -EINVAL;
+
+	nthreads = len / sizeof(u32);
+
+	cpu_maps_update_begin();
+	for (i = 0; i < nthreads; i++) {
+		thread = be32_to_cpu(intserv[i]);
+		for_each_present_cpu(cpu) {
+			if (get_hard_smp_processor_id(cpu) != thread)
+				continue;
+
+			if (get_cpu_current_state(cpu) == CPU_STATE_OFFLINE)
+				break;
+
+			if (get_cpu_current_state(cpu) == CPU_STATE_ONLINE) {
+				set_preferred_offline_state(cpu,
+							    CPU_STATE_OFFLINE);
+				cpu_maps_update_done();
+				rc = device_offline(get_cpu_device(cpu));
+				if (rc)
+					goto out;
+				cpu_maps_update_begin();
+				break;
+
+			}
+
+			/*
+			 * The cpu is in CPU_STATE_INACTIVE.
+			 * Upgrade it's state to CPU_STATE_OFFLINE.
+			 */
+			set_preferred_offline_state(cpu, CPU_STATE_OFFLINE);
+			BUG_ON(plpar_hcall_norets(H_PROD, thread)
+								!= H_SUCCESS);
+			__cpu_die(cpu);
+			break;
+		}
+		if (cpu == num_possible_cpus())
+			printk(KERN_WARNING "Could not find cpu to offline with physical id 0x%x\n", thread);
+	}
+	cpu_maps_update_done();
+
+out:
+	return rc;
+
+}
+
+static ssize_t dlpar_cpu_release(const char *buf, size_t count)
+{
+	struct device_node *dn;
+	u32 drc_index;
+	int rc;
+
+	dn = of_find_node_by_path(buf);
+	if (!dn)
+		return -EINVAL;
+
+	rc = of_property_read_u32(dn, "ibm,my-drc-index", &drc_index);
+	if (rc) {
+		of_node_put(dn);
+		return -EINVAL;
+	}
+
+	rc = dlpar_offline_cpu(dn);
+	if (rc) {
+		of_node_put(dn);
+		return -EINVAL;
+	}
+
+	rc = dlpar_release_drc(drc_index);
+	if (rc) {
+		of_node_put(dn);
+		return rc;
+	}
+
+	rc = dlpar_detach_node(dn);
+	if (rc) {
+		dlpar_acquire_drc(drc_index);
+		return rc;
+	}
+
+	of_node_put(dn);
+
+	return count;
+}
+
+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
+
 static int pseries_smp_notifier(struct notifier_block *nb,
 				unsigned long action, void *data)
 {
@@ -385,6 +598,11 @@ static int __init pseries_cpu_hotplug_init(void)
 	int cpu;
 	int qcss_tok;
 
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
+	ppc_md.cpu_probe = dlpar_cpu_probe;
+	ppc_md.cpu_release = dlpar_cpu_release;
+#endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */
+
 	for_each_node_by_name(np, "interrupt-controller") {
 		typep = of_get_property(np, "compatible", NULL);
 		if (strstr(typep, "open-pic")) {

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 2/6] powerpc/pseries: Factor out common cpu hotplug code
  2015-10-27 18:21 [PATCH v2 0/6] powerpc/pseries: Move CPU DLPAR into the kernel Nathan Fontenot
  2015-10-27 18:23 ` [PATCH v2 1/6] powerpc/pseries: Consolidate CPU hotplug code to hotplug-cpu.c Nathan Fontenot
@ 2015-10-27 18:24 ` Nathan Fontenot
  2015-10-27 18:25 ` [PATCH v2 3/6] powerpc/pseries: Update CPU hotplug error recovery Nathan Fontenot
                   ` (3 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Nathan Fontenot @ 2015-10-27 18:24 UTC (permalink / raw)
  To: linuxppc-dev

Re-factor the cpu hotplug code to support doing cpu hotplug completely in
the kernel and using the existing sysfs probe/release interfaces. This
patch pulls out pieces of existing cpu hotplug code into common routines,
dlpar_cpu_add() and dlpar_cpu_remove(), to be used by both interfaces.
There are no functional changes introduced.

Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/pseries/hotplug-cpu.c |   70 ++++++++++++++------------
 1 file changed, 39 insertions(+), 31 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 10c2942..d6cb184 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -340,8 +340,6 @@ static void pseries_remove_processor(struct device_node *np)
 	cpu_maps_update_done();
 }
 
-#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
-
 static int dlpar_online_cpu(struct device_node *dn)
 {
 	int rc = 0;
@@ -409,16 +407,11 @@ static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index)
 	return found;
 }
 
-static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
+static ssize_t dlpar_cpu_add(u32 drc_index)
 {
 	struct device_node *dn, *parent;
-	u32 drc_index;
 	int rc;
 
-	rc = kstrtou32(buf, 0, &drc_index);
-	if (rc)
-		return -EINVAL;
-
 	parent = of_find_node_by_path("/cpus");
 	if (!parent)
 		return -ENODEV;
@@ -449,10 +442,7 @@ static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
 	}
 
 	rc = dlpar_online_cpu(dn);
-	if (rc)
-		return rc;
-
-	return count;
+	return rc;
 }
 
 static int dlpar_offline_cpu(struct device_node *dn)
@@ -511,6 +501,41 @@ out:
 
 }
 
+static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index)
+{
+	int rc;
+
+	rc = dlpar_offline_cpu(dn);
+	if (rc)
+		return -EINVAL;
+
+	rc = dlpar_release_drc(drc_index);
+	if (rc)
+		return rc;
+
+	rc = dlpar_detach_node(dn);
+	if (rc)
+		dlpar_acquire_drc(drc_index);
+
+	return rc;
+}
+
+#ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
+
+static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
+{
+	u32 drc_index;
+	int rc;
+
+	rc = kstrtou32(buf, 0, &drc_index);
+	if (rc)
+		return -EINVAL;
+
+	rc = dlpar_cpu_add(drc_index);
+
+	return rc ? rc : count;
+}
+
 static ssize_t dlpar_cpu_release(const char *buf, size_t count)
 {
 	struct device_node *dn;
@@ -527,27 +552,10 @@ static ssize_t dlpar_cpu_release(const char *buf, size_t count)
 		return -EINVAL;
 	}
 
-	rc = dlpar_offline_cpu(dn);
-	if (rc) {
-		of_node_put(dn);
-		return -EINVAL;
-	}
-
-	rc = dlpar_release_drc(drc_index);
-	if (rc) {
-		of_node_put(dn);
-		return rc;
-	}
-
-	rc = dlpar_detach_node(dn);
-	if (rc) {
-		dlpar_acquire_drc(drc_index);
-		return rc;
-	}
-
+	rc = dlpar_cpu_remove(dn, drc_index);
 	of_node_put(dn);
 
-	return count;
+	return rc ? rc : count;
 }
 
 #endif /* CONFIG_ARCH_CPU_PROBE_RELEASE */

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 3/6] powerpc/pseries: Update CPU hotplug error recovery
  2015-10-27 18:21 [PATCH v2 0/6] powerpc/pseries: Move CPU DLPAR into the kernel Nathan Fontenot
  2015-10-27 18:23 ` [PATCH v2 1/6] powerpc/pseries: Consolidate CPU hotplug code to hotplug-cpu.c Nathan Fontenot
  2015-10-27 18:24 ` [PATCH v2 2/6] powerpc/pseries: Factor out common cpu hotplug code Nathan Fontenot
@ 2015-10-27 18:25 ` Nathan Fontenot
  2015-10-27 18:26 ` [PATCH v2 4/6] powerpc/pseries: Add CPU dlpar remove functionality Nathan Fontenot
                   ` (2 subsequent siblings)
  5 siblings, 0 replies; 11+ messages in thread
From: Nathan Fontenot @ 2015-10-27 18:25 UTC (permalink / raw)
  To: linuxppc-dev

Update the cpu dlpar add/remove paths to do better error recovery when
a failure occurs during the add/remove operation.

Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---

Updates for v2:
- Corrected some pr_* statements moving pr_info to pr_debug staements
  and pr_debug to pr_warn statements.

 arch/powerpc/platforms/pseries/hotplug-cpu.c |   76 ++++++++++++++++++++++----
 1 file changed, 63 insertions(+), 13 deletions(-)

diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index d6cb184..f080e81 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -18,6 +18,8 @@
  *      2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt)     "pseries-hotplug-cpu: " fmt
+
 #include <linux/kernel.h>
 #include <linux/interrupt.h>
 #include <linux/delay.h>
@@ -410,38 +412,67 @@ static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index)
 static ssize_t dlpar_cpu_add(u32 drc_index)
 {
 	struct device_node *dn, *parent;
-	int rc;
+	int rc, saved_rc;
+
+	pr_debug("Attempting to add CPU, drc index: %x\n", drc_index);
 
 	parent = of_find_node_by_path("/cpus");
-	if (!parent)
+	if (!parent) {
+		pr_warn("Failed to find CPU root node \"/cpus\"\n");
 		return -ENODEV;
+	}
 
 	if (dlpar_cpu_exists(parent, drc_index)) {
 		of_node_put(parent);
-		printk(KERN_WARNING "CPU with drc index %x already exists\n",
-		       drc_index);
+		pr_warn("CPU with drc index %x already exists\n", drc_index);
 		return -EINVAL;
 	}
 
 	rc = dlpar_acquire_drc(drc_index);
 	if (rc) {
+		pr_warn("Failed to acquire DRC, rc: %d, drc index: %x\n",
+			rc, drc_index);
 		of_node_put(parent);
 		return -EINVAL;
 	}
 
 	dn = dlpar_configure_connector(cpu_to_be32(drc_index), parent);
 	of_node_put(parent);
-	if (!dn)
+	if (!dn) {
+		pr_warn("Failed call to configure-connector, drc index: %x\n",
+			drc_index);
+		dlpar_release_drc(drc_index);
 		return -EINVAL;
+	}
 
 	rc = dlpar_attach_node(dn);
 	if (rc) {
-		dlpar_release_drc(drc_index);
-		dlpar_free_cc_nodes(dn);
-		return rc;
+		saved_rc = rc;
+		pr_warn("Failed to attach node %s, rc: %d, drc index: %x\n",
+			dn->name, rc, drc_index);
+
+		rc = dlpar_release_drc(drc_index);
+		if (!rc)
+			dlpar_free_cc_nodes(dn);
+
+		return saved_rc;
 	}
 
 	rc = dlpar_online_cpu(dn);
+	if (rc) {
+		saved_rc = rc;
+		pr_warn("Failed to online cpu %s, rc: %d, drc index: %x\n",
+			dn->name, rc, drc_index);
+
+		rc = dlpar_detach_node(dn);
+		if (!rc)
+			dlpar_release_drc(drc_index);
+
+		return saved_rc;
+	}
+
+	pr_debug("Successfully added CPU %s, drc index: %x\n", dn->name,
+		 drc_index);
 	return rc;
 }
 
@@ -505,19 +536,38 @@ static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index)
 {
 	int rc;
 
+	pr_debug("Attemping to remove CPU %s, drc index: %x\n",
+		 dn->name, drc_index);
+
 	rc = dlpar_offline_cpu(dn);
-	if (rc)
+	if (rc) {
+		pr_warn("Failed to offline CPU %s, rc: %d\n", dn->name, rc);
 		return -EINVAL;
+	}
 
 	rc = dlpar_release_drc(drc_index);
-	if (rc)
+	if (rc) {
+		pr_warn("Failed to release drc (%x) for CPU %s, rc: %d\n",
+			drc_index, dn->name, rc);
+		dlpar_online_cpu(dn);
 		return rc;
+	}
 
 	rc = dlpar_detach_node(dn);
-	if (rc)
-		dlpar_acquire_drc(drc_index);
+	if (rc) {
+		int saved_rc = rc;
 
-	return rc;
+		pr_warn("Failed to detach CPU %s, rc: %d", dn->name, rc);
+
+		rc = dlpar_acquire_drc(drc_index);
+		if (!rc)
+			dlpar_online_cpu(dn);
+
+		return saved_rc;
+	}
+
+	pr_debug("Successfully removed CPU, drc index: %x\n", drc_index);
+	return 0;
 }
 
 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 4/6] powerpc/pseries: Add CPU dlpar remove functionality
  2015-10-27 18:21 [PATCH v2 0/6] powerpc/pseries: Move CPU DLPAR into the kernel Nathan Fontenot
                   ` (2 preceding siblings ...)
  2015-10-27 18:25 ` [PATCH v2 3/6] powerpc/pseries: Update CPU hotplug error recovery Nathan Fontenot
@ 2015-10-27 18:26 ` Nathan Fontenot
  2015-11-26  5:02   ` Michael Ellerman
  2015-10-27 18:27 ` [PATCH v2 5/6] powerpc/pseries: Add CPU dlpar add functionality Nathan Fontenot
  2015-10-27 18:28 ` [PATCH v2 6/6] powerpc/pseries: Enable kernel CPU dlpar from sysfs Nathan Fontenot
  5 siblings, 1 reply; 11+ messages in thread
From: Nathan Fontenot @ 2015-10-27 18:26 UTC (permalink / raw)
  To: linuxppc-dev

Add the ability to dlpar remove CPUs via hotplug rtas events, either by
specifying the drc-index of the CPU to remove or providing a count of cpus
to remove.

To remove multiple cpus in a single request we create a list of possible
DR (Dynamic Reconfiguration) cpus and their drc indexes that can be
removed.  We can then traverse the list remove each cpu and easily clean
up in any cases of failure.

Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---

Updates for v2:
- use for_each_node_by_type() instead of for_each_child_of_node
- updated how the list of cpus to remove is generated
- change to remove all cpus requested or none at all
- put function declarations under CONFIG_HOTPLUG_CPU

 arch/powerpc/platforms/pseries/hotplug-cpu.c |  138 ++++++++++++++++++++++++++
 arch/powerpc/platforms/pseries/pseries.h     |    9 ++
 2 files changed, 147 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index f080e81..635f0ba 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -26,6 +26,7 @@
 #include <linux/sched.h>	/* for idle_task_exit */
 #include <linux/cpu.h>
 #include <linux/of.h>
+#include <linux/slab.h>
 #include <asm/prom.h>
 #include <asm/rtas.h>
 #include <asm/firmware.h>
@@ -570,6 +571,143 @@ static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index)
 	return 0;
 }
 
+static struct device_node *cpu_drc_index_to_dn(u32 drc_index)
+{
+	struct device_node *dn;
+	u32 my_index;
+	int rc;
+
+	for_each_node_by_type(dn, "cpu") {
+		rc = of_property_read_u32(dn, "ibm,my-drc-index", &my_index);
+		if (rc)
+			continue;
+
+		if (my_index == drc_index)
+			break;
+	}
+
+	return dn;
+}
+
+static int dlpar_cpu_remove_by_index(u32 drc_index)
+{
+	struct device_node *dn;
+	int rc;
+
+	dn = cpu_drc_index_to_dn(drc_index);
+	if (!dn)
+		return -ENODEV;
+
+	rc = dlpar_cpu_remove(dn, drc_index);
+	of_node_put(dn);
+	return rc;
+}
+
+static u32 *dlpar_cpus_to_remove(int cpus_to_remove)
+{
+	struct device_node *dn;
+	u32 *cpu_drcs;
+	int cpus_found = 0;
+	int i, rc;
+
+	cpu_drcs = kcalloc(cpus_to_remove, sizeof(*cpu_drcs), GFP_KERNEL);
+	if (!cpu_drcs)
+		return NULL;
+
+	i = 0;
+	for_each_node_by_type(dn, "cpu") {
+		cpus_found++;
+
+		if (cpus_found > cpus_to_remove) {
+			of_node_put(dn);
+			break;
+		}
+
+		rc = of_property_read_u32(dn, "ibm,my-drc-index",
+					  &cpu_drcs[i++]);
+		if (rc) {
+			of_node_put(dn);
+			break;
+		}
+	}
+
+	/* We want to find cpus_to_remove + 1 CPUs to ensure we do not
+	 * remove the last CPU.
+	 */
+	if (cpus_found <= cpus_to_remove) {
+		pr_warn("Failed to find enough CPUs (%d of %d) to remove\n",
+			cpus_found, cpus_to_remove);
+		kfree(cpu_drcs);
+		cpu_drcs = NULL;
+	}
+
+	return cpu_drcs;
+}
+
+static int dlpar_cpu_remove_by_count(u32 cpus_to_remove)
+{
+	u32 *cpu_drcs;
+	int cpus_removed = 0;
+	int i, rc;
+
+	pr_debug("Attempting to hot-remove %d CPUs\n", cpus_to_remove);
+
+	cpu_drcs = dlpar_cpus_to_remove(cpus_to_remove);
+	if (!cpu_drcs)
+		return -EINVAL;
+
+	for (i = 0; i < cpus_to_remove; i++) {
+		rc = dlpar_cpu_remove_by_index(cpu_drcs[i]);
+		if (rc)
+			break;
+
+		cpus_removed++;
+	}
+
+	if (cpus_removed != cpus_to_remove) {
+		pr_warn("CPU hot-remove failed, adding back removed CPUs\n");
+
+		for (i = 0; i < cpus_removed; i++)
+			dlpar_cpu_add(cpu_drcs[i]);
+
+		rc = -EINVAL;
+	} else {
+		rc = 0;
+	}
+
+	kfree(cpu_drcs);
+	return rc;
+}
+
+int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
+{
+	u32 count, drc_index;
+	int rc;
+
+	count = hp_elog->_drc_u.drc_count;
+	drc_index = hp_elog->_drc_u.drc_index;
+
+	lock_device_hotplug();
+
+	switch (hp_elog->action) {
+	case PSERIES_HP_ELOG_ACTION_REMOVE:
+		if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT)
+			rc = dlpar_cpu_remove_by_count(count);
+		else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX)
+			rc = dlpar_cpu_remove_by_index(drc_index);
+		else
+			rc = -EINVAL;
+		break;
+	default:
+		pr_err("Invalid action (%d) specified\n", hp_elog->action);
+		rc = -EINVAL;
+		break;
+	}
+
+	unlock_device_hotplug();
+	return rc;
+}
+
 #ifdef CONFIG_ARCH_CPU_PROBE_RELEASE
 
 static ssize_t dlpar_cpu_probe(const char *buf, size_t count)
diff --git a/arch/powerpc/platforms/pseries/pseries.h b/arch/powerpc/platforms/pseries/pseries.h
index 8411c27..7aa83f0 100644
--- a/arch/powerpc/platforms/pseries/pseries.h
+++ b/arch/powerpc/platforms/pseries/pseries.h
@@ -73,6 +73,15 @@ static inline int dlpar_memory(struct pseries_hp_errorlog *hp_elog)
 }
 #endif
 
+#ifdef CONFIG_HOTPLUG_CPU
+int dlpar_cpu(struct pseries_hp_errorlog *hp_elog);
+#else
+static inline int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
+{
+	return -EOPNOTSUPP;
+}
+#endif
+
 /* PCI root bridge prepare function override for pseries */
 struct pci_host_bridge;
 int pseries_root_bridge_prepare(struct pci_host_bridge *bridge);

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 5/6] powerpc/pseries: Add CPU dlpar add functionality
  2015-10-27 18:21 [PATCH v2 0/6] powerpc/pseries: Move CPU DLPAR into the kernel Nathan Fontenot
                   ` (3 preceding siblings ...)
  2015-10-27 18:26 ` [PATCH v2 4/6] powerpc/pseries: Add CPU dlpar remove functionality Nathan Fontenot
@ 2015-10-27 18:27 ` Nathan Fontenot
  2015-11-26  5:13   ` Michael Ellerman
  2015-10-27 18:28 ` [PATCH v2 6/6] powerpc/pseries: Enable kernel CPU dlpar from sysfs Nathan Fontenot
  5 siblings, 1 reply; 11+ messages in thread
From: Nathan Fontenot @ 2015-10-27 18:27 UTC (permalink / raw)
  To: linuxppc-dev

Add the ability to hotplug add cpus via rtas hotplug events by either
specifying the drc index of the CPU to add, or providing a count of the
number of CPUs to add.

Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/pseries/hotplug-cpu.c |   94 ++++++++++++++++++++++++++
 1 file changed, 94 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
index 635f0ba..8ec52c0 100644
--- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
+++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
@@ -679,6 +679,92 @@ static int dlpar_cpu_remove_by_count(u32 cpus_to_remove)
 	return rc;
 }
 
+static u32 *dlpar_cpus_to_add(u32 cpus_to_add)
+{
+	struct device_node *parent;
+	u32 *cpu_drcs;
+	int cpus_found = 0;
+	int i, index, rc;
+
+	cpu_drcs = kcalloc(cpus_to_add, sizeof(*cpu_drcs), GFP_KERNEL);
+	if (!cpu_drcs)
+		return NULL;
+
+	parent = of_find_node_by_path("/cpus");
+	if (!parent) {
+		kfree(cpu_drcs);
+		return NULL;
+	}
+
+	/* Search the ibm,drc-indexes array for possible CPU drcs to
+	 * add. Note that the format of the ibm,drc-indexes array is
+	 * the number of entries in the array followed by the array
+	 * of drc values so we start looking at index = 1.
+	 */
+	i = 0;
+	index = 1;
+	while (cpus_found < cpus_to_add) {
+		u32 drc;
+
+		rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
+						index++, &drc);
+		if (rc)
+			break;
+
+		if (dlpar_cpu_exists(parent, drc))
+			continue;
+
+		cpu_drcs[i++] = drc;
+		cpus_found++;
+	}
+
+	of_node_put(parent);
+
+	if (cpus_found < cpus_to_add) {
+		pr_warn("Failed to find enough CPUs (%d of %d) to add\n",
+			cpus_found, cpus_to_add);
+		kfree(cpu_drcs);
+		cpu_drcs = NULL;
+	}
+
+	return cpu_drcs;
+}
+
+static int dlpar_cpu_add_by_count(u32 cpus_to_add)
+{
+	u32 *cpu_drcs;
+	int cpus_added = 0;
+	int i, rc;
+
+	pr_debug("Attempting to hot-add %d CPUs\n", cpus_to_add);
+
+	cpu_drcs = dlpar_cpus_to_add(cpus_to_add);
+	if (!cpu_drcs)
+		return -EINVAL;
+
+	for (i = 0; i < cpus_to_add; i++) {
+		rc = dlpar_cpu_add(cpu_drcs[i]);
+		if (rc)
+			break;
+
+		cpus_added++;
+	}
+
+	if (cpus_added < cpus_to_add) {
+		pr_warn("CPU hot-add failed, removing any added CPUs\n");
+
+		for (i = 0; i < cpus_added; i++)
+			dlpar_cpu_remove_by_index(cpu_drcs[i]);
+
+		rc = -EINVAL;
+	} else {
+		rc = 0;
+	}
+
+	kfree(cpu_drcs);
+	return rc;
+}
+
 int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
 {
 	u32 count, drc_index;
@@ -698,6 +784,14 @@ int dlpar_cpu(struct pseries_hp_errorlog *hp_elog)
 		else
 			rc = -EINVAL;
 		break;
+	case PSERIES_HP_ELOG_ACTION_ADD:
+		if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_COUNT)
+			rc = dlpar_cpu_add_by_count(count);
+		else if (hp_elog->id_type == PSERIES_HP_ELOG_ID_DRC_INDEX)
+			rc = dlpar_cpu_add(drc_index);
+		else
+			rc = -EINVAL;
+		break;
 	default:
 		pr_err("Invalid action (%d) specified\n", hp_elog->action);
 		rc = -EINVAL;

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [PATCH v2 6/6] powerpc/pseries: Enable kernel CPU dlpar from sysfs
  2015-10-27 18:21 [PATCH v2 0/6] powerpc/pseries: Move CPU DLPAR into the kernel Nathan Fontenot
                   ` (4 preceding siblings ...)
  2015-10-27 18:27 ` [PATCH v2 5/6] powerpc/pseries: Add CPU dlpar add functionality Nathan Fontenot
@ 2015-10-27 18:28 ` Nathan Fontenot
  5 siblings, 0 replies; 11+ messages in thread
From: Nathan Fontenot @ 2015-10-27 18:28 UTC (permalink / raw)
  To: linuxppc-dev

Enable new kernel cpu hotplug functionality by allowing cpu dlpar requests
to be initiated from sysfs.

Signed-off-by: Nathan Fontenot <nfont@linux.vnet.ibm.com>
---
 arch/powerpc/platforms/pseries/dlpar.c |    6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/arch/powerpc/platforms/pseries/dlpar.c b/arch/powerpc/platforms/pseries/dlpar.c
index 438fdbd..2b93ae8 100644
--- a/arch/powerpc/platforms/pseries/dlpar.c
+++ b/arch/powerpc/platforms/pseries/dlpar.c
@@ -356,6 +356,9 @@ static int handle_dlpar_errorlog(struct pseries_hp_errorlog *hp_elog)
 	case PSERIES_HP_ELOG_RESOURCE_MEM:
 		rc = dlpar_memory(hp_elog);
 		break;
+	case PSERIES_HP_ELOG_RESOURCE_CPU:
+		rc = dlpar_cpu(hp_elog);
+		break;
 	default:
 		pr_warn_ratelimited("Invalid resource (%d) specified\n",
 				    hp_elog->resource);
@@ -385,6 +388,9 @@ static ssize_t dlpar_store(struct class *class, struct class_attribute *attr,
 	if (!strncmp(arg, "memory", 6)) {
 		hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_MEM;
 		arg += strlen("memory ");
+	} else if (!strncmp(arg, "cpu", 3)) {
+		hp_elog->resource = PSERIES_HP_ELOG_RESOURCE_CPU;
+		arg += strlen("cpu ");
 	} else {
 		pr_err("Invalid resource specified: \"%s\"\n", buf);
 		rc = -EINVAL;

^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 4/6] powerpc/pseries: Add CPU dlpar remove functionality
  2015-10-27 18:26 ` [PATCH v2 4/6] powerpc/pseries: Add CPU dlpar remove functionality Nathan Fontenot
@ 2015-11-26  5:02   ` Michael Ellerman
  2015-12-01 20:51     ` Nathan Fontenot
  0 siblings, 1 reply; 11+ messages in thread
From: Michael Ellerman @ 2015-11-26  5:02 UTC (permalink / raw)
  To: Nathan Fontenot, linuxppc-dev

On Tue, 2015-10-27 at 13:26 -0500, Nathan Fontenot wrote:

> Add the ability to dlpar remove CPUs via hotplug rtas events, either by
> specifying the drc-index of the CPU to remove or providing a count of cpus
> to remove.
> 
> diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> index f080e81..635f0ba 100644
> --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
> +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
> @@ -570,6 +571,143 @@ static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index)
>  	return 0;
>  }
>  
> +static struct device_node *cpu_drc_index_to_dn(u32 drc_index)
> +{
> +	struct device_node *dn;
> +	u32 my_index;
> +	int rc;
> +
> +	for_each_node_by_type(dn, "cpu") {
> +		rc = of_property_read_u32(dn, "ibm,my-drc-index", &my_index);
> +		if (rc)
> +			continue;
> +
> +		if (my_index == drc_index)
> +			break;
> +	}
> +
> +	return dn;
> +}
> +
> +static int dlpar_cpu_remove_by_index(u32 drc_index)
> +{
> +	struct device_node *dn;
> +	int rc;
> +
> +	dn = cpu_drc_index_to_dn(drc_index);
> +	if (!dn)
> +		return -ENODEV;
> +
> +	rc = dlpar_cpu_remove(dn, drc_index);
> +	of_node_put(dn);

Does dlpar_cpu_remove() work when you still hold a reference to the dn?

It looks like dlpar_detach_node() does an of_node_put() also.

> +	return rc;
> +}
> +
> +static u32 *dlpar_cpus_to_remove(int cpus_to_remove)
> +{
> +	struct device_node *dn;
> +	u32 *cpu_drcs;
> +	int cpus_found = 0;
> +	int i, rc;
> +
> +	cpu_drcs = kcalloc(cpus_to_remove, sizeof(*cpu_drcs), GFP_KERNEL);
> +	if (!cpu_drcs)
> +		return NULL;
> +
> +	i = 0;
> +	for_each_node_by_type(dn, "cpu") {
> +		cpus_found++;
> +
> +		if (cpus_found > cpus_to_remove) {
> +			of_node_put(dn);
> +			break;
> +		}
> +
> +		rc = of_property_read_u32(dn, "ibm,my-drc-index",
> +					  &cpu_drcs[i++]);
> +		if (rc) {
> +			of_node_put(dn);
> +			break;

I'm not sure about the logic here with cpus_found and i. If you break here
cpus_found will be 1, but you found zero, which seems odd.

If instead you delayed the increment of i:

		rc = of_property_read_u32(dn, "ibm,my-drc-index",
					  &cpu_drcs[i]);
		if (rc) {
			of_node_put(dn);
			break;
		}

		i++;
	}

Then i would equal the number of cpus found at all times. If you need to count
one more in the if below you can just do that there.

> +
> +	/* We want to find cpus_to_remove + 1 CPUs to ensure we do not
> +	 * remove the last CPU.
> +	 */
> +	if (cpus_found <= cpus_to_remove) {
> +		pr_warn("Failed to find enough CPUs (%d of %d) to remove\n",
> +			cpus_found, cpus_to_remove);
> +		kfree(cpu_drcs);
> +		cpu_drcs = NULL;
> +	}

On my two cpu system when I do "cpu remove count 1" this always says:

  pseries-hotplug-cpu: Failed to find enough CPUs (1 of 1) to remove

Which confuses me.

I suspect that's because I actually have one cpu *node*, which appears to Linux
as two cpus (due to SMT). So I think it's working as expected, but it's not
very clear from a user's perspective.

cheers

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 5/6] powerpc/pseries: Add CPU dlpar add functionality
  2015-10-27 18:27 ` [PATCH v2 5/6] powerpc/pseries: Add CPU dlpar add functionality Nathan Fontenot
@ 2015-11-26  5:13   ` Michael Ellerman
  2015-12-01 21:00     ` Nathan Fontenot
  0 siblings, 1 reply; 11+ messages in thread
From: Michael Ellerman @ 2015-11-26  5:13 UTC (permalink / raw)
  To: Nathan Fontenot, linuxppc-dev

On Tue, 2015-10-27 at 13:27 -0500, Nathan Fontenot wrote:

> Add the ability to hotplug add cpus via rtas hotplug events by either
> specifying the drc index of the CPU to add, or providing a count of the
> number of CPUs to add.

So I just tried running this on my system, without doing anything on the HMC.

I have:

  # lsprop /proc/device-tree/cpus/ibm,drc-indexes 
  /proc/device-tree/cpus/ibm,drc-indexes
  		 00000002 10000000 10000002

So I think that says I have two cpus.

The first one is already added:

  /proc/device-tree/cpus/PowerPC,POWER6@0/ibm,my-drc-index
  		 10000000 (268435456)

But can I add the second one?

  # echo "cpu add count 1" > dlpar 
  RTAS: event: 34, Type: Platform Error, Severity: 2
  pseries-hotplug-cpu: Failed to acquire DRC, rc: -5, drc index: 10000002
  pseries-hotplug-cpu: CPU hot-add failed, removing any added CPUs
  -bash: echo: write error: Invalid argument


Seems not. But I'm not clear why?

Adding by index doesn't work either:

  # echo "cpu add index 10000002" > dlpar
  pseries-hotplug-cpu: Failed to acquire DRC, rc: -1, drc index: 989682
  -bash: echo: write error: Invalid argument

That's a little confusing, drc index is hex obviously.

  [root@p6-10-P5-E0 kernel]# echo "cpu add index 0x10000002" > dlpar 
  RTAS: event: 35, Type: Platform Error, Severity: 2
  pseries-hotplug-cpu: Failed to acquire DRC, rc: -5, drc index: 10000002
  -bash: echo: write error: Invalid argument


So that's probably all PEBKAC, but if we can make it more intutive that would be good.

cheers

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 4/6] powerpc/pseries: Add CPU dlpar remove functionality
  2015-11-26  5:02   ` Michael Ellerman
@ 2015-12-01 20:51     ` Nathan Fontenot
  0 siblings, 0 replies; 11+ messages in thread
From: Nathan Fontenot @ 2015-12-01 20:51 UTC (permalink / raw)
  To: Michael Ellerman, linuxppc-dev

On 11/25/2015 11:02 PM, Michael Ellerman wrote:
> On Tue, 2015-10-27 at 13:26 -0500, Nathan Fontenot wrote:
> 
>> Add the ability to dlpar remove CPUs via hotplug rtas events, either by
>> specifying the drc-index of the CPU to remove or providing a count of cpus
>> to remove.
>>
>> diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c
>> index f080e81..635f0ba 100644
>> --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c
>> +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c
>> @@ -570,6 +571,143 @@ static ssize_t dlpar_cpu_remove(struct device_node *dn, u32 drc_index)
>>  	return 0;
>>  }
>>  
>> +static struct device_node *cpu_drc_index_to_dn(u32 drc_index)
>> +{
>> +	struct device_node *dn;
>> +	u32 my_index;
>> +	int rc;
>> +
>> +	for_each_node_by_type(dn, "cpu") {
>> +		rc = of_property_read_u32(dn, "ibm,my-drc-index", &my_index);
>> +		if (rc)
>> +			continue;
>> +
>> +		if (my_index == drc_index)
>> +			break;
>> +	}
>> +
>> +	return dn;
>> +}
>> +
>> +static int dlpar_cpu_remove_by_index(u32 drc_index)
>> +{
>> +	struct device_node *dn;
>> +	int rc;
>> +
>> +	dn = cpu_drc_index_to_dn(drc_index);
>> +	if (!dn)
>> +		return -ENODEV;
>> +
>> +	rc = dlpar_cpu_remove(dn, drc_index);
>> +	of_node_put(dn);
> 
> Does dlpar_cpu_remove() work when you still hold a reference to the dn?

Yes, this works while holding the dn reference here.
> 
> It looks like dlpar_detach_node() does an of_node_put() also.

Correct. The of_node_put() in dlpar_detach_node() is there to do a put
from the initial node creation, without this the reference count would never
go to zero and the node would not be released.

> 
>> +	return rc;
>> +}
>> +
>> +static u32 *dlpar_cpus_to_remove(int cpus_to_remove)
>> +{
>> +	struct device_node *dn;
>> +	u32 *cpu_drcs;
>> +	int cpus_found = 0;
>> +	int i, rc;
>> +
>> +	cpu_drcs = kcalloc(cpus_to_remove, sizeof(*cpu_drcs), GFP_KERNEL);
>> +	if (!cpu_drcs)
>> +		return NULL;
>> +
>> +	i = 0;
>> +	for_each_node_by_type(dn, "cpu") {
>> +		cpus_found++;
>> +
>> +		if (cpus_found > cpus_to_remove) {
>> +			of_node_put(dn);
>> +			break;
>> +		}
>> +
>> +		rc = of_property_read_u32(dn, "ibm,my-drc-index",
>> +					  &cpu_drcs[i++]);
>> +		if (rc) {
>> +			of_node_put(dn);
>> +			break;
> 
> I'm not sure about the logic here with cpus_found and i. If you break here
> cpus_found will be 1, but you found zero, which seems odd.
> 

Agreed, it is a bit odd. The cpus_found var is meant to count the number of
cpus we find when looping through for_each_node_by_type() whereas i is just
meant to be an index into the cpu_cars array so we can save the drc-index
of the cpus we find. The variable i is just to index the array, nothing more.

Perhaps instead of having i to use as an index into the cpu_drcs array I
could just use [cpus_found - 1] to index cpu_drcs and get rid of i. Not sure
if that makes the code any easier to read.

> If instead you delayed the increment of i:
> 
> 		rc = of_property_read_u32(dn, "ibm,my-drc-index",
> 					  &cpu_drcs[i]);
> 		if (rc) {
> 			of_node_put(dn);
> 			break;
> 		}
> 
> 		i++;
> 	}
> 
> Then i would equal the number of cpus found at all times. If you need to count
> one more in the if below you can just do that there.
> 
>> +
>> +	/* We want to find cpus_to_remove + 1 CPUs to ensure we do not
>> +	 * remove the last CPU.
>> +	 */
>> +	if (cpus_found <= cpus_to_remove) {
>> +		pr_warn("Failed to find enough CPUs (%d of %d) to remove\n",
>> +			cpus_found, cpus_to_remove);
>> +		kfree(cpu_drcs);
>> +		cpu_drcs = NULL;
>> +	}
> 
> On my two cpu system when I do "cpu remove count 1" this always says:
> 
>   pseries-hotplug-cpu: Failed to find enough CPUs (1 of 1) to remove
> 
> Which confuses me.
> 
> I suspect that's because I actually have one cpu *node*, which appears to Linux
> as two cpus (due to SMT). So I think it's working as expected, but it's not
> very clear from a user's perspective.
> 

You are correct. For Power CPU DLPAR works on a node basis. If there
is only one node it will not remove the last CPU.

I should update the cpus_found to check to print a message if the remove
request would entail removing the last CPU and that the request is being
failed because of that.


Thanks for the feedback,
-Nathan

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH v2 5/6] powerpc/pseries: Add CPU dlpar add functionality
  2015-11-26  5:13   ` Michael Ellerman
@ 2015-12-01 21:00     ` Nathan Fontenot
  0 siblings, 0 replies; 11+ messages in thread
From: Nathan Fontenot @ 2015-12-01 21:00 UTC (permalink / raw)
  To: Michael Ellerman, linuxppc-dev

On 11/25/2015 11:13 PM, Michael Ellerman wrote:
> On Tue, 2015-10-27 at 13:27 -0500, Nathan Fontenot wrote:
> 
>> Add the ability to hotplug add cpus via rtas hotplug events by either
>> specifying the drc index of the CPU to add, or providing a count of the
>> number of CPUs to add.
> 
> So I just tried running this on my system, without doing anything on the HMC.
> 
> I have:
> 
>   # lsprop /proc/device-tree/cpus/ibm,drc-indexes 
>   /proc/device-tree/cpus/ibm,drc-indexes
>   		 00000002 10000000 10000002
> 
> So I think that says I have two cpus.
> 
> The first one is already added:
> 
>   /proc/device-tree/cpus/PowerPC,POWER6@0/ibm,my-drc-index
>   		 10000000 (268435456)
> 
> But can I add the second one?
> 
>   # echo "cpu add count 1" > dlpar 
>   RTAS: event: 34, Type: Platform Error, Severity: 2
>   pseries-hotplug-cpu: Failed to acquire DRC, rc: -5, drc index: 10000002
>   pseries-hotplug-cpu: CPU hot-add failed, removing any added CPUs
>   -bash: echo: write error: Invalid argument
> 
> 
> Seems not. But I'm not clear why?

The add request is failing because rtas call to acquire the resource is failing.
I have seen this on many systems lately. Previously one could add and remove
CPUs (and memory) by running the drmgr command on an LPAR manually and
everything would work. It seems there are now systems (not sure if its a
firmware or HMC update) that will only allow the rtas call to acquire the 
resource to succeed when the request is initiated from the HMC.

I can provide a patch for drmgr that uses the new sysfs interface so you
can drive the dlpar operations from the hmc.

> 
> Adding by index doesn't work either:
> 
>   # echo "cpu add index 10000002" > dlpar
>   pseries-hotplug-cpu: Failed to acquire DRC, rc: -1, drc index: 989682
>   -bash: echo: write error: Invalid argument
> 
> That's a little confusing, drc index is hex obviously.
> 
>   [root@p6-10-P5-E0 kernel]# echo "cpu add index 0x10000002" > dlpar 
>   RTAS: event: 35, Type: Platform Error, Severity: 2
>   pseries-hotplug-cpu: Failed to acquire DRC, rc: -5, drc index: 10000002
>   -bash: echo: write error: Invalid argument
> 
> 
> So that's probably all PEBKAC, but if we can make it more intutive that would be good.

I wrote the interface to take the drc index value in the format specified, so
without the 0x it assumes decimal. Should be a better error message in this case.

-Nathan

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2015-12-01 21:00 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2015-10-27 18:21 [PATCH v2 0/6] powerpc/pseries: Move CPU DLPAR into the kernel Nathan Fontenot
2015-10-27 18:23 ` [PATCH v2 1/6] powerpc/pseries: Consolidate CPU hotplug code to hotplug-cpu.c Nathan Fontenot
2015-10-27 18:24 ` [PATCH v2 2/6] powerpc/pseries: Factor out common cpu hotplug code Nathan Fontenot
2015-10-27 18:25 ` [PATCH v2 3/6] powerpc/pseries: Update CPU hotplug error recovery Nathan Fontenot
2015-10-27 18:26 ` [PATCH v2 4/6] powerpc/pseries: Add CPU dlpar remove functionality Nathan Fontenot
2015-11-26  5:02   ` Michael Ellerman
2015-12-01 20:51     ` Nathan Fontenot
2015-10-27 18:27 ` [PATCH v2 5/6] powerpc/pseries: Add CPU dlpar add functionality Nathan Fontenot
2015-11-26  5:13   ` Michael Ellerman
2015-12-01 21:00     ` Nathan Fontenot
2015-10-27 18:28 ` [PATCH v2 6/6] powerpc/pseries: Enable kernel CPU dlpar from sysfs 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).