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