@@ -5,14 +5,14 @@ obj-y := lpar.o hvCall.o nvram.o reconfig.o \
of_helpers.o \
setup.o iommu.o event_sources.o ras.o \
firmware.o power.o dlpar.o mobility.o rng.o \
- pci.o pci_dlpar.o eeh_pseries.o msi.o
+ pci.o pci_dlpar.o eeh_pseries.o msi.o \
+ hotplug-memory.o
obj-$(CONFIG_SMP) += smp.o
obj-$(CONFIG_SCANLOG) += scanlog.o
obj-$(CONFIG_KEXEC_CORE) += kexec.o
obj-$(CONFIG_PSERIES_ENERGY) += pseries_energy.o
obj-$(CONFIG_HOTPLUG_CPU) += hotplug-cpu.o
-obj-$(CONFIG_MEMORY_HOTPLUG) += hotplug-memory.o
obj-$(CONFIG_HVC_CONSOLE) += hvconsole.o
obj-$(CONFIG_HVCS) += hvcserver.o
@@ -24,8 +24,6 @@
#include <asm/sparsemem.h>
#include "pseries.h"
-static bool rtas_hp_event;
-
unsigned long pseries_memory_block_size(void)
{
struct device_node *np;
@@ -69,6 +67,10 @@ unsigned long pseries_memory_block_size(void)
return memblock_size;
}
+#ifdef CONFIG_MEMORY_HOTPLUG
+
+static bool rtas_hp_event;
+
static void dlpar_free_property(struct property *prop)
{
kfree(prop->name);
@@ -890,11 +892,101 @@ static int pseries_memory_notifier(struct notifier_block *nb,
static struct notifier_block pseries_mem_nb = {
.notifier_call = pseries_memory_notifier,
};
+#endif /* CONFIG_MEMORY_HOTPLUG */
+
+static int pseries_rewrite_dynamic_memory_v2(void)
+{
+ unsigned long memblock_size;
+ struct device_node *dn;
+ struct property *prop, *prop_v2;
+ __be32 *p;
+ struct of_drconf_cell *lmbs;
+ u32 num_lmb_desc_sets, num_lmbs;
+ int i, j, k;
+
+ dn = of_find_node_by_path("/ibm,dynamic-reconfiguration-memory");
+ if (!dn)
+ return -EINVAL;
+
+ prop_v2 = of_find_property(dn, "ibm,dynamic-memory-v2", NULL);
+ if (!prop_v2)
+ return -EINVAL;
+
+ memblock_size = pseries_memory_block_size();
+ if (!memblock_size)
+ return -EINVAL;
+
+ /* The first int of the property is the number of lmb sets
+ * described by the property.
+ */
+ p = (__be32 *)prop_v2->value;
+ num_lmb_desc_sets = be32_to_cpu(*p++);
+
+ /* Count the number of LMBs for generating the alternate format
+ */
+ for (i = 0, num_lmbs = 0; i < num_lmb_desc_sets; i++) {
+ struct of_drconf_cell_v2 drmem;
+
+ read_drconf_cell_v2(&drmem, (const __be32 **)&p);
+ num_lmbs += drmem.num_seq_lmbs;
+ }
+
+ /* Create an empty copy of the new 'ibm,dynamic-memory' property
+ */
+ prop = kzalloc(sizeof(*prop), GFP_KERNEL);
+ if (!prop)
+ return -ENOMEM;
+ prop->name = kstrdup("ibm,dynamic-memory", GFP_KERNEL);
+ prop->length = dyn_mem_v2_len(num_lmbs);
+ prop->value = kzalloc(prop->length, GFP_KERNEL);
+
+ /* Copy/expand the ibm,dynamic-memory-v2 format to produce the
+ * ibm,dynamic-memory format.
+ */
+ p = (__be32 *)prop->value;
+ *p = cpu_to_be32(num_lmbs);
+ p++;
+ lmbs = (struct of_drconf_cell *)p;
+
+ p = (__be32 *)prop_v2->value;
+ p++;
+
+ for (i = 0, k = 0; i < num_lmb_desc_sets; i++) {
+ struct of_drconf_cell_v2 drmem;
+
+ read_drconf_cell_v2(&drmem, (const __be32 **)&p);
+
+ for (j = 0; j < drmem.num_seq_lmbs; j++) {
+ lmbs[k+j].base_addr = be64_to_cpu(drmem.base_addr);
+ lmbs[k+j].drc_index = be32_to_cpu(drmem.drc_index);
+ lmbs[k+j].aa_index = be32_to_cpu(drmem.aa_index);
+ lmbs[k+i].flags = be32_to_cpu(drmem.flags);
+
+ drmem.base_addr += memblock_size;
+ drmem.drc_index++;
+ }
+
+ k += drmem.num_seq_lmbs;
+ }
+
+ of_remove_property(dn, prop_v2);
+
+ of_add_property(dn, prop);
+
+ /* And disable feature flag since the property has gone away */
+ powerpc_firmware_features &= ~FW_FEATURE_DYN_MEM_V2;
+
+ return 0;
+}
static int __init pseries_memory_hotplug_init(void)
{
+ if (firmware_has_feature(FW_FEATURE_DYN_MEM_V2))
+ pseries_rewrite_dynamic_memory_v2();
+#ifdef CONFIG_MEMORY_HOTPLUG
if (firmware_has_feature(FW_FEATURE_LPAR))
of_reconfig_notifier_register(&pseries_mem_nb);
+#endif /* CONFIG_MEMORY_HOTPLUG */
return 0;
}