diff --git a/arch/powerpc/include/asm/kexec.h b/arch/powerpc/include/asm/kexec.h index 95a98b390d62..270ee93a0f7d 100644 --- a/arch/powerpc/include/asm/kexec.h +++ b/arch/powerpc/include/asm/kexec.h @@ -103,10 +103,8 @@ int load_crashdump_segments_ppc64(struct kimage *image, int setup_purgatory_ppc64(struct kimage *image, const void *slave_code, const void *fdt, unsigned long kernel_load_addr, unsigned long fdt_load_addr); -unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image); -int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, - unsigned long initrd_load_addr, - unsigned long initrd_len, const char *cmdline); +unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem *rmem); +int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct crash_mem *rmem); #endif /* CONFIG_PPC64 */ #endif /* CONFIG_KEXEC_FILE */ diff --git a/arch/powerpc/kexec/elf_64.c b/arch/powerpc/kexec/elf_64.c index 214c071c58ed..5d6d616404cf 100644 --- a/arch/powerpc/kexec/elf_64.c +++ b/arch/powerpc/kexec/elf_64.c @@ -23,6 +23,7 @@ #include #include #include +#include static void *elf64_load(struct kimage *image, char *kernel_buf, unsigned long kernel_len, char *initrd, @@ -36,6 +37,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, const void *slave_code; struct elfhdr ehdr; char *modified_cmdline = NULL; + struct crash_mem *rmem = NULL; struct kexec_elf_info elf_info; struct kexec_buf kbuf = { .image = image, .buf_min = 0, .buf_max = ppc64_rma_size }; @@ -102,17 +104,20 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, kexec_dprintk("Loaded initrd at 0x%lx\n", initrd_load_addr); } + ret = get_reserved_memory_ranges(&rmem); + if (ret) + goto out; + fdt = of_kexec_alloc_and_setup_fdt(image, initrd_load_addr, initrd_len, cmdline, - kexec_extra_fdt_size_ppc64(image)); + kexec_extra_fdt_size_ppc64(image, rmem)); if (!fdt) { pr_err("Error setting up the new device tree.\n"); ret = -EINVAL; goto out; } - ret = setup_new_fdt_ppc64(image, fdt, initrd_load_addr, - initrd_len, cmdline); + ret = setup_new_fdt_ppc64(image, fdt, rmem); if (ret) goto out_free_fdt; @@ -146,6 +151,7 @@ static void *elf64_load(struct kimage *image, char *kernel_buf, out_free_fdt: kvfree(fdt); out: + kfree(rmem); kfree(modified_cmdline); kexec_free_elf_info(&elf_info); diff --git a/arch/powerpc/kexec/file_load_64.c b/arch/powerpc/kexec/file_load_64.c index 925a69ad2468..413c76de283d 100644 --- a/arch/powerpc/kexec/file_load_64.c +++ b/arch/powerpc/kexec/file_load_64.c @@ -803,10 +803,9 @@ static unsigned int cpu_node_size(void) return size; } -static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image) +static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image, unsigned int cpu_nodes) { - unsigned int cpu_nodes, extra_size = 0; - struct device_node *dn; + unsigned int extra_size = 0; u64 usm_entries; #ifdef CONFIG_CRASH_HOTPLUG unsigned int possible_cpu_nodes; @@ -826,18 +825,6 @@ static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image) 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(); - #ifdef CONFIG_CRASH_HOTPLUG /* * Make sure enough space is reserved to accommodate possible CPU nodes @@ -861,16 +848,30 @@ static unsigned int kdump_extra_fdt_size_ppc64(struct kimage *image) * * Returns the estimated extra size needed for kexec/kdump kernel FDT. */ -unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image) +unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image, struct crash_mem *rmem) { - unsigned int extra_size = 0; + struct device_node *dn; + unsigned int cpu_nodes = 0, extra_size = 0; // Budget some space for the password blob. There's already extra space // for the key name if (plpks_is_available()) extra_size += (unsigned int)plpks_get_passwordlen(); - return extra_size + kdump_extra_fdt_size_ppc64(image); + /* Get the number of CPU nodes in the current device tree */ + for_each_node_by_type(dn, "cpu") { + cpu_nodes++; + } + + /* Consider extra space for CPU nodes added since the boot time */ + if (cpu_nodes > boot_cpu_node_count) + extra_size += (cpu_nodes - boot_cpu_node_count) * cpu_node_size(); + + /* Consider extra space for reserved memory ranges if any */ + if (rmem->nr_ranges > 0) + extra_size += sizeof(struct fdt_reserve_entry) * rmem->nr_ranges; + + return extra_size + kdump_extra_fdt_size_ppc64(image, cpu_nodes); } static int copy_property(void *fdt, int node_offset, const struct device_node *dn, @@ -924,18 +925,13 @@ static int update_pci_dma_nodes(void *fdt, const char *dmapropname) * being loaded. * @image: kexec image being loaded. * @fdt: Flattened device tree for the next kernel. - * @initrd_load_addr: Address where the next initrd will be loaded. - * @initrd_len: Size of the next initrd, or 0 if there will be none. - * @cmdline: Command line for the next kernel, or NULL if there will - * be none. + * @rmem: Reserved memory ranges. * * Returns 0 on success, negative errno on error. */ -int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, - unsigned long initrd_load_addr, - unsigned long initrd_len, const char *cmdline) +int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, struct crash_mem *rmem) { - struct crash_mem *umem = NULL, *rmem = NULL; + struct crash_mem *umem = NULL; int i, nr_ranges, ret; #ifdef CONFIG_CRASH_DUMP @@ -991,10 +987,6 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, goto out; /* Update memory reserve map */ - ret = get_reserved_memory_ranges(&rmem); - if (ret) - goto out; - nr_ranges = rmem ? rmem->nr_ranges : 0; for (i = 0; i < nr_ranges; i++) { u64 base, size; @@ -1014,7 +1006,6 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt, ret = plpks_populate_fdt(fdt); out: - kfree(rmem); kfree(umem); return ret; }