diff mbox

[v2,5/6] powerpc/pseries: Add CPU dlpar add functionality

Message ID 562FC21F.3050907@linux.vnet.ibm.com (mailing list archive)
State Changes Requested
Headers show

Commit Message

Nathan Fontenot Oct. 27, 2015, 6:27 p.m. UTC
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(+)

Comments

Michael Ellerman Nov. 26, 2015, 5:13 a.m. UTC | #1
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
Nathan Fontenot Dec. 1, 2015, 9 p.m. UTC | #2
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
diff mbox

Patch

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;