Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-or-later
0002 /*
0003  * Firmware-Assisted Dump support on POWER platform (OPAL).
0004  *
0005  * Copyright 2019, Hari Bathini, IBM Corporation.
0006  */
0007 
0008 #define pr_fmt(fmt) "opal fadump: " fmt
0009 
0010 #include <linux/string.h>
0011 #include <linux/seq_file.h>
0012 #include <linux/of.h>
0013 #include <linux/of_fdt.h>
0014 #include <linux/libfdt.h>
0015 #include <linux/mm.h>
0016 #include <linux/crash_dump.h>
0017 
0018 #include <asm/page.h>
0019 #include <asm/opal.h>
0020 #include <asm/fadump-internal.h>
0021 
0022 #include "opal-fadump.h"
0023 
0024 
0025 #ifdef CONFIG_PRESERVE_FA_DUMP
0026 /*
0027  * When dump is active but PRESERVE_FA_DUMP is enabled on the kernel,
0028  * ensure crash data is preserved in hope that the subsequent memory
0029  * preserving kernel boot is going to process this crash data.
0030  */
0031 void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
0032 {
0033     const struct opal_fadump_mem_struct *opal_fdm_active;
0034     const __be32 *prop;
0035     unsigned long dn;
0036     u64 addr = 0;
0037     s64 ret;
0038 
0039     dn = of_get_flat_dt_subnode_by_name(node, "dump");
0040     if (dn == -FDT_ERR_NOTFOUND)
0041         return;
0042 
0043     /*
0044      * Check if dump has been initiated on last reboot.
0045      */
0046     prop = of_get_flat_dt_prop(dn, "mpipl-boot", NULL);
0047     if (!prop)
0048         return;
0049 
0050     ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &addr);
0051     if ((ret != OPAL_SUCCESS) || !addr) {
0052         pr_debug("Could not get Kernel metadata (%lld)\n", ret);
0053         return;
0054     }
0055 
0056     /*
0057      * Preserve memory only if kernel memory regions are registered
0058      * with f/w for MPIPL.
0059      */
0060     addr = be64_to_cpu(addr);
0061     pr_debug("Kernel metadata addr: %llx\n", addr);
0062     opal_fdm_active = (void *)addr;
0063     if (be16_to_cpu(opal_fdm_active->registered_regions) == 0)
0064         return;
0065 
0066     ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_BOOT_MEM, &addr);
0067     if ((ret != OPAL_SUCCESS) || !addr) {
0068         pr_err("Failed to get boot memory tag (%lld)\n", ret);
0069         return;
0070     }
0071 
0072     /*
0073      * Memory below this address can be used for booting a
0074      * capture kernel or petitboot kernel. Preserve everything
0075      * above this address for processing crashdump.
0076      */
0077     fadump_conf->boot_mem_top = be64_to_cpu(addr);
0078     pr_debug("Preserve everything above %llx\n", fadump_conf->boot_mem_top);
0079 
0080     pr_info("Firmware-assisted dump is active.\n");
0081     fadump_conf->dump_active = 1;
0082 }
0083 
0084 #else /* CONFIG_PRESERVE_FA_DUMP */
0085 static const struct opal_fadump_mem_struct *opal_fdm_active;
0086 static const struct opal_mpipl_fadump *opal_cpu_metadata;
0087 static struct opal_fadump_mem_struct *opal_fdm;
0088 
0089 #ifdef CONFIG_OPAL_CORE
0090 extern bool kernel_initiated;
0091 #endif
0092 
0093 static int opal_fadump_unregister(struct fw_dump *fadump_conf);
0094 
0095 static void opal_fadump_update_config(struct fw_dump *fadump_conf,
0096                       const struct opal_fadump_mem_struct *fdm)
0097 {
0098     pr_debug("Boot memory regions count: %d\n", be16_to_cpu(fdm->region_cnt));
0099 
0100     /*
0101      * The destination address of the first boot memory region is the
0102      * destination address of boot memory regions.
0103      */
0104     fadump_conf->boot_mem_dest_addr = be64_to_cpu(fdm->rgn[0].dest);
0105     pr_debug("Destination address of boot memory regions: %#016llx\n",
0106          fadump_conf->boot_mem_dest_addr);
0107 
0108     fadump_conf->fadumphdr_addr = be64_to_cpu(fdm->fadumphdr_addr);
0109 }
0110 
0111 /*
0112  * This function is called in the capture kernel to get configuration details
0113  * from metadata setup by the first kernel.
0114  */
0115 static void __init opal_fadump_get_config(struct fw_dump *fadump_conf,
0116                    const struct opal_fadump_mem_struct *fdm)
0117 {
0118     unsigned long base, size, last_end, hole_size;
0119     int i;
0120 
0121     if (!fadump_conf->dump_active)
0122         return;
0123 
0124     last_end = 0;
0125     hole_size = 0;
0126     fadump_conf->boot_memory_size = 0;
0127 
0128     pr_debug("Boot memory regions:\n");
0129     for (i = 0; i < be16_to_cpu(fdm->region_cnt); i++) {
0130         base = be64_to_cpu(fdm->rgn[i].src);
0131         size = be64_to_cpu(fdm->rgn[i].size);
0132         pr_debug("\t[%03d] base: 0x%lx, size: 0x%lx\n", i, base, size);
0133 
0134         fadump_conf->boot_mem_addr[i] = base;
0135         fadump_conf->boot_mem_sz[i] = size;
0136         fadump_conf->boot_memory_size += size;
0137         hole_size += (base - last_end);
0138 
0139         last_end = base + size;
0140     }
0141 
0142     /*
0143      * Start address of reserve dump area (permanent reservation) for
0144      * re-registering FADump after dump capture.
0145      */
0146     fadump_conf->reserve_dump_area_start = be64_to_cpu(fdm->rgn[0].dest);
0147 
0148     /*
0149      * Rarely, but it can so happen that system crashes before all
0150      * boot memory regions are registered for MPIPL. In such
0151      * cases, warn that the vmcore may not be accurate and proceed
0152      * anyway as that is the best bet considering free pages, cache
0153      * pages, user pages, etc are usually filtered out.
0154      *
0155      * Hope the memory that could not be preserved only has pages
0156      * that are usually filtered out while saving the vmcore.
0157      */
0158     if (be16_to_cpu(fdm->region_cnt) > be16_to_cpu(fdm->registered_regions)) {
0159         pr_warn("Not all memory regions were saved!!!\n");
0160         pr_warn("  Unsaved memory regions:\n");
0161         i = be16_to_cpu(fdm->registered_regions);
0162         while (i < be16_to_cpu(fdm->region_cnt)) {
0163             pr_warn("\t[%03d] base: 0x%llx, size: 0x%llx\n",
0164                 i, be64_to_cpu(fdm->rgn[i].src),
0165                 be64_to_cpu(fdm->rgn[i].size));
0166             i++;
0167         }
0168 
0169         pr_warn("If the unsaved regions only contain pages that are filtered out (eg. free/user pages), the vmcore should still be usable.\n");
0170         pr_warn("WARNING: If the unsaved regions contain kernel pages, the vmcore will be corrupted.\n");
0171     }
0172 
0173     fadump_conf->boot_mem_top = (fadump_conf->boot_memory_size + hole_size);
0174     fadump_conf->boot_mem_regs_cnt = be16_to_cpu(fdm->region_cnt);
0175     opal_fadump_update_config(fadump_conf, fdm);
0176 }
0177 
0178 /* Initialize kernel metadata */
0179 static void opal_fadump_init_metadata(struct opal_fadump_mem_struct *fdm)
0180 {
0181     fdm->version = OPAL_FADUMP_VERSION;
0182     fdm->region_cnt = cpu_to_be16(0);
0183     fdm->registered_regions = cpu_to_be16(0);
0184     fdm->fadumphdr_addr = cpu_to_be64(0);
0185 }
0186 
0187 static u64 opal_fadump_init_mem_struct(struct fw_dump *fadump_conf)
0188 {
0189     u64 addr = fadump_conf->reserve_dump_area_start;
0190     u16 reg_cnt;
0191     int i;
0192 
0193     opal_fdm = __va(fadump_conf->kernel_metadata);
0194     opal_fadump_init_metadata(opal_fdm);
0195 
0196     /* Boot memory regions */
0197     reg_cnt = be16_to_cpu(opal_fdm->region_cnt);
0198     for (i = 0; i < fadump_conf->boot_mem_regs_cnt; i++) {
0199         opal_fdm->rgn[i].src    = cpu_to_be64(fadump_conf->boot_mem_addr[i]);
0200         opal_fdm->rgn[i].dest   = cpu_to_be64(addr);
0201         opal_fdm->rgn[i].size   = cpu_to_be64(fadump_conf->boot_mem_sz[i]);
0202 
0203         reg_cnt++;
0204         addr += fadump_conf->boot_mem_sz[i];
0205     }
0206     opal_fdm->region_cnt = cpu_to_be16(reg_cnt);
0207 
0208     /*
0209      * Kernel metadata is passed to f/w and retrieved in capture kernel.
0210      * So, use it to save fadump header address instead of calculating it.
0211      */
0212     opal_fdm->fadumphdr_addr = cpu_to_be64(be64_to_cpu(opal_fdm->rgn[0].dest) +
0213                            fadump_conf->boot_memory_size);
0214 
0215     opal_fadump_update_config(fadump_conf, opal_fdm);
0216 
0217     return addr;
0218 }
0219 
0220 static u64 opal_fadump_get_metadata_size(void)
0221 {
0222     return PAGE_ALIGN(sizeof(struct opal_fadump_mem_struct));
0223 }
0224 
0225 static int opal_fadump_setup_metadata(struct fw_dump *fadump_conf)
0226 {
0227     int err = 0;
0228     s64 ret;
0229 
0230     /*
0231      * Use the last page(s) in FADump memory reservation for
0232      * kernel metadata.
0233      */
0234     fadump_conf->kernel_metadata = (fadump_conf->reserve_dump_area_start +
0235                     fadump_conf->reserve_dump_area_size -
0236                     opal_fadump_get_metadata_size());
0237     pr_info("Kernel metadata addr: %llx\n", fadump_conf->kernel_metadata);
0238 
0239     /* Initialize kernel metadata before registering the address with f/w */
0240     opal_fdm = __va(fadump_conf->kernel_metadata);
0241     opal_fadump_init_metadata(opal_fdm);
0242 
0243     /*
0244      * Register metadata address with f/w. Can be retrieved in
0245      * the capture kernel.
0246      */
0247     ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_KERNEL,
0248                       fadump_conf->kernel_metadata);
0249     if (ret != OPAL_SUCCESS) {
0250         pr_err("Failed to set kernel metadata tag!\n");
0251         err = -EPERM;
0252     }
0253 
0254     /*
0255      * Register boot memory top address with f/w. Should be retrieved
0256      * by a kernel that intends to preserve crash'ed kernel's memory.
0257      */
0258     ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_BOOT_MEM,
0259                       fadump_conf->boot_mem_top);
0260     if (ret != OPAL_SUCCESS) {
0261         pr_err("Failed to set boot memory tag!\n");
0262         err = -EPERM;
0263     }
0264 
0265     return err;
0266 }
0267 
0268 static u64 opal_fadump_get_bootmem_min(void)
0269 {
0270     return OPAL_FADUMP_MIN_BOOT_MEM;
0271 }
0272 
0273 static int opal_fadump_register(struct fw_dump *fadump_conf)
0274 {
0275     s64 rc = OPAL_PARAMETER;
0276     u16 registered_regs;
0277     int i, err = -EIO;
0278 
0279     registered_regs = be16_to_cpu(opal_fdm->registered_regions);
0280     for (i = 0; i < be16_to_cpu(opal_fdm->region_cnt); i++) {
0281         rc = opal_mpipl_update(OPAL_MPIPL_ADD_RANGE,
0282                        be64_to_cpu(opal_fdm->rgn[i].src),
0283                        be64_to_cpu(opal_fdm->rgn[i].dest),
0284                        be64_to_cpu(opal_fdm->rgn[i].size));
0285         if (rc != OPAL_SUCCESS)
0286             break;
0287 
0288         registered_regs++;
0289     }
0290     opal_fdm->registered_regions = cpu_to_be16(registered_regs);
0291 
0292     switch (rc) {
0293     case OPAL_SUCCESS:
0294         pr_info("Registration is successful!\n");
0295         fadump_conf->dump_registered = 1;
0296         err = 0;
0297         break;
0298     case OPAL_RESOURCE:
0299         /* If MAX regions limit in f/w is hit, warn and proceed. */
0300         pr_warn("%d regions could not be registered for MPIPL as MAX limit is reached!\n",
0301             (be16_to_cpu(opal_fdm->region_cnt) -
0302              be16_to_cpu(opal_fdm->registered_regions)));
0303         fadump_conf->dump_registered = 1;
0304         err = 0;
0305         break;
0306     case OPAL_PARAMETER:
0307         pr_err("Failed to register. Parameter Error(%lld).\n", rc);
0308         break;
0309     case OPAL_HARDWARE:
0310         pr_err("Support not available.\n");
0311         fadump_conf->fadump_supported = 0;
0312         fadump_conf->fadump_enabled = 0;
0313         break;
0314     default:
0315         pr_err("Failed to register. Unknown Error(%lld).\n", rc);
0316         break;
0317     }
0318 
0319     /*
0320      * If some regions were registered before OPAL_MPIPL_ADD_RANGE
0321      * OPAL call failed, unregister all regions.
0322      */
0323     if ((err < 0) && (be16_to_cpu(opal_fdm->registered_regions) > 0))
0324         opal_fadump_unregister(fadump_conf);
0325 
0326     return err;
0327 }
0328 
0329 static int opal_fadump_unregister(struct fw_dump *fadump_conf)
0330 {
0331     s64 rc;
0332 
0333     rc = opal_mpipl_update(OPAL_MPIPL_REMOVE_ALL, 0, 0, 0);
0334     if (rc) {
0335         pr_err("Failed to un-register - unexpected Error(%lld).\n", rc);
0336         return -EIO;
0337     }
0338 
0339     opal_fdm->registered_regions = cpu_to_be16(0);
0340     fadump_conf->dump_registered = 0;
0341     return 0;
0342 }
0343 
0344 static int opal_fadump_invalidate(struct fw_dump *fadump_conf)
0345 {
0346     s64 rc;
0347 
0348     rc = opal_mpipl_update(OPAL_MPIPL_FREE_PRESERVED_MEMORY, 0, 0, 0);
0349     if (rc) {
0350         pr_err("Failed to invalidate - unexpected Error(%lld).\n", rc);
0351         return -EIO;
0352     }
0353 
0354     fadump_conf->dump_active = 0;
0355     opal_fdm_active = NULL;
0356     return 0;
0357 }
0358 
0359 static void opal_fadump_cleanup(struct fw_dump *fadump_conf)
0360 {
0361     s64 ret;
0362 
0363     ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_KERNEL, 0);
0364     if (ret != OPAL_SUCCESS)
0365         pr_warn("Could not reset (%llu) kernel metadata tag!\n", ret);
0366 }
0367 
0368 /*
0369  * Verify if CPU state data is available. If available, do a bit of sanity
0370  * checking before processing this data.
0371  */
0372 static bool __init is_opal_fadump_cpu_data_valid(struct fw_dump *fadump_conf)
0373 {
0374     if (!opal_cpu_metadata)
0375         return false;
0376 
0377     fadump_conf->cpu_state_data_version =
0378         be32_to_cpu(opal_cpu_metadata->cpu_data_version);
0379     fadump_conf->cpu_state_entry_size =
0380         be32_to_cpu(opal_cpu_metadata->cpu_data_size);
0381     fadump_conf->cpu_state_dest_vaddr =
0382         (u64)__va(be64_to_cpu(opal_cpu_metadata->region[0].dest));
0383     fadump_conf->cpu_state_data_size =
0384         be64_to_cpu(opal_cpu_metadata->region[0].size);
0385 
0386     if (fadump_conf->cpu_state_data_version != HDAT_FADUMP_CPU_DATA_VER) {
0387         pr_warn("Supported CPU state data version: %u, found: %d!\n",
0388             HDAT_FADUMP_CPU_DATA_VER,
0389             fadump_conf->cpu_state_data_version);
0390         pr_warn("WARNING: F/W using newer CPU state data format!!\n");
0391     }
0392 
0393     if ((fadump_conf->cpu_state_dest_vaddr == 0) ||
0394         (fadump_conf->cpu_state_entry_size == 0) ||
0395         (fadump_conf->cpu_state_entry_size >
0396          fadump_conf->cpu_state_data_size)) {
0397         pr_err("CPU state data is invalid. Ignoring!\n");
0398         return false;
0399     }
0400 
0401     return true;
0402 }
0403 
0404 /*
0405  * Convert CPU state data saved at the time of crash into ELF notes.
0406  *
0407  * While the crashing CPU's register data is saved by the kernel, CPU state
0408  * data for all CPUs is saved by f/w. In CPU state data provided by f/w,
0409  * each register entry is of 16 bytes, a numerical identifier along with
0410  * a GPR/SPR flag in the first 8 bytes and the register value in the next
0411  * 8 bytes. For more details refer to F/W documentation. If this data is
0412  * missing or in unsupported format, append crashing CPU's register data
0413  * saved by the kernel in the PT_NOTE, to have something to work with in
0414  * the vmcore file.
0415  */
0416 static int __init
0417 opal_fadump_build_cpu_notes(struct fw_dump *fadump_conf,
0418                 struct fadump_crash_info_header *fdh)
0419 {
0420     u32 thread_pir, size_per_thread, regs_offset, regs_cnt, reg_esize;
0421     struct hdat_fadump_thread_hdr *thdr;
0422     bool is_cpu_data_valid = false;
0423     u32 num_cpus = 1, *note_buf;
0424     struct pt_regs regs;
0425     char *bufp;
0426     int rc, i;
0427 
0428     if (is_opal_fadump_cpu_data_valid(fadump_conf)) {
0429         size_per_thread = fadump_conf->cpu_state_entry_size;
0430         num_cpus = (fadump_conf->cpu_state_data_size / size_per_thread);
0431         bufp = __va(fadump_conf->cpu_state_dest_vaddr);
0432         is_cpu_data_valid = true;
0433     }
0434 
0435     rc = fadump_setup_cpu_notes_buf(num_cpus);
0436     if (rc != 0)
0437         return rc;
0438 
0439     note_buf = (u32 *)fadump_conf->cpu_notes_buf_vaddr;
0440     if (!is_cpu_data_valid)
0441         goto out;
0442 
0443     /*
0444      * Offset for register entries, entry size and registers count is
0445      * duplicated in every thread header in keeping with HDAT format.
0446      * Use these values from the first thread header.
0447      */
0448     thdr = (struct hdat_fadump_thread_hdr *)bufp;
0449     regs_offset = (offsetof(struct hdat_fadump_thread_hdr, offset) +
0450                be32_to_cpu(thdr->offset));
0451     reg_esize = be32_to_cpu(thdr->esize);
0452     regs_cnt  = be32_to_cpu(thdr->ecnt);
0453 
0454     pr_debug("--------CPU State Data------------\n");
0455     pr_debug("NumCpus     : %u\n", num_cpus);
0456     pr_debug("\tOffset: %u, Entry size: %u, Cnt: %u\n",
0457          regs_offset, reg_esize, regs_cnt);
0458 
0459     for (i = 0; i < num_cpus; i++, bufp += size_per_thread) {
0460         thdr = (struct hdat_fadump_thread_hdr *)bufp;
0461 
0462         thread_pir = be32_to_cpu(thdr->pir);
0463         pr_debug("[%04d] PIR: 0x%x, core state: 0x%02x\n",
0464              i, thread_pir, thdr->core_state);
0465 
0466         /*
0467          * If this is kernel initiated crash, crashing_cpu would be set
0468          * appropriately and register data of the crashing CPU saved by
0469          * crashing kernel. Add this saved register data of crashing CPU
0470          * to elf notes and populate the pt_regs for the remaining CPUs
0471          * from register state data provided by firmware.
0472          */
0473         if (fdh->crashing_cpu == thread_pir) {
0474             note_buf = fadump_regs_to_elf_notes(note_buf,
0475                                 &fdh->regs);
0476             pr_debug("Crashing CPU PIR: 0x%x - R1 : 0x%lx, NIP : 0x%lx\n",
0477                  fdh->crashing_cpu, fdh->regs.gpr[1],
0478                  fdh->regs.nip);
0479             continue;
0480         }
0481 
0482         /*
0483          * Register state data of MAX cores is provided by firmware,
0484          * but some of this cores may not be active. So, while
0485          * processing register state data, check core state and
0486          * skip threads that belong to inactive cores.
0487          */
0488         if (thdr->core_state == HDAT_FADUMP_CORE_INACTIVE)
0489             continue;
0490 
0491         opal_fadump_read_regs((bufp + regs_offset), regs_cnt,
0492                       reg_esize, true, &regs);
0493         note_buf = fadump_regs_to_elf_notes(note_buf, &regs);
0494         pr_debug("CPU PIR: 0x%x - R1 : 0x%lx, NIP : 0x%lx\n",
0495              thread_pir, regs.gpr[1], regs.nip);
0496     }
0497 
0498 out:
0499     /*
0500      * CPU state data is invalid/unsupported. Try appending crashing CPU's
0501      * register data, if it is saved by the kernel.
0502      */
0503     if (fadump_conf->cpu_notes_buf_vaddr == (u64)note_buf) {
0504         if (fdh->crashing_cpu == FADUMP_CPU_UNKNOWN) {
0505             fadump_free_cpu_notes_buf();
0506             return -ENODEV;
0507         }
0508 
0509         pr_warn("WARNING: appending only crashing CPU's register data\n");
0510         note_buf = fadump_regs_to_elf_notes(note_buf, &(fdh->regs));
0511     }
0512 
0513     final_note(note_buf);
0514 
0515     pr_debug("Updating elfcore header (%llx) with cpu notes\n",
0516          fdh->elfcorehdr_addr);
0517     fadump_update_elfcore_header(__va(fdh->elfcorehdr_addr));
0518     return 0;
0519 }
0520 
0521 static int __init opal_fadump_process(struct fw_dump *fadump_conf)
0522 {
0523     struct fadump_crash_info_header *fdh;
0524     int rc = -EINVAL;
0525 
0526     if (!opal_fdm_active || !fadump_conf->fadumphdr_addr)
0527         return rc;
0528 
0529     /* Validate the fadump crash info header */
0530     fdh = __va(fadump_conf->fadumphdr_addr);
0531     if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) {
0532         pr_err("Crash info header is not valid.\n");
0533         return rc;
0534     }
0535 
0536 #ifdef CONFIG_OPAL_CORE
0537     /*
0538      * If this is a kernel initiated crash, crashing_cpu would be set
0539      * appropriately and register data of the crashing CPU saved by
0540      * crashing kernel. Add this saved register data of crashing CPU
0541      * to elf notes and populate the pt_regs for the remaining CPUs
0542      * from register state data provided by firmware.
0543      */
0544     if (fdh->crashing_cpu != FADUMP_CPU_UNKNOWN)
0545         kernel_initiated = true;
0546 #endif
0547 
0548     rc = opal_fadump_build_cpu_notes(fadump_conf, fdh);
0549     if (rc)
0550         return rc;
0551 
0552     /*
0553      * We are done validating dump info and elfcore header is now ready
0554      * to be exported. set elfcorehdr_addr so that vmcore module will
0555      * export the elfcore header through '/proc/vmcore'.
0556      */
0557     elfcorehdr_addr = fdh->elfcorehdr_addr;
0558 
0559     return rc;
0560 }
0561 
0562 static void opal_fadump_region_show(struct fw_dump *fadump_conf,
0563                     struct seq_file *m)
0564 {
0565     const struct opal_fadump_mem_struct *fdm_ptr;
0566     u64 dumped_bytes = 0;
0567     int i;
0568 
0569     if (fadump_conf->dump_active)
0570         fdm_ptr = opal_fdm_active;
0571     else
0572         fdm_ptr = opal_fdm;
0573 
0574     for (i = 0; i < be16_to_cpu(fdm_ptr->region_cnt); i++) {
0575         /*
0576          * Only regions that are registered for MPIPL
0577          * would have dump data.
0578          */
0579         if ((fadump_conf->dump_active) &&
0580             (i < be16_to_cpu(fdm_ptr->registered_regions)))
0581             dumped_bytes = be64_to_cpu(fdm_ptr->rgn[i].size);
0582 
0583         seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ",
0584                be64_to_cpu(fdm_ptr->rgn[i].src),
0585                be64_to_cpu(fdm_ptr->rgn[i].dest));
0586         seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n",
0587                be64_to_cpu(fdm_ptr->rgn[i].size), dumped_bytes);
0588     }
0589 
0590     /* Dump is active. Show preserved area start address. */
0591     if (fadump_conf->dump_active) {
0592         seq_printf(m, "\nMemory above %#016llx is reserved for saving crash dump\n",
0593                fadump_conf->boot_mem_top);
0594     }
0595 }
0596 
0597 static void opal_fadump_trigger(struct fadump_crash_info_header *fdh,
0598                 const char *msg)
0599 {
0600     int rc;
0601 
0602     /*
0603      * Unlike on pSeries platform, logical CPU number is not provided
0604      * with architected register state data. So, store the crashing
0605      * CPU's PIR instead to plug the appropriate register data for
0606      * crashing CPU in the vmcore file.
0607      */
0608     fdh->crashing_cpu = (u32)mfspr(SPRN_PIR);
0609 
0610     rc = opal_cec_reboot2(OPAL_REBOOT_MPIPL, msg);
0611     if (rc == OPAL_UNSUPPORTED) {
0612         pr_emerg("Reboot type %d not supported.\n",
0613              OPAL_REBOOT_MPIPL);
0614     } else if (rc == OPAL_HARDWARE)
0615         pr_emerg("No backend support for MPIPL!\n");
0616 }
0617 
0618 static struct fadump_ops opal_fadump_ops = {
0619     .fadump_init_mem_struct     = opal_fadump_init_mem_struct,
0620     .fadump_get_metadata_size   = opal_fadump_get_metadata_size,
0621     .fadump_setup_metadata      = opal_fadump_setup_metadata,
0622     .fadump_get_bootmem_min     = opal_fadump_get_bootmem_min,
0623     .fadump_register        = opal_fadump_register,
0624     .fadump_unregister      = opal_fadump_unregister,
0625     .fadump_invalidate      = opal_fadump_invalidate,
0626     .fadump_cleanup         = opal_fadump_cleanup,
0627     .fadump_process         = opal_fadump_process,
0628     .fadump_region_show     = opal_fadump_region_show,
0629     .fadump_trigger         = opal_fadump_trigger,
0630 };
0631 
0632 void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node)
0633 {
0634     const __be32 *prop;
0635     unsigned long dn;
0636     __be64 be_addr;
0637     u64 addr = 0;
0638     int i, len;
0639     s64 ret;
0640 
0641     /*
0642      * Check if Firmware-Assisted Dump is supported. if yes, check
0643      * if dump has been initiated on last reboot.
0644      */
0645     dn = of_get_flat_dt_subnode_by_name(node, "dump");
0646     if (dn == -FDT_ERR_NOTFOUND) {
0647         pr_debug("FADump support is missing!\n");
0648         return;
0649     }
0650 
0651     if (!of_flat_dt_is_compatible(dn, "ibm,opal-dump")) {
0652         pr_err("Support missing for this f/w version!\n");
0653         return;
0654     }
0655 
0656     prop = of_get_flat_dt_prop(dn, "fw-load-area", &len);
0657     if (prop) {
0658         /*
0659          * Each f/w load area is an (address,size) pair,
0660          * 2 cells each, totalling 4 cells per range.
0661          */
0662         for (i = 0; i < len / (sizeof(*prop) * 4); i++) {
0663             u64 base, end;
0664 
0665             base = of_read_number(prop + (i * 4) + 0, 2);
0666             end = base;
0667             end += of_read_number(prop + (i * 4) + 2, 2);
0668             if (end > OPAL_FADUMP_MIN_BOOT_MEM) {
0669                 pr_err("F/W load area: 0x%llx-0x%llx\n",
0670                        base, end);
0671                 pr_err("F/W version not supported!\n");
0672                 return;
0673             }
0674         }
0675     }
0676 
0677     fadump_conf->ops        = &opal_fadump_ops;
0678     fadump_conf->fadump_supported   = 1;
0679 
0680     /*
0681      * Firmware supports 32-bit field for size. Align it to PAGE_SIZE
0682      * and request firmware to copy multiple kernel boot memory regions.
0683      */
0684     fadump_conf->max_copy_size = ALIGN_DOWN(U32_MAX, PAGE_SIZE);
0685 
0686     /*
0687      * Check if dump has been initiated on last reboot.
0688      */
0689     prop = of_get_flat_dt_prop(dn, "mpipl-boot", NULL);
0690     if (!prop)
0691         return;
0692 
0693     ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &be_addr);
0694     if ((ret != OPAL_SUCCESS) || !be_addr) {
0695         pr_err("Failed to get Kernel metadata (%lld)\n", ret);
0696         return;
0697     }
0698 
0699     addr = be64_to_cpu(be_addr);
0700     pr_debug("Kernel metadata addr: %llx\n", addr);
0701 
0702     opal_fdm_active = __va(addr);
0703     if (opal_fdm_active->version != OPAL_FADUMP_VERSION) {
0704         pr_warn("Supported kernel metadata version: %u, found: %d!\n",
0705             OPAL_FADUMP_VERSION, opal_fdm_active->version);
0706         pr_warn("WARNING: Kernel metadata format mismatch identified! Core file maybe corrupted..\n");
0707     }
0708 
0709     /* Kernel regions not registered with f/w for MPIPL */
0710     if (be16_to_cpu(opal_fdm_active->registered_regions) == 0) {
0711         opal_fdm_active = NULL;
0712         return;
0713     }
0714 
0715     ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_CPU, &be_addr);
0716     if (be_addr) {
0717         addr = be64_to_cpu(be_addr);
0718         pr_debug("CPU metadata addr: %llx\n", addr);
0719         opal_cpu_metadata = __va(addr);
0720     }
0721 
0722     pr_info("Firmware-assisted dump is active.\n");
0723     fadump_conf->dump_active = 1;
0724     opal_fadump_get_config(fadump_conf, opal_fdm_active);
0725 }
0726 #endif /* !CONFIG_PRESERVE_FA_DUMP */