mirror of
https://github.com/edk2-porting/linux-next.git
synced 2025-01-10 22:54:11 +08:00
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: Nathan Fontenot <nfont@linux.vnet.ibm.com> Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
This commit is contained in:
parent
ac71380071
commit
90edf184b9
@ -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;
|
||||
|
Loading…
Reference in New Issue
Block a user