Skip to content

Commit 40c7539

Browse files
sourabhjainsmpe
authored andcommitted
powerpc/kexec_file: Use current CPU info while setting up FDT
kexec_file_load() uses initial_boot_params in setting up the device tree for the kernel to be loaded. Though initial_boot_params holds info about CPUs at the time of boot, it doesn't account for hot added CPUs. So, kexec'ing with kexec_file_load() syscall leaves the kexec'ed kernel with inaccurate CPU info. If kdump kernel is loaded with kexec_file_load() syscall and the system crashes on a hot added CPU, the capture kernel hangs failing to identify the boot CPU, with no output. To avoid this from happening, extract current CPU info from of_root device node and use it for setting up the fdt in kexec_file_load case. Fixes: 6ecd016 ("powerpc/kexec_file: Add appropriate regions for memory reserve map") Cc: [email protected] # v5.9+ Signed-off-by: Sourabh Jain <[email protected]> Reviewed-by: Hari Bathini <[email protected]> Signed-off-by: Michael Ellerman <[email protected]> Link: https://lore.kernel.org/r/[email protected]
1 parent 8abddd9 commit 40c7539

File tree

1 file changed

+92
-0
lines changed

1 file changed

+92
-0
lines changed

arch/powerpc/kexec/file_load_64.c

Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -950,6 +950,93 @@ unsigned int kexec_extra_fdt_size_ppc64(struct kimage *image)
950950
return (unsigned int)(usm_entries * sizeof(u64));
951951
}
952952

953+
/**
954+
* add_node_props - Reads node properties from device node structure and add
955+
* them to fdt.
956+
* @fdt: Flattened device tree of the kernel
957+
* @node_offset: offset of the node to add a property at
958+
* @dn: device node pointer
959+
*
960+
* Returns 0 on success, negative errno on error.
961+
*/
962+
static int add_node_props(void *fdt, int node_offset, const struct device_node *dn)
963+
{
964+
int ret = 0;
965+
struct property *pp;
966+
967+
if (!dn)
968+
return -EINVAL;
969+
970+
for_each_property_of_node(dn, pp) {
971+
ret = fdt_setprop(fdt, node_offset, pp->name, pp->value, pp->length);
972+
if (ret < 0) {
973+
pr_err("Unable to add %s property: %s\n", pp->name, fdt_strerror(ret));
974+
return ret;
975+
}
976+
}
977+
return ret;
978+
}
979+
980+
/**
981+
* update_cpus_node - Update cpus node of flattened device tree using of_root
982+
* device node.
983+
* @fdt: Flattened device tree of the kernel.
984+
*
985+
* Returns 0 on success, negative errno on error.
986+
*/
987+
static int update_cpus_node(void *fdt)
988+
{
989+
struct device_node *cpus_node, *dn;
990+
int cpus_offset, cpus_subnode_offset, ret = 0;
991+
992+
cpus_offset = fdt_path_offset(fdt, "/cpus");
993+
if (cpus_offset < 0 && cpus_offset != -FDT_ERR_NOTFOUND) {
994+
pr_err("Malformed device tree: error reading /cpus node: %s\n",
995+
fdt_strerror(cpus_offset));
996+
return cpus_offset;
997+
}
998+
999+
if (cpus_offset > 0) {
1000+
ret = fdt_del_node(fdt, cpus_offset);
1001+
if (ret < 0) {
1002+
pr_err("Error deleting /cpus node: %s\n", fdt_strerror(ret));
1003+
return -EINVAL;
1004+
}
1005+
}
1006+
1007+
/* Add cpus node to fdt */
1008+
cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "cpus");
1009+
if (cpus_offset < 0) {
1010+
pr_err("Error creating /cpus node: %s\n", fdt_strerror(cpus_offset));
1011+
return -EINVAL;
1012+
}
1013+
1014+
/* Add cpus node properties */
1015+
cpus_node = of_find_node_by_path("/cpus");
1016+
ret = add_node_props(fdt, cpus_offset, cpus_node);
1017+
of_node_put(cpus_node);
1018+
if (ret < 0)
1019+
return ret;
1020+
1021+
/* Loop through all subnodes of cpus and add them to fdt */
1022+
for_each_node_by_type(dn, "cpu") {
1023+
cpus_subnode_offset = fdt_add_subnode(fdt, cpus_offset, dn->full_name);
1024+
if (cpus_subnode_offset < 0) {
1025+
pr_err("Unable to add %s subnode: %s\n", dn->full_name,
1026+
fdt_strerror(cpus_subnode_offset));
1027+
ret = cpus_subnode_offset;
1028+
goto out;
1029+
}
1030+
1031+
ret = add_node_props(fdt, cpus_subnode_offset, dn);
1032+
if (ret < 0)
1033+
goto out;
1034+
}
1035+
out:
1036+
of_node_put(dn);
1037+
return ret;
1038+
}
1039+
9531040
/**
9541041
* setup_new_fdt_ppc64 - Update the flattend device-tree of the kernel
9551042
* being loaded.
@@ -1006,6 +1093,11 @@ int setup_new_fdt_ppc64(const struct kimage *image, void *fdt,
10061093
}
10071094
}
10081095

1096+
/* Update cpus nodes information to account hotplug CPUs. */
1097+
ret = update_cpus_node(fdt);
1098+
if (ret < 0)
1099+
goto out;
1100+
10091101
/* Update memory reserve map */
10101102
ret = get_reserved_memory_ranges(&rmem);
10111103
if (ret)

0 commit comments

Comments
 (0)