This patch fixes a bug matching drc-indexes of CPUs that are being hot-added to a system either individually or by count. This patch inserts a couple of missing checks and parsing code for the new representation of device-tree information provided by the property "ibm,drc-info".
Signed-off-by: Michael Bringmann <[email protected]> Fixes: 3f38000eda48 ("powerpc/firmware: Add definitions for new drc-info firmwar e feature" -- end of patch series applied to powerpc next) --- arch/powerpc/platforms/pseries/hotplug-cpu.c | 117 +++++++++++++++++++++----- 1 file changed, 96 insertions(+), 21 deletions(-) diff --git a/arch/powerpc/platforms/pseries/hotplug-cpu.c b/arch/powerpc/platforms/pseries/hotplug-cpu.c index a7d14aa7..4cc6b70 100644 --- a/arch/powerpc/platforms/pseries/hotplug-cpu.c +++ b/arch/powerpc/platforms/pseries/hotplug-cpu.c @@ -413,19 +413,52 @@ 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; + if (firmware_has_feature(FW_FEATURE_DRC_INFO)) { + struct property *info = NULL; + struct of_drc_info drc; + int j; + u32 num_set_entries; + const __be32 *value; + + info = of_find_property(parent, "ibm,drc-info", NULL); + if (info == NULL) + goto end_out; + + value = of_prop_next_u32(info, NULL, &num_set_entries); + if (!value) + goto end_out; + value++; + + for (j = 0; j < num_set_entries; j++) { + + of_read_drc_info_cell(&info, &value, &drc); + if (strncmp(drc.drc_type, "CPU", 3)) + goto end_out; + + if ((drc.drc_index_start <= drc_index) && + (drc_index <= drc.last_drc_index)) { + found = true; + break; + } + } - rc = of_property_read_u32_index(parent, "ibm,drc-indexes", + } else { + index = 0; + while (!found) { + u32 drc; + + rc = of_property_read_u32_index(parent, + "ibm,drc-indexes", index++, &drc); - if (rc) - break; + if (rc) + break; - if (drc == drc_index) - found = true; + if (drc == drc_index) + found = true; + } } +end_out: return found; } @@ -731,26 +764,68 @@ static int find_dlpar_cpus_to_add(u32 *cpu_drcs, u32 cpus_to_add) 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. + /* Search the ibm,drc-indexes or ibm,drc-info 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. The ibm,drc-info array is a more + * compact format for large numbers of CPUs, and the format + * is correspondingly more complex. */ - index = 1; - while (cpus_found < cpus_to_add) { - u32 drc; + if (firmware_has_feature(FW_FEATURE_DRC_INFO)) { + struct property *info = NULL; + struct of_drc_info drc; + int j; + u32 num_set_entries; + const __be32 *value; + + info = of_find_property(parent, "ibm,drc-info", NULL); + if (info == NULL) + goto err_out; + + value = of_prop_next_u32(info, NULL, &num_set_entries); + if (!value) + goto err_out; + value++; + + for (j = 0; j < num_set_entries; j++) { + int k; + + of_read_drc_info_cell(&info, &value, &drc); + if (strncmp(drc.drc_type, "CPU", 3)) + goto err_out; + + for (k = 0; (k < drc.num_sequential_elems) && + (cpus_found < cpus_to_add); k++) { + u32 idrc = drc.drc_index_start + + (k * drc.sequential_inc); + + if (dlpar_cpu_exists(parent, idrc)) + continue; + + cpu_drcs[cpus_found++] = idrc; + } + } + + } else { + index = 1; + while (cpus_found < cpus_to_add) { + u32 drc; - rc = of_property_read_u32_index(parent, "ibm,drc-indexes", + rc = of_property_read_u32_index(parent, + "ibm,drc-indexes", index++, &drc); - if (rc) - break; + if (rc) + break; - if (dlpar_cpu_exists(parent, drc)) - continue; + if (dlpar_cpu_exists(parent, drc)) + continue; - cpu_drcs[cpus_found++] = drc; + cpu_drcs[cpus_found++] = drc; + } } +err_out: of_node_put(parent); return cpus_found; }
