Skip to content

Commit

Permalink
powerpc/pseries: Add CPU dlpar add functionality
Browse files Browse the repository at this point in the history
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>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
  • Loading branch information
Nathan Fontenot authored and Michael Ellerman committed Dec 17, 2015
1 parent ac71380 commit 90edf18
Showing 1 changed file with 116 additions and 0 deletions.
116 changes: 116 additions & 0 deletions arch/powerpc/platforms/pseries/hotplug-cpu.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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",
Expand Down Expand Up @@ -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;
Expand All @@ -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;
Expand Down

0 comments on commit 90edf18

Please sign in to comment.