postmigration/memory: In an LPAR migration scenario, the property "ibm,associativity-lookup-arrays" may change. In the event that a row of the array differs, locate all assigned memory blocks with that 'aa_index' and 're-add' them to the system memory block data structures. In the process of the 're-add', the appropriate entry of the property 'ibm,dynamic-memory' would be updated as well as any other applicable system data structures.
Signed-off-by: Michael Bringmann <m...@linux.vnet.ibm.com> --- Changes in V2: -- Remove unnecessary spacing changes --- arch/powerpc/platforms/pseries/hotplug-memory.c | 119 +++++++++++++++++++++++ 1 file changed, 119 insertions(+) diff --git a/arch/powerpc/platforms/pseries/hotplug-memory.c b/arch/powerpc/platforms/pseries/hotplug-memory.c index c61cfc6..b37e6ad 100644 --- a/arch/powerpc/platforms/pseries/hotplug-memory.c +++ b/arch/powerpc/platforms/pseries/hotplug-memory.c @@ -1171,6 +1171,122 @@ static int pseries_update_drconf_memory(struct of_reconfig_data *pr) return rc; } +struct assoc_arrays { + u32 n_arrays; + u32 array_sz; + const __be32 *arrays; +}; + +static int pseries_update_ala_memory_aai(int aa_index, + struct property *dmprop) +{ + struct of_drconf_cell *drmem; + u32 entries; + __be32 *p; + int i; + + p = (__be32 *) dmprop->value; + if (!p) + return -EINVAL; + + /* The first int of the property is the number of lmb's + * described by the property. This is followed by an array + * of of_drconf_cell entries. Get the number of entries + * and skip to the array of of_drconf_cell's. + */ + entries = be32_to_cpu(*p++); + drmem = (struct of_drconf_cell *)p; + + for (i = 0; i < entries; i++) { + if ((be32_to_cpu(drmem[i].aa_index) != aa_index) && + (be32_to_cpu(drmem[i].flags) & DRCONF_MEM_ASSIGNED)) { + pseries_memory_readd_by_index( + be32_to_cpu(drmem[i].drc_index)); + } + } + + return 0; +} + +static int pseries_update_ala_memory(struct of_reconfig_data *pr) +{ + struct assoc_arrays new_ala, old_ala; + struct device_node *dn; + struct property *dmprop; + __be32 *p; + int i, lim; + + if (rtas_hp_event) + return 0; + + dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory"); + if (!dn) + return -ENODEV; + + dmprop = of_find_property(dn, "ibm,dynamic-memory", NULL); + if (!dmprop) { + of_node_put(dn); + return -ENODEV; + } + + /* + * The layout of the ibm,associativity-lookup-arrays + * property is a number N indicating the number of + * associativity arrays, followed by a number M + * indicating the size of each associativity array, + * followed by a list of N associativity arrays. + */ + + p = (__be32 *) pr->old_prop->value; + if (!p) { + of_node_put(dn); + return -EINVAL; + } + old_ala.n_arrays = of_read_number(p++, 1); + old_ala.array_sz = of_read_number(p++, 1); + old_ala.arrays = p; + + p = (__be32 *) pr->prop->value; + if (!p) { + of_node_put(dn); + return -EINVAL; + } + new_ala.n_arrays = of_read_number(p++, 1); + new_ala.array_sz = of_read_number(p++, 1); + new_ala.arrays = p; + + lim = (new_ala.n_arrays > old_ala.n_arrays) ? old_ala.n_arrays : + new_ala.n_arrays; + + if (old_ala.array_sz == new_ala.array_sz) { + + for (i = 0; i < lim; i++) { + int index = (i * new_ala.array_sz); + + if (!memcmp(&old_ala.arrays[index], + &new_ala.arrays[index], + new_ala.array_sz)) + continue; + + pseries_update_ala_memory_aai(i, dmprop); + } + + for (i = lim; i < new_ala.n_arrays; i++) + pseries_update_ala_memory_aai(i, dmprop); + + } else { + /* Update all entries representing these rows; + * as all rows have different sizes, none can + * have equivalent values. + */ + for (i = 0; i < lim; i++) + pseries_update_ala_memory_aai(i, dmprop); + } + + of_node_put(dn); + return 0; +} + static int pseries_memory_notifier(struct notifier_block *nb, unsigned long action, void *data) { @@ -1187,6 +1303,9 @@ static int pseries_memory_notifier(struct notifier_block *nb, case OF_RECONFIG_UPDATE_PROPERTY: if (!strcmp(rd->prop->name, "ibm,dynamic-memory")) err = pseries_update_drconf_memory(rd); + if (!strcmp(rd->prop->name, + "ibm,associativity-lookup-arrays")) + err = pseries_update_ala_memory(rd); break; } return notifier_from_errno(err);