@@ -45,6 +45,29 @@ uint64_t initrd_base, initrd_size;
unsigned char reuse_initrd = 0;
const char *ramdisk;
+#define MAX_CORE 256
+#define PER_CORE_NODE_SIZE 1500
+
+/**
+ * get_crash_fdt_mem_sz() - calcuate mem size for crash kernel FDT
+ * @fdt: pointer to crash kernel FDT
+ *
+ * Calculate the buffer space needed to add more CPU nodes in FDT after
+ * capture kenrel load due to hot add events.
+ *
+ * Some assumption are made to calculate the additional buffer size needed
+ * to accommodate future hot add CPUs to the crash FDT. The maximum core count
+ * in the system would not go beyond MAX_CORE and memory needed to store per core
+ * date in FDT is PER_CORE_NODE_SIZE.
+ *
+ * Certainly MAX_CORE count can be replaced with possible core count and
+ * PER_CORE_NODE_SIZE to some standard value instead of randomly observed
+ * core size value on Power9 LPAR.
+ */
+static unsigned int get_crash_fdt_mem_sz(void *fdt) {
+ return fdt_totalsize(fdt) + (PER_CORE_NODE_SIZE * MAX_CORE);
+}
+
int elf_ppc64_probe(const char *buf, off_t len)
{
struct mem_ehdr ehdr;
@@ -179,6 +202,7 @@ int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
uint64_t max_addr, hole_addr;
char *seg_buf = NULL;
off_t seg_size = 0;
+ unsigned int mem_sz = 0;
struct mem_phdr *phdr;
size_t size;
#ifdef NEED_RESERVE_DTB
@@ -329,7 +353,13 @@ int elf_ppc64_load(int argc, char **argv, const char *buf, off_t len,
if (result < 0)
return result;
- my_dt_offset = add_buffer(info, seg_buf, seg_size, seg_size,
+ if (info->kexec_flags & KEXEC_ON_CRASH) {
+ mem_sz = get_crash_fdt_mem_sz((void *)seg_buf);
+ fdt_set_totalsize(seg_buf, mem_sz);
+ info->fdt_index = info->nr_segments;
+ }
+
+ my_dt_offset = add_buffer(info, seg_buf, seg_size, mem_sz,
0, 0, max_addr, -1);
#ifdef NEED_RESERVE_DTB
@@ -672,6 +672,9 @@ static void update_purgatory(struct kexec_info *info)
if (info->segment[i].mem == (void *)info->rhdr.rel_addr) {
continue;
}
+ if (info->fdt_index == i)
+ continue;
+
sha256_update(&ctx, info->segment[i].buf,
info->segment[i].bufsz);
nullsz = info->segment[i].memsz - info->segment[i].bufsz;
@@ -169,6 +169,7 @@ struct kexec_info {
int command_line_len;
int skip_checks;
+ // Given that we might need to update mutliple kexec segments
+ // then having array to keep indexes of all hotplug kexec segments
+ // will be helpful.
+ unsigned int fdt_index;
};
struct arch_map_entry {