Merge tag 'powerpc-6.2-1' of git://git.kernel.org/pub/scm/linux/kernel/git/powerpc...
[linux-block.git] / arch / powerpc / kexec / file_load_64.c
index 60e12b716d3c8c59a25fb66af119920b6f1e191e..af8854f9eae3c85645a8482cadbaf84524b017e4 100644 (file)
@@ -26,6 +26,7 @@
 #include <asm/firmware.h>
 #include <asm/kexec_ranges.h>
 #include <asm/crashdump-ppc64.h>
+#include <asm/prom.h>
 
 struct umem_info {
        u64 *buf;               /* data buffer for usable-memory property */
@@ -928,6 +929,45 @@ out:
        return ret;
 }
 
+/**
+ * get_cpu_node_size - Compute the size of a CPU node in the FDT.
+ *                     This should be done only once and the value is stored in
+ *                     a static variable.
+ * Returns the max size of a CPU node in the FDT.
+ */
+static unsigned int cpu_node_size(void)
+{
+       static unsigned int size;
+       struct device_node *dn;
+       struct property *pp;
+
+       /*
+        * Don't compute it twice, we are assuming that the per CPU node size
+        * doesn't change during the system's life.
+        */
+       if (size)
+               return size;
+
+       dn = of_find_node_by_type(NULL, "cpu");
+       if (WARN_ON_ONCE(!dn)) {
+               // Unlikely to happen
+               return 0;
+       }
+
+       /*
+        * We compute the sub node size for a CPU node, assuming it
+        * will be the same for all.
+        */
+       size += strlen(dn->name) + 5;
+       for_each_property_of_node(dn, pp) {
+               size += strlen(pp->name);
+               size += pp->length;
+       }
+
+       of_node_put(dn);
+       return size;
+}
+
 /**
  * kexec_extra_fdt_size_ppc64 - Return the estimated additional size needed to
  *                              setup FDT for kexec/kdump kernel.
@@ -937,6 +977,8 @@ out:
  */
 unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
 {
+       unsigned int cpu_nodes, extra_size;
+       struct device_node *dn;
        u64 usm_entries;
 
        if (image->type != KEXEC_TYPE_CRASH)
@@ -949,7 +991,22 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
         */
        usm_entries = ((memblock_end_of_DRAM() / drmem_lmb_size()) +
                       (2 * (resource_size(&crashk_res) / drmem_lmb_size())));
-       return (unsigned int)(usm_entries * sizeof(u64));
+
+       extra_size = (unsigned int)(usm_entries * sizeof(u64));
+
+       /*
+        * Get the number of CPU nodes in the current DT. This allows to
+        * reserve places for CPU nodes added since the boot time.
+        */
+       cpu_nodes = 0;
+       for_each_node_by_type(dn, "cpu") {
+               cpu_nodes++;
+       }
+
+       if (cpu_nodes > boot_cpu_node_count)
+               extra_size += (cpu_nodes - boot_cpu_node_count) * cpu_node_size();
+
+       return extra_size;
 }
 
 /**