|
17 | 17 | #include <linux/cpu.h> |
18 | 18 | #include <linux/hardirq.h> |
19 | 19 | #include <linux/of.h> |
| 20 | +#include <linux/libfdt.h> |
20 | 21 |
|
21 | 22 | #include <asm/page.h> |
22 | 23 | #include <asm/current.h> |
|
32 | 33 | #include <asm/asm-prototypes.h> |
33 | 34 | #include <asm/svm.h> |
34 | 35 | #include <asm/ultravisor.h> |
| 36 | +#include <asm/crashdump-ppc64.h> |
35 | 37 |
|
36 | 38 | int machine_kexec_prepare(struct kimage *image) |
37 | 39 | { |
@@ -430,3 +432,92 @@ static int __init export_htab_values(void) |
430 | 432 | } |
431 | 433 | late_initcall(export_htab_values); |
432 | 434 | #endif /* CONFIG_PPC_64S_HASH_MMU */ |
| 435 | + |
| 436 | +#if defined(CONFIG_KEXEC_FILE) || defined(CONFIG_CRASH_DUMP) |
| 437 | +/** |
| 438 | + * add_node_props - Reads node properties from device node structure and add |
| 439 | + * them to fdt. |
| 440 | + * @fdt: Flattened device tree of the kernel |
| 441 | + * @node_offset: offset of the node to add a property at |
| 442 | + * @dn: device node pointer |
| 443 | + * |
| 444 | + * Returns 0 on success, negative errno on error. |
| 445 | + */ |
| 446 | +static int add_node_props(void *fdt, int node_offset, const struct device_node *dn) |
| 447 | +{ |
| 448 | + int ret = 0; |
| 449 | + struct property *pp; |
| 450 | + |
| 451 | + if (!dn) |
| 452 | + return -EINVAL; |
| 453 | + |
| 454 | + for_each_property_of_node(dn, pp) { |
| 455 | + ret = fdt_setprop(fdt, node_offset, pp->name, pp->value, pp->length); |
| 456 | + if (ret < 0) { |
| 457 | + pr_err("Unable to add %s property: %s\n", pp->name, fdt_strerror(ret)); |
| 458 | + return ret; |
| 459 | + } |
| 460 | + } |
| 461 | + return ret; |
| 462 | +} |
| 463 | + |
| 464 | +/** |
| 465 | + * update_cpus_node - Update cpus node of flattened device tree using of_root |
| 466 | + * device node. |
| 467 | + * @fdt: Flattened device tree of the kernel. |
| 468 | + * |
| 469 | + * Returns 0 on success, negative errno on error. |
| 470 | + */ |
| 471 | +int update_cpus_node(void *fdt) |
| 472 | +{ |
| 473 | + struct device_node *cpus_node, *dn; |
| 474 | + int cpus_offset, cpus_subnode_offset, ret = 0; |
| 475 | + |
| 476 | + cpus_offset = fdt_path_offset(fdt, "/cpus"); |
| 477 | + if (cpus_offset < 0 && cpus_offset != -FDT_ERR_NOTFOUND) { |
| 478 | + pr_err("Malformed device tree: error reading /cpus node: %s\n", |
| 479 | + fdt_strerror(cpus_offset)); |
| 480 | + return cpus_offset; |
| 481 | + } |
| 482 | + |
| 483 | + if (cpus_offset > 0) { |
| 484 | + ret = fdt_del_node(fdt, cpus_offset); |
| 485 | + if (ret < 0) { |
| 486 | + pr_err("Error deleting /cpus node: %s\n", fdt_strerror(ret)); |
| 487 | + return -EINVAL; |
| 488 | + } |
| 489 | + } |
| 490 | + |
| 491 | + /* Add cpus node to fdt */ |
| 492 | + cpus_offset = fdt_add_subnode(fdt, fdt_path_offset(fdt, "/"), "cpus"); |
| 493 | + if (cpus_offset < 0) { |
| 494 | + pr_err("Error creating /cpus node: %s\n", fdt_strerror(cpus_offset)); |
| 495 | + return -EINVAL; |
| 496 | + } |
| 497 | + |
| 498 | + /* Add cpus node properties */ |
| 499 | + cpus_node = of_find_node_by_path("/cpus"); |
| 500 | + ret = add_node_props(fdt, cpus_offset, cpus_node); |
| 501 | + of_node_put(cpus_node); |
| 502 | + if (ret < 0) |
| 503 | + return ret; |
| 504 | + |
| 505 | + /* Loop through all subnodes of cpus and add them to fdt */ |
| 506 | + for_each_node_by_type(dn, "cpu") { |
| 507 | + cpus_subnode_offset = fdt_add_subnode(fdt, cpus_offset, dn->full_name); |
| 508 | + if (cpus_subnode_offset < 0) { |
| 509 | + pr_err("Unable to add %s subnode: %s\n", dn->full_name, |
| 510 | + fdt_strerror(cpus_subnode_offset)); |
| 511 | + ret = cpus_subnode_offset; |
| 512 | + goto out; |
| 513 | + } |
| 514 | + |
| 515 | + ret = add_node_props(fdt, cpus_subnode_offset, dn); |
| 516 | + if (ret < 0) |
| 517 | + goto out; |
| 518 | + } |
| 519 | +out: |
| 520 | + of_node_put(dn); |
| 521 | + return ret; |
| 522 | +} |
| 523 | +#endif /* CONFIG_KEXEC_FILE || CONFIG_CRASH_DUMP */ |
0 commit comments