Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

powerpc/kexec_file: fix cpus node update to FDT

While updating the cpus node, commit 40c753993e3a ("powerpc/kexec_file:
Use current CPU info while setting up FDT") first deletes all subnodes
under the /cpus node. However, while adding sub-nodes back, it missed
adding cpus subnodes whose device_type != "cpu", such as l2-cache*,
l3-cache*, ibm,powerpc-cpu-features.

Fix this by only deleting cpus sub-nodes of device_type == "cpus" and
then adding all available nodes with device_type == "cpu".

Fixes: 40c753993e3a ("powerpc/kexec_file: Use current CPU info while setting up FDT")
Signed-off-by: Sourabh Jain <sourabhjain@linux.ibm.com>
Signed-off-by: Michael Ellerman <mpe@ellerman.id.au>
Link: https://msgid.link/20240510102235.2269496-3-sourabhjain@linux.ibm.com

authored by

Sourabh Jain and committed by
Michael Ellerman
932bed41 0d3ff067

+38 -17
+38 -17
arch/powerpc/kexec/core_64.c
··· 456 456 * @fdt: Flattened device tree of the kernel. 457 457 * 458 458 * Returns 0 on success, negative errno on error. 459 + * 460 + * Note: expecting no subnodes under /cpus/<node> with device_type == "cpu". 461 + * If this changes, update this function to include them. 459 462 */ 460 463 int update_cpus_node(void *fdt) 461 464 { 465 + int prev_node_offset; 466 + const char *device_type; 467 + const struct fdt_property *prop; 462 468 struct device_node *cpus_node, *dn; 463 469 int cpus_offset, cpus_subnode_offset, ret = 0; 464 470 ··· 475 469 return cpus_offset; 476 470 } 477 471 478 - if (cpus_offset > 0) { 479 - ret = fdt_del_node(fdt, cpus_offset); 480 - if (ret < 0) { 481 - pr_err("Error deleting /cpus node: %s\n", fdt_strerror(ret)); 482 - return -EINVAL; 472 + prev_node_offset = cpus_offset; 473 + /* Delete sub-nodes of /cpus node with device_type == "cpu" */ 474 + for (cpus_subnode_offset = fdt_first_subnode(fdt, cpus_offset); cpus_subnode_offset >= 0;) { 475 + /* Ignore nodes that do not have a device_type property or device_type != "cpu" */ 476 + prop = fdt_get_property(fdt, cpus_subnode_offset, "device_type", NULL); 477 + if (!prop || strcmp(prop->data, "cpu")) { 478 + prev_node_offset = cpus_subnode_offset; 479 + goto next_node; 483 480 } 481 + 482 + ret = fdt_del_node(fdt, cpus_subnode_offset); 483 + if (ret < 0) { 484 + pr_err("Failed to delete a cpus sub-node: %s\n", fdt_strerror(ret)); 485 + return ret; 486 + } 487 + next_node: 488 + if (prev_node_offset == cpus_offset) 489 + cpus_subnode_offset = fdt_first_subnode(fdt, cpus_offset); 490 + else 491 + cpus_subnode_offset = fdt_next_subnode(fdt, prev_node_offset); 484 492 } 485 493 486 - /* Add cpus node to fdt */ 487 - cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "cpus"); 488 - if (cpus_offset < 0) { 489 - pr_err("Error creating /cpus node: %s\n", fdt_strerror(cpus_offset)); 494 + cpus_node = of_find_node_by_path("/cpus"); 495 + /* Fail here to avoid kexec/kdump kernel boot hung */ 496 + if (!cpus_node) { 497 + pr_err("No /cpus node found\n"); 490 498 return -EINVAL; 491 499 } 492 500 493 - /* Add cpus node properties */ 494 - cpus_node = of_find_node_by_path("/cpus"); 495 - ret = add_node_props(fdt, cpus_offset, cpus_node); 496 - of_node_put(cpus_node); 497 - if (ret < 0) 498 - return ret; 501 + /* Add all /cpus sub-nodes of device_type == "cpu" to FDT */ 502 + for_each_child_of_node(cpus_node, dn) { 503 + /* Ignore device nodes that do not have a device_type property 504 + * or device_type != "cpu". 505 + */ 506 + device_type = of_get_property(dn, "device_type", NULL); 507 + if (!device_type || strcmp(device_type, "cpu")) 508 + continue; 499 509 500 - /* Loop through all subnodes of cpus and add them to fdt */ 501 - for_each_node_by_type(dn, "cpu") { 502 510 cpus_subnode_offset = fdt_add_subnode(fdt, cpus_offset, dn->full_name); 503 511 if (cpus_subnode_offset < 0) { 504 512 pr_err("Unable to add %s subnode: %s\n", dn->full_name, ··· 526 506 goto out; 527 507 } 528 508 out: 509 + of_node_put(cpus_node); 529 510 of_node_put(dn); 530 511 return ret; 531 512 }