Commit 90edf184 authored by Nathan Fontenot's avatar Nathan Fontenot Committed by Michael Ellerman

powerpc/pseries: Add CPU dlpar add functionality

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: default avatarNathan Fontenot <nfont@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent ac713800
......@@ -405,6 +405,27 @@ static bool dlpar_cpu_exists(struct device_node *parent, u32 drc_index)
return found;
}
static bool valid_cpu_drc_index(struct device_node *parent, u32 drc_index)
{
bool found = false;
int rc, index;
index = 0;
while (!found) {
u32 drc;
rc = of_property_read_u32_index(parent, "ibm,drc-indexes",
index++, &drc);
if (rc)
break;
if (drc == drc_index)
found = true;
}
return found;
}
static ssize_t dlpar_cpu_add(u32 drc_index)
{
struct device_node *dn, *parent;
......@@ -424,6 +445,12 @@ static ssize_t dlpar_cpu_add(u32 drc_index)
return -EINVAL;
}
if (!valid_cpu_drc_index(parent, drc_index)) {
of_node_put(parent);
pr_warn("Cannot find CPU (drc index %x) to add.\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",
......@@ -683,6 +710,87 @@ static int dlpar_cpu_remove_by_count(u32 cpus_to_remove)
return rc;
}
static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add)
{
struct device_node *parent;
int cpus_found = 0;
int index, rc;
parent = of_find_node_by_path("/cpus");
if (!parent) {
pr_warn("Could not find CPU root node in device tree\n");
kfree(cpu_drcs);
return -1;
}
/* 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.
*/
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[cpus_found++] = drc;
}
of_node_put(parent);
return cpus_found;
}
static int dlpar_cpu_add_by_count(u32 cpus_to_add)
{
u32 *cpu_drcs;
int cpus_added = 0;
int cpus_found;
int i, rc;
pr_debug("Attempting to hot-add %d CPUs\n", cpus_to_add);
cpu_drcs = kcalloc(cpus_to_add, sizeof(*cpu_drcs), GFP_KERNEL);
if (!cpu_drcs)
return -EINVAL;
cpus_found = find_dlpar_cpus_to_add(cpu_drcs, cpus_to_add);
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);
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;
......@@ -702,6 +810,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;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment