linux/arch/powerpc/platforms/powernv/opal-fadump.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-or-later
   2/*
   3 * Firmware-Assisted Dump support on POWER platform (OPAL).
   4 *
   5 * Copyright 2019, Hari Bathini, IBM Corporation.
   6 */
   7
   8#define pr_fmt(fmt) "opal fadump: " fmt
   9
  10#include <linux/string.h>
  11#include <linux/seq_file.h>
  12#include <linux/of.h>
  13#include <linux/of_fdt.h>
  14#include <linux/libfdt.h>
  15#include <linux/mm.h>
  16#include <linux/crash_dump.h>
  17
  18#include <asm/page.h>
  19#include <asm/opal.h>
  20#include <asm/fadump-internal.h>
  21
  22#include "opal-fadump.h"
  23
  24
  25#ifdef CONFIG_PRESERVE_FA_DUMP
  26/*
  27 * When dump is active but PRESERVE_FA_DUMP is enabled on the kernel,
  28 * ensure crash data is preserved in hope that the subsequent memory
  29 * preserving kernel boot is going to process this crash data.
  30 */
  31void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
  32{
  33        const struct opal_fadump_mem_struct *opal_fdm_active;
  34        const __be32 *prop;
  35        unsigned long dn;
  36        u64 addr = 0;
  37        s64 ret;
  38
  39        dn = of_get_flat_dt_subnode_by_name(node, "dump");
  40        if (dn == -FDT_ERR_NOTFOUND)
  41                return;
  42
  43        /*
  44         * Check if dump has been initiated on last reboot.
  45         */
  46        prop = of_get_flat_dt_prop(dn, "mpipl-boot", NULL);
  47        if (!prop)
  48                return;
  49
  50        ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &addr);
  51        if ((ret != OPAL_SUCCESS) || !addr) {
  52                pr_debug("Could not get Kernel metadata (%lld)\n", ret);
  53                return;
  54        }
  55
  56        /*
  57         * Preserve memory only if kernel memory regions are registered
  58         * with f/w for MPIPL.
  59         */
  60        addr = be64_to_cpu(addr);
  61        pr_debug("Kernel metadata addr: %llx\n", addr);
  62        opal_fdm_active = (void *)addr;
  63        if (opal_fdm_active->registered_regions == 0)
  64                return;
  65
  66        ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_BOOT_MEM, &addr);
  67        if ((ret != OPAL_SUCCESS) || !addr) {
  68                pr_err("Failed to get boot memory tag (%lld)\n", ret);
  69                return;
  70        }
  71
  72        /*
  73         * Memory below this address can be used for booting a
  74         * capture kernel or petitboot kernel. Preserve everything
  75         * above this address for processing crashdump.
  76         */
  77        fadump_conf->boot_mem_top = be64_to_cpu(addr);
  78        pr_debug("Preserve everything above %llx\n", fadump_conf->boot_mem_top);
  79
  80        pr_info("Firmware-assisted dump is active.\n");
  81        fadump_conf->dump_active = 1;
  82}
  83
  84#else /* CONFIG_PRESERVE_FA_DUMP */
  85static const struct opal_fadump_mem_struct *opal_fdm_active;
  86static const struct opal_mpipl_fadump *opal_cpu_metadata;
  87static struct opal_fadump_mem_struct *opal_fdm;
  88
  89#ifdef CONFIG_OPAL_CORE
  90extern bool kernel_initiated;
  91#endif
  92
  93static int opal_fadump_unregister(struct fw_dump *fadump_conf);
  94
  95static void opal_fadump_update_config(struct fw_dump *fadump_conf,
  96                                      const struct opal_fadump_mem_struct *fdm)
  97{
  98        pr_debug("Boot memory regions count: %d\n", fdm->region_cnt);
  99
 100        /*
 101         * The destination address of the first boot memory region is the
 102         * destination address of boot memory regions.
 103         */
 104        fadump_conf->boot_mem_dest_addr = fdm->rgn[0].dest;
 105        pr_debug("Destination address of boot memory regions: %#016llx\n",
 106                 fadump_conf->boot_mem_dest_addr);
 107
 108        fadump_conf->fadumphdr_addr = fdm->fadumphdr_addr;
 109}
 110
 111/*
 112 * This function is called in the capture kernel to get configuration details
 113 * from metadata setup by the first kernel.
 114 */
 115static void opal_fadump_get_config(struct fw_dump *fadump_conf,
 116                                   const struct opal_fadump_mem_struct *fdm)
 117{
 118        unsigned long base, size, last_end, hole_size;
 119        int i;
 120
 121        if (!fadump_conf->dump_active)
 122                return;
 123
 124        last_end = 0;
 125        hole_size = 0;
 126        fadump_conf->boot_memory_size = 0;
 127
 128        pr_debug("Boot memory regions:\n");
 129        for (i = 0; i < fdm->region_cnt; i++) {
 130                base = fdm->rgn[i].src;
 131                size = fdm->rgn[i].size;
 132                pr_debug("\t[%03d] base: 0x%lx, size: 0x%lx\n", i, base, size);
 133
 134                fadump_conf->boot_mem_addr[i] = base;
 135                fadump_conf->boot_mem_sz[i] = size;
 136                fadump_conf->boot_memory_size += size;
 137                hole_size += (base - last_end);
 138
 139                last_end = base + size;
 140        }
 141
 142        /*
 143         * Start address of reserve dump area (permanent reservation) for
 144         * re-registering FADump after dump capture.
 145         */
 146        fadump_conf->reserve_dump_area_start = fdm->rgn[0].dest;
 147
 148        /*
 149         * Rarely, but it can so happen that system crashes before all
 150         * boot memory regions are registered for MPIPL. In such
 151         * cases, warn that the vmcore may not be accurate and proceed
 152         * anyway as that is the best bet considering free pages, cache
 153         * pages, user pages, etc are usually filtered out.
 154         *
 155         * Hope the memory that could not be preserved only has pages
 156         * that are usually filtered out while saving the vmcore.
 157         */
 158        if (fdm->region_cnt > fdm->registered_regions) {
 159                pr_warn("Not all memory regions were saved!!!\n");
 160                pr_warn("  Unsaved memory regions:\n");
 161                i = fdm->registered_regions;
 162                while (i < fdm->region_cnt) {
 163                        pr_warn("\t[%03d] base: 0x%llx, size: 0x%llx\n",
 164                                i, fdm->rgn[i].src, fdm->rgn[i].size);
 165                        i++;
 166                }
 167
 168                pr_warn("If the unsaved regions only contain pages that are filtered out (eg. free/user pages), the vmcore should still be usable.\n");
 169                pr_warn("WARNING: If the unsaved regions contain kernel pages, the vmcore will be corrupted.\n");
 170        }
 171
 172        fadump_conf->boot_mem_top = (fadump_conf->boot_memory_size + hole_size);
 173        fadump_conf->boot_mem_regs_cnt = fdm->region_cnt;
 174        opal_fadump_update_config(fadump_conf, fdm);
 175}
 176
 177/* Initialize kernel metadata */
 178static void opal_fadump_init_metadata(struct opal_fadump_mem_struct *fdm)
 179{
 180        fdm->version = OPAL_FADUMP_VERSION;
 181        fdm->region_cnt = 0;
 182        fdm->registered_regions = 0;
 183        fdm->fadumphdr_addr = 0;
 184}
 185
 186static u64 opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
 187{
 188        u64 addr = fadump_conf->reserve_dump_area_start;
 189        int i;
 190
 191        opal_fdm = __va(fadump_conf->kernel_metadata);
 192        opal_fadump_init_metadata(opal_fdm);
 193
 194        /* Boot memory regions */
 195        for (i = 0; i < fadump_conf->boot_mem_regs_cnt; i++) {
 196                opal_fdm->rgn[i].src    = fadump_conf->boot_mem_addr[i];
 197                opal_fdm->rgn[i].dest   = addr;
 198                opal_fdm->rgn[i].size   = fadump_conf->boot_mem_sz[i];
 199
 200                opal_fdm->region_cnt++;
 201                addr += fadump_conf->boot_mem_sz[i];
 202        }
 203
 204        /*
 205         * Kernel metadata is passed to f/w and retrieved in capture kerenl.
 206         * So, use it to save fadump header address instead of calculating it.
 207         */
 208        opal_fdm->fadumphdr_addr = (opal_fdm->rgn[0].dest +
 209                                    fadump_conf->boot_memory_size);
 210
 211        opal_fadump_update_config(fadump_conf, opal_fdm);
 212
 213        return addr;
 214}
 215
 216static u64 opal_fadump_get_metadata_size(void)
 217{
 218        return PAGE_ALIGN(sizeof(struct opal_fadump_mem_struct));
 219}
 220
 221static int opal_fadump_setup_metadata(struct fw_dump *fadump_conf)
 222{
 223        int err = 0;
 224        s64 ret;
 225
 226        /*
 227         * Use the last page(s) in FADump memory reservation for
 228         * kernel metadata.
 229         */
 230        fadump_conf->kernel_metadata = (fadump_conf->reserve_dump_area_start +
 231                                        fadump_conf->reserve_dump_area_size -
 232                                        opal_fadump_get_metadata_size());
 233        pr_info("Kernel metadata addr: %llx\n", fadump_conf->kernel_metadata);
 234
 235        /* Initialize kernel metadata before registering the address with f/w */
 236        opal_fdm = __va(fadump_conf->kernel_metadata);
 237        opal_fadump_init_metadata(opal_fdm);
 238
 239        /*
 240         * Register metadata address with f/w. Can be retrieved in
 241         * the capture kernel.
 242         */
 243        ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_KERNEL,
 244                                      fadump_conf->kernel_metadata);
 245        if (ret != OPAL_SUCCESS) {
 246                pr_err("Failed to set kernel metadata tag!\n");
 247                err = -EPERM;
 248        }
 249
 250        /*
 251         * Register boot memory top address with f/w. Should be retrieved
 252         * by a kernel that intends to preserve crash'ed kernel's memory.
 253         */
 254        ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_BOOT_MEM,
 255                                      fadump_conf->boot_mem_top);
 256        if (ret != OPAL_SUCCESS) {
 257                pr_err("Failed to set boot memory tag!\n");
 258                err = -EPERM;
 259        }
 260
 261        return err;
 262}
 263
 264static u64 opal_fadump_get_bootmem_min(void)
 265{
 266        return OPAL_FADUMP_MIN_BOOT_MEM;
 267}
 268
 269static int opal_fadump_register(struct fw_dump *fadump_conf)
 270{
 271        s64 rc = OPAL_PARAMETER;
 272        int i, err = -EIO;
 273
 274        for (i = 0; i < opal_fdm->region_cnt; i++) {
 275                rc = opal_mpipl_update(OPAL_MPIPL_ADD_RANGE,
 276                                       opal_fdm->rgn[i].src,
 277                                       opal_fdm->rgn[i].dest,
 278                                       opal_fdm->rgn[i].size);
 279                if (rc != OPAL_SUCCESS)
 280                        break;
 281
 282                opal_fdm->registered_regions++;
 283        }
 284
 285        switch (rc) {
 286        case OPAL_SUCCESS:
 287                pr_info("Registration is successful!\n");
 288                fadump_conf->dump_registered = 1;
 289                err = 0;
 290                break;
 291        case OPAL_RESOURCE:
 292                /* If MAX regions limit in f/w is hit, warn and proceed. */
 293                pr_warn("%d regions could not be registered for MPIPL as MAX limit is reached!\n",
 294                        (opal_fdm->region_cnt - opal_fdm->registered_regions));
 295                fadump_conf->dump_registered = 1;
 296                err = 0;
 297                break;
 298        case OPAL_PARAMETER:
 299                pr_err("Failed to register. Parameter Error(%lld).\n", rc);
 300                break;
 301        case OPAL_HARDWARE:
 302                pr_err("Support not available.\n");
 303                fadump_conf->fadump_supported = 0;
 304                fadump_conf->fadump_enabled = 0;
 305                break;
 306        default:
 307                pr_err("Failed to register. Unknown Error(%lld).\n", rc);
 308                break;
 309        }
 310
 311        /*
 312         * If some regions were registered before OPAL_MPIPL_ADD_RANGE
 313         * OPAL call failed, unregister all regions.
 314         */
 315        if ((err < 0) && (opal_fdm->registered_regions > 0))
 316                opal_fadump_unregister(fadump_conf);
 317
 318        return err;
 319}
 320
 321static int opal_fadump_unregister(struct fw_dump *fadump_conf)
 322{
 323        s64 rc;
 324
 325        rc = opal_mpipl_update(OPAL_MPIPL_REMOVE_ALL, 0, 0, 0);
 326        if (rc) {
 327                pr_err("Failed to un-register - unexpected Error(%lld).\n", rc);
 328                return -EIO;
 329        }
 330
 331        opal_fdm->registered_regions = 0;
 332        fadump_conf->dump_registered = 0;
 333        return 0;
 334}
 335
 336static int opal_fadump_invalidate(struct fw_dump *fadump_conf)
 337{
 338        s64 rc;
 339
 340        rc = opal_mpipl_update(OPAL_MPIPL_FREE_PRESERVED_MEMORY, 0, 0, 0);
 341        if (rc) {
 342                pr_err("Failed to invalidate - unexpected Error(%lld).\n", rc);
 343                return -EIO;
 344        }
 345
 346        fadump_conf->dump_active = 0;
 347        opal_fdm_active = NULL;
 348        return 0;
 349}
 350
 351static void opal_fadump_cleanup(struct fw_dump *fadump_conf)
 352{
 353        s64 ret;
 354
 355        ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_KERNEL, 0);
 356        if (ret != OPAL_SUCCESS)
 357                pr_warn("Could not reset (%llu) kernel metadata tag!\n", ret);
 358}
 359
 360/*
 361 * Verify if CPU state data is available. If available, do a bit of sanity
 362 * checking before processing this data.
 363 */
 364static bool __init is_opal_fadump_cpu_data_valid(struct fw_dump *fadump_conf)
 365{
 366        if (!opal_cpu_metadata)
 367                return false;
 368
 369        fadump_conf->cpu_state_data_version =
 370                be32_to_cpu(opal_cpu_metadata->cpu_data_version);
 371        fadump_conf->cpu_state_entry_size =
 372                be32_to_cpu(opal_cpu_metadata->cpu_data_size);
 373        fadump_conf->cpu_state_dest_vaddr =
 374                (u64)__va(be64_to_cpu(opal_cpu_metadata->region[0].dest));
 375        fadump_conf->cpu_state_data_size =
 376                be64_to_cpu(opal_cpu_metadata->region[0].size);
 377
 378        if (fadump_conf->cpu_state_data_version != HDAT_FADUMP_CPU_DATA_VER) {
 379                pr_warn("Supported CPU state data version: %u, found: %d!\n",
 380                        HDAT_FADUMP_CPU_DATA_VER,
 381                        fadump_conf->cpu_state_data_version);
 382                pr_warn("WARNING: F/W using newer CPU state data format!!\n");
 383        }
 384
 385        if ((fadump_conf->cpu_state_dest_vaddr == 0) ||
 386            (fadump_conf->cpu_state_entry_size == 0) ||
 387            (fadump_conf->cpu_state_entry_size >
 388             fadump_conf->cpu_state_data_size)) {
 389                pr_err("CPU state data is invalid. Ignoring!\n");
 390                return false;
 391        }
 392
 393        return true;
 394}
 395
 396/*
 397 * Convert CPU state data saved at the time of crash into ELF notes.
 398 *
 399 * While the crashing CPU's register data is saved by the kernel, CPU state
 400 * data for all CPUs is saved by f/w. In CPU state data provided by f/w,
 401 * each register entry is of 16 bytes, a numerical identifier along with
 402 * a GPR/SPR flag in the first 8 bytes and the register value in the next
 403 * 8 bytes. For more details refer to F/W documentation. If this data is
 404 * missing or in unsupported format, append crashing CPU's register data
 405 * saved by the kernel in the PT_NOTE, to have something to work with in
 406 * the vmcore file.
 407 */
 408static int __init
 409opal_fadump_build_cpu_notes(struct fw_dump *fadump_conf,
 410                            struct fadump_crash_info_header *fdh)
 411{
 412        u32 thread_pir, size_per_thread, regs_offset, regs_cnt, reg_esize;
 413        struct hdat_fadump_thread_hdr *thdr;
 414        bool is_cpu_data_valid = false;
 415        u32 num_cpus = 1, *note_buf;
 416        struct pt_regs regs;
 417        char *bufp;
 418        int rc, i;
 419
 420        if (is_opal_fadump_cpu_data_valid(fadump_conf)) {
 421                size_per_thread = fadump_conf->cpu_state_entry_size;
 422                num_cpus = (fadump_conf->cpu_state_data_size / size_per_thread);
 423                bufp = __va(fadump_conf->cpu_state_dest_vaddr);
 424                is_cpu_data_valid = true;
 425        }
 426
 427        rc = fadump_setup_cpu_notes_buf(num_cpus);
 428        if (rc != 0)
 429                return rc;
 430
 431        note_buf = (u32 *)fadump_conf->cpu_notes_buf_vaddr;
 432        if (!is_cpu_data_valid)
 433                goto out;
 434
 435        /*
 436         * Offset for register entries, entry size and registers count is
 437         * duplicated in every thread header in keeping with HDAT format.
 438         * Use these values from the first thread header.
 439         */
 440        thdr = (struct hdat_fadump_thread_hdr *)bufp;
 441        regs_offset = (offsetof(struct hdat_fadump_thread_hdr, offset) +
 442                       be32_to_cpu(thdr->offset));
 443        reg_esize = be32_to_cpu(thdr->esize);
 444        regs_cnt  = be32_to_cpu(thdr->ecnt);
 445
 446        pr_debug("--------CPU State Data------------\n");
 447        pr_debug("NumCpus     : %u\n", num_cpus);
 448        pr_debug("\tOffset: %u, Entry size: %u, Cnt: %u\n",
 449                 regs_offset, reg_esize, regs_cnt);
 450
 451        for (i = 0; i < num_cpus; i++, bufp += size_per_thread) {
 452                thdr = (struct hdat_fadump_thread_hdr *)bufp;
 453
 454                thread_pir = be32_to_cpu(thdr->pir);
 455                pr_debug("[%04d] PIR: 0x%x, core state: 0x%02x\n",
 456                         i, thread_pir, thdr->core_state);
 457
 458                /*
 459                 * If this is kernel initiated crash, crashing_cpu would be set
 460                 * appropriately and register data of the crashing CPU saved by
 461                 * crashing kernel. Add this saved register data of crashing CPU
 462                 * to elf notes and populate the pt_regs for the remaining CPUs
 463                 * from register state data provided by firmware.
 464                 */
 465                if (fdh->crashing_cpu == thread_pir) {
 466                        note_buf = fadump_regs_to_elf_notes(note_buf,
 467                                                            &fdh->regs);
 468                        pr_debug("Crashing CPU PIR: 0x%x - R1 : 0x%lx, NIP : 0x%lx\n",
 469                                 fdh->crashing_cpu, fdh->regs.gpr[1],
 470                                 fdh->regs.nip);
 471                        continue;
 472                }
 473
 474                /*
 475                 * Register state data of MAX cores is provided by firmware,
 476                 * but some of this cores may not be active. So, while
 477                 * processing register state data, check core state and
 478                 * skip threads that belong to inactive cores.
 479                 */
 480                if (thdr->core_state == HDAT_FADUMP_CORE_INACTIVE)
 481                        continue;
 482
 483                opal_fadump_read_regs((bufp + regs_offset), regs_cnt,
 484                                      reg_esize, true, &regs);
 485                note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
 486                pr_debug("CPU PIR: 0x%x - R1 : 0x%lx, NIP : 0x%lx\n",
 487                         thread_pir, regs.gpr[1], regs.nip);
 488        }
 489
 490out:
 491        /*
 492         * CPU state data is invalid/unsupported. Try appending crashing CPU's
 493         * register data, if it is saved by the kernel.
 494         */
 495        if (fadump_conf->cpu_notes_buf_vaddr == (u64)note_buf) {
 496                if (fdh->crashing_cpu == FADUMP_CPU_UNKNOWN) {
 497                        fadump_free_cpu_notes_buf();
 498                        return -ENODEV;
 499                }
 500
 501                pr_warn("WARNING: appending only crashing CPU's register data\n");
 502                note_buf = fadump_regs_to_elf_notes(note_buf, &(fdh->regs));
 503        }
 504
 505        final_note(note_buf);
 506
 507        pr_debug("Updating elfcore header (%llx) with cpu notes\n",
 508                 fdh->elfcorehdr_addr);
 509        fadump_update_elfcore_header(__va(fdh->elfcorehdr_addr));
 510        return 0;
 511}
 512
 513static int __init opal_fadump_process(struct fw_dump *fadump_conf)
 514{
 515        struct fadump_crash_info_header *fdh;
 516        int rc = -EINVAL;
 517
 518        if (!opal_fdm_active || !fadump_conf->fadumphdr_addr)
 519                return rc;
 520
 521        /* Validate the fadump crash info header */
 522        fdh = __va(fadump_conf->fadumphdr_addr);
 523        if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) {
 524                pr_err("Crash info header is not valid.\n");
 525                return rc;
 526        }
 527
 528#ifdef CONFIG_OPAL_CORE
 529        /*
 530         * If this is a kernel initiated crash, crashing_cpu would be set
 531         * appropriately and register data of the crashing CPU saved by
 532         * crashing kernel. Add this saved register data of crashing CPU
 533         * to elf notes and populate the pt_regs for the remaining CPUs
 534         * from register state data provided by firmware.
 535         */
 536        if (fdh->crashing_cpu != FADUMP_CPU_UNKNOWN)
 537                kernel_initiated = true;
 538#endif
 539
 540        rc = opal_fadump_build_cpu_notes(fadump_conf, fdh);
 541        if (rc)
 542                return rc;
 543
 544        /*
 545         * We are done validating dump info and elfcore header is now ready
 546         * to be exported. set elfcorehdr_addr so that vmcore module will
 547         * export the elfcore header through '/proc/vmcore'.
 548         */
 549        elfcorehdr_addr = fdh->elfcorehdr_addr;
 550
 551        return rc;
 552}
 553
 554static void opal_fadump_region_show(struct fw_dump *fadump_conf,
 555                                    struct seq_file *m)
 556{
 557        const struct opal_fadump_mem_struct *fdm_ptr;
 558        u64 dumped_bytes = 0;
 559        int i;
 560
 561        if (fadump_conf->dump_active)
 562                fdm_ptr = opal_fdm_active;
 563        else
 564                fdm_ptr = opal_fdm;
 565
 566        for (i = 0; i < fdm_ptr->region_cnt; i++) {
 567                /*
 568                 * Only regions that are registered for MPIPL
 569                 * would have dump data.
 570                 */
 571                if ((fadump_conf->dump_active) &&
 572                    (i < fdm_ptr->registered_regions))
 573                        dumped_bytes = fdm_ptr->rgn[i].size;
 574
 575                seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
 576                           fdm_ptr->rgn[i].src, fdm_ptr->rgn[i].dest);
 577                seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
 578                           fdm_ptr->rgn[i].size, dumped_bytes);
 579        }
 580
 581        /* Dump is active. Show reserved area start address. */
 582        if (fadump_conf->dump_active) {
 583                seq_printf(m, "\nMemory above %#016lx is reserved for saving crash dump\n",
 584                           fadump_conf->reserve_dump_area_start);
 585        }
 586}
 587
 588static void opal_fadump_trigger(struct fadump_crash_info_header *fdh,
 589                                const char *msg)
 590{
 591        int rc;
 592
 593        /*
 594         * Unlike on pSeries platform, logical CPU number is not provided
 595         * with architected register state data. So, store the crashing
 596         * CPU's PIR instead to plug the appropriate register data for
 597         * crashing CPU in the vmcore file.
 598         */
 599        fdh->crashing_cpu = (u32)mfspr(SPRN_PIR);
 600
 601        rc = opal_cec_reboot2(OPAL_REBOOT_MPIPL, msg);
 602        if (rc == OPAL_UNSUPPORTED) {
 603                pr_emerg("Reboot type %d not supported.\n",
 604                         OPAL_REBOOT_MPIPL);
 605        } else if (rc == OPAL_HARDWARE)
 606                pr_emerg("No backend support for MPIPL!\n");
 607}
 608
 609static struct fadump_ops opal_fadump_ops = {
 610        .fadump_init_mem_struct         = opal_fadump_init_mem_struct,
 611        .fadump_get_metadata_size       = opal_fadump_get_metadata_size,
 612        .fadump_setup_metadata          = opal_fadump_setup_metadata,
 613        .fadump_get_bootmem_min         = opal_fadump_get_bootmem_min,
 614        .fadump_register                = opal_fadump_register,
 615        .fadump_unregister              = opal_fadump_unregister,
 616        .fadump_invalidate              = opal_fadump_invalidate,
 617        .fadump_cleanup                 = opal_fadump_cleanup,
 618        .fadump_process                 = opal_fadump_process,
 619        .fadump_region_show             = opal_fadump_region_show,
 620        .fadump_trigger                 = opal_fadump_trigger,
 621};
 622
 623void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
 624{
 625        const __be32 *prop;
 626        unsigned long dn;
 627        u64 addr = 0;
 628        int i, len;
 629        s64 ret;
 630
 631        /*
 632         * Check if Firmware-Assisted Dump is supported. if yes, check
 633         * if dump has been initiated on last reboot.
 634         */
 635        dn = of_get_flat_dt_subnode_by_name(node, "dump");
 636        if (dn == -FDT_ERR_NOTFOUND) {
 637                pr_debug("FADump support is missing!\n");
 638                return;
 639        }
 640
 641        if (!of_flat_dt_is_compatible(dn, "ibm,opal-dump")) {
 642                pr_err("Support missing for this f/w version!\n");
 643                return;
 644        }
 645
 646        prop = of_get_flat_dt_prop(dn, "fw-load-area", &len);
 647        if (prop) {
 648                /*
 649                 * Each f/w load area is an (address,size) pair,
 650                 * 2 cells each, totalling 4 cells per range.
 651                 */
 652                for (i = 0; i < len / (sizeof(*prop) * 4); i++) {
 653                        u64 base, end;
 654
 655                        base = of_read_number(prop + (i * 4) + 0, 2);
 656                        end = base;
 657                        end += of_read_number(prop + (i * 4) + 2, 2);
 658                        if (end > OPAL_FADUMP_MIN_BOOT_MEM) {
 659                                pr_err("F/W load area: 0x%llx-0x%llx\n",
 660                                       base, end);
 661                                pr_err("F/W version not supported!\n");
 662                                return;
 663                        }
 664                }
 665        }
 666
 667        fadump_conf->ops                = &opal_fadump_ops;
 668        fadump_conf->fadump_supported   = 1;
 669
 670        /*
 671         * Firmware supports 32-bit field for size. Align it to PAGE_SIZE
 672         * and request firmware to copy multiple kernel boot memory regions.
 673         */
 674        fadump_conf->max_copy_size = ALIGN_DOWN(U32_MAX, PAGE_SIZE);
 675
 676        /*
 677         * Check if dump has been initiated on last reboot.
 678         */
 679        prop = of_get_flat_dt_prop(dn, "mpipl-boot", NULL);
 680        if (!prop)
 681                return;
 682
 683        ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &addr);
 684        if ((ret != OPAL_SUCCESS) || !addr) {
 685                pr_err("Failed to get Kernel metadata (%lld)\n", ret);
 686                return;
 687        }
 688
 689        addr = be64_to_cpu(addr);
 690        pr_debug("Kernel metadata addr: %llx\n", addr);
 691
 692        opal_fdm_active = __va(addr);
 693        if (opal_fdm_active->version != OPAL_FADUMP_VERSION) {
 694                pr_warn("Supported kernel metadata version: %u, found: %d!\n",
 695                        OPAL_FADUMP_VERSION, opal_fdm_active->version);
 696                pr_warn("WARNING: Kernel metadata format mismatch identified! Core file maybe corrupted..\n");
 697        }
 698
 699        /* Kernel regions not registered with f/w for MPIPL */
 700        if (opal_fdm_active->registered_regions == 0) {
 701                opal_fdm_active = NULL;
 702                return;
 703        }
 704
 705        ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &addr);
 706        if (addr) {
 707                addr = be64_to_cpu(addr);
 708                pr_debug("CPU metadata addr: %llx\n", addr);
 709                opal_cpu_metadata = __va(addr);
 710        }
 711
 712        pr_info("Firmware-assisted dump is active.\n");
 713        fadump_conf->dump_active = 1;
 714        opal_fadump_get_config(fadump_conf, opal_fdm_active);
 715}
 716#endif /* !CONFIG_PRESERVE_FA_DUMP */
 717