|
16 | 16 | #include <linux/delay.h> |
17 | 17 | #include <linux/irq.h> |
18 | 18 | #include <linux/types.h> |
| 19 | +#include <linux/libfdt.h> |
19 | 20 |
|
20 | 21 | #include <asm/processor.h> |
21 | 22 | #include <asm/machdep.h> |
@@ -376,3 +377,105 @@ void default_machine_crash_shutdown(struct pt_regs *regs) |
376 | 377 | if (ppc_md.kexec_cpu_down) |
377 | 378 | ppc_md.kexec_cpu_down(1, 0); |
378 | 379 | } |
| 380 | + |
| 381 | +#ifdef CONFIG_CRASH_HOTPLUG |
| 382 | +#undef pr_fmt |
| 383 | +#define pr_fmt(fmt) "crash hp: " fmt |
| 384 | + |
| 385 | +/** |
| 386 | + * get_fdt_index - Loop through the kexec segment array and find |
| 387 | + * the index of the FDT segment. |
| 388 | + * @image: a pointer to kexec_crash_image |
| 389 | + * |
| 390 | + * Returns the index of FDT segment in the kexec segment array |
| 391 | + * if found; otherwise -1. |
| 392 | + */ |
| 393 | +static int get_fdt_index(struct kimage *image) |
| 394 | +{ |
| 395 | + void *ptr; |
| 396 | + unsigned long mem; |
| 397 | + int i, fdt_index = -1; |
| 398 | + |
| 399 | + /* Find the FDT segment index in kexec segment array. */ |
| 400 | + for (i = 0; i < image->nr_segments; i++) { |
| 401 | + mem = image->segment[i].mem; |
| 402 | + ptr = __va(mem); |
| 403 | + |
| 404 | + if (ptr && fdt_magic(ptr) == FDT_MAGIC) { |
| 405 | + fdt_index = i; |
| 406 | + break; |
| 407 | + } |
| 408 | + } |
| 409 | + |
| 410 | + return fdt_index; |
| 411 | +} |
| 412 | + |
| 413 | +/** |
| 414 | + * update_crash_fdt - updates the cpus node of the crash FDT. |
| 415 | + * |
| 416 | + * @image: a pointer to kexec_crash_image |
| 417 | + */ |
| 418 | +static void update_crash_fdt(struct kimage *image) |
| 419 | +{ |
| 420 | + void *fdt; |
| 421 | + int fdt_index; |
| 422 | + |
| 423 | + fdt_index = get_fdt_index(image); |
| 424 | + if (fdt_index < 0) { |
| 425 | + pr_err("Unable to locate FDT segment.\n"); |
| 426 | + return; |
| 427 | + } |
| 428 | + |
| 429 | + fdt = __va((void *)image->segment[fdt_index].mem); |
| 430 | + |
| 431 | + /* Temporarily invalidate the crash image while it is replaced */ |
| 432 | + xchg(&kexec_crash_image, NULL); |
| 433 | + |
| 434 | + /* update FDT to reflect changes in CPU resources */ |
| 435 | + if (update_cpus_node(fdt)) |
| 436 | + pr_err("Failed to update crash FDT"); |
| 437 | + |
| 438 | + /* The crash image is now valid once again */ |
| 439 | + xchg(&kexec_crash_image, image); |
| 440 | +} |
| 441 | + |
| 442 | +int arch_crash_hotplug_support(struct kimage *image, unsigned long kexec_flags) |
| 443 | +{ |
| 444 | +#ifdef CONFIG_KEXEC_FILE |
| 445 | + if (image->file_mode) |
| 446 | + return 1; |
| 447 | +#endif |
| 448 | + return kexec_flags & KEXEC_CRASH_HOTPLUG_SUPPORT; |
| 449 | +} |
| 450 | + |
| 451 | +/** |
| 452 | + * arch_crash_handle_hotplug_event - Handle crash CPU/Memory hotplug events to update the |
| 453 | + * necessary kexec segments based on the hotplug event. |
| 454 | + * @image: a pointer to kexec_crash_image |
| 455 | + * @arg: struct memory_notify handler for memory hotplug case and NULL for CPU hotplug case. |
| 456 | + * |
| 457 | + * Update the kdump image based on the type of hotplug event, represented by image->hp_action. |
| 458 | + * CPU add: Update the FDT segment to include the newly added CPU. |
| 459 | + * CPU remove: No action is needed, with the assumption that it's okay to have offline CPUs |
| 460 | + * part of the FDT. |
| 461 | + * Memory add/remove: No action is taken as this is not yet supported. |
| 462 | + */ |
| 463 | +void arch_crash_handle_hotplug_event(struct kimage *image, void *arg) |
| 464 | +{ |
| 465 | + switch (image->hp_action) { |
| 466 | + case KEXEC_CRASH_HP_REMOVE_CPU: |
| 467 | + return; |
| 468 | + |
| 469 | + case KEXEC_CRASH_HP_ADD_CPU: |
| 470 | + update_crash_fdt(image); |
| 471 | + break; |
| 472 | + |
| 473 | + case KEXEC_CRASH_HP_REMOVE_MEMORY: |
| 474 | + case KEXEC_CRASH_HP_ADD_MEMORY: |
| 475 | + pr_info_once("Crash update is not supported for memory hotplug\n"); |
| 476 | + return; |
| 477 | + default: |
| 478 | + pr_warn_once("Unknown hotplug action\n"); |
| 479 | + } |
| 480 | +} |
| 481 | +#endif /* CONFIG_CRASH_HOTPLUG */ |
0 commit comments