141df5928SHari Bathini // SPDX-License-Identifier: GPL-2.0-or-later 241df5928SHari Bathini /* 341df5928SHari Bathini * Firmware-Assisted Dump support on POWER platform (OPAL). 441df5928SHari Bathini * 541df5928SHari Bathini * Copyright 2019, Hari Bathini, IBM Corporation. 641df5928SHari Bathini */ 741df5928SHari Bathini 841df5928SHari Bathini #define pr_fmt(fmt) "opal fadump: " fmt 941df5928SHari Bathini 1041df5928SHari Bathini #include <linux/string.h> 1141df5928SHari Bathini #include <linux/seq_file.h> 1241df5928SHari Bathini #include <linux/of_fdt.h> 1341df5928SHari Bathini #include <linux/libfdt.h> 14742a265aSHari Bathini #include <linux/mm.h> 152a1b06ddSHari Bathini #include <linux/crash_dump.h> 1641df5928SHari Bathini 17742a265aSHari Bathini #include <asm/page.h> 1841df5928SHari Bathini #include <asm/opal.h> 1941df5928SHari Bathini #include <asm/fadump-internal.h> 2041df5928SHari Bathini 21742a265aSHari Bathini #include "opal-fadump.h" 22742a265aSHari Bathini 232a1b06ddSHari Bathini static const struct opal_fadump_mem_struct *opal_fdm_active; 24742a265aSHari Bathini static struct opal_fadump_mem_struct *opal_fdm; 25742a265aSHari Bathini 26a20a8fa4SHari Bathini static int opal_fadump_unregister(struct fw_dump *fadump_conf); 27a20a8fa4SHari Bathini 28a20a8fa4SHari Bathini static void opal_fadump_update_config(struct fw_dump *fadump_conf, 29a20a8fa4SHari Bathini const struct opal_fadump_mem_struct *fdm) 30a20a8fa4SHari Bathini { 3151bba8edSHari Bathini pr_debug("Boot memory regions count: %d\n", fdm->region_cnt); 3251bba8edSHari Bathini 33a20a8fa4SHari Bathini /* 34a20a8fa4SHari Bathini * The destination address of the first boot memory region is the 35a20a8fa4SHari Bathini * destination address of boot memory regions. 36a20a8fa4SHari Bathini */ 37a20a8fa4SHari Bathini fadump_conf->boot_mem_dest_addr = fdm->rgn[0].dest; 38a20a8fa4SHari Bathini pr_debug("Destination address of boot memory regions: %#016llx\n", 39a20a8fa4SHari Bathini fadump_conf->boot_mem_dest_addr); 40a20a8fa4SHari Bathini 41a20a8fa4SHari Bathini fadump_conf->fadumphdr_addr = fdm->fadumphdr_addr; 42a20a8fa4SHari Bathini } 43a20a8fa4SHari Bathini 442a1b06ddSHari Bathini /* 452a1b06ddSHari Bathini * This function is called in the capture kernel to get configuration details 462a1b06ddSHari Bathini * from metadata setup by the first kernel. 472a1b06ddSHari Bathini */ 482a1b06ddSHari Bathini static void opal_fadump_get_config(struct fw_dump *fadump_conf, 492a1b06ddSHari Bathini const struct opal_fadump_mem_struct *fdm) 502a1b06ddSHari Bathini { 512a1b06ddSHari Bathini int i; 522a1b06ddSHari Bathini 532a1b06ddSHari Bathini if (!fadump_conf->dump_active) 542a1b06ddSHari Bathini return; 552a1b06ddSHari Bathini 562a1b06ddSHari Bathini fadump_conf->boot_memory_size = 0; 572a1b06ddSHari Bathini 582a1b06ddSHari Bathini pr_debug("Boot memory regions:\n"); 592a1b06ddSHari Bathini for (i = 0; i < fdm->region_cnt; i++) { 602a1b06ddSHari Bathini pr_debug("\t%d. base: 0x%llx, size: 0x%llx\n", 612a1b06ddSHari Bathini (i + 1), fdm->rgn[i].src, fdm->rgn[i].size); 622a1b06ddSHari Bathini 632a1b06ddSHari Bathini fadump_conf->boot_memory_size += fdm->rgn[i].size; 642a1b06ddSHari Bathini } 652a1b06ddSHari Bathini 662a1b06ddSHari Bathini /* 672a1b06ddSHari Bathini * Start address of reserve dump area (permanent reservation) for 682a1b06ddSHari Bathini * re-registering FADump after dump capture. 692a1b06ddSHari Bathini */ 702a1b06ddSHari Bathini fadump_conf->reserve_dump_area_start = fdm->rgn[0].dest; 712a1b06ddSHari Bathini 722a1b06ddSHari Bathini opal_fadump_update_config(fadump_conf, fdm); 732a1b06ddSHari Bathini } 742a1b06ddSHari Bathini 75742a265aSHari Bathini /* Initialize kernel metadata */ 76742a265aSHari Bathini static void opal_fadump_init_metadata(struct opal_fadump_mem_struct *fdm) 77742a265aSHari Bathini { 78742a265aSHari Bathini fdm->version = OPAL_FADUMP_VERSION; 79742a265aSHari Bathini fdm->region_cnt = 0; 80742a265aSHari Bathini fdm->registered_regions = 0; 81742a265aSHari Bathini fdm->fadumphdr_addr = 0; 82742a265aSHari Bathini } 83742a265aSHari Bathini 8441df5928SHari Bathini static u64 opal_fadump_init_mem_struct(struct fw_dump *fadump_conf) 8541df5928SHari Bathini { 8651bba8edSHari Bathini int max_copy_size, cur_size, size; 8751bba8edSHari Bathini u64 src_addr, dest_addr; 88742a265aSHari Bathini 89742a265aSHari Bathini opal_fdm = __va(fadump_conf->kernel_metadata); 90742a265aSHari Bathini opal_fadump_init_metadata(opal_fdm); 91742a265aSHari Bathini 9251bba8edSHari Bathini /* 9351bba8edSHari Bathini * Firmware supports 32-bit field for size. Align it to PAGE_SIZE 9451bba8edSHari Bathini * and request firmware to copy multiple kernel boot memory regions. 9551bba8edSHari Bathini */ 9651bba8edSHari Bathini max_copy_size = _ALIGN_DOWN(U32_MAX, PAGE_SIZE); 9751bba8edSHari Bathini 9851bba8edSHari Bathini /* Boot memory regions */ 9951bba8edSHari Bathini src_addr = 0; 10051bba8edSHari Bathini dest_addr = fadump_conf->reserve_dump_area_start; 10151bba8edSHari Bathini size = fadump_conf->boot_memory_size; 10251bba8edSHari Bathini while (size) { 10351bba8edSHari Bathini cur_size = size > max_copy_size ? max_copy_size : size; 10451bba8edSHari Bathini 10551bba8edSHari Bathini opal_fdm->rgn[opal_fdm->region_cnt].src = src_addr; 10651bba8edSHari Bathini opal_fdm->rgn[opal_fdm->region_cnt].dest = dest_addr; 10751bba8edSHari Bathini opal_fdm->rgn[opal_fdm->region_cnt].size = cur_size; 10851bba8edSHari Bathini 10951bba8edSHari Bathini opal_fdm->region_cnt++; 11051bba8edSHari Bathini dest_addr += cur_size; 11151bba8edSHari Bathini src_addr += cur_size; 11251bba8edSHari Bathini size -= cur_size; 11351bba8edSHari Bathini } 114742a265aSHari Bathini 115742a265aSHari Bathini /* 116742a265aSHari Bathini * Kernel metadata is passed to f/w and retrieved in capture kerenl. 117742a265aSHari Bathini * So, use it to save fadump header address instead of calculating it. 118742a265aSHari Bathini */ 119742a265aSHari Bathini opal_fdm->fadumphdr_addr = (opal_fdm->rgn[0].dest + 120742a265aSHari Bathini fadump_conf->boot_memory_size); 121742a265aSHari Bathini 122a20a8fa4SHari Bathini opal_fadump_update_config(fadump_conf, opal_fdm); 123a20a8fa4SHari Bathini 12451bba8edSHari Bathini return dest_addr; 125742a265aSHari Bathini } 126742a265aSHari Bathini 127742a265aSHari Bathini static u64 opal_fadump_get_metadata_size(void) 128742a265aSHari Bathini { 129742a265aSHari Bathini return PAGE_ALIGN(sizeof(struct opal_fadump_mem_struct)); 130742a265aSHari Bathini } 131742a265aSHari Bathini 132742a265aSHari Bathini static int opal_fadump_setup_metadata(struct fw_dump *fadump_conf) 133742a265aSHari Bathini { 134742a265aSHari Bathini int err = 0; 135742a265aSHari Bathini s64 ret; 136742a265aSHari Bathini 137742a265aSHari Bathini /* 138742a265aSHari Bathini * Use the last page(s) in FADump memory reservation for 139742a265aSHari Bathini * kernel metadata. 140742a265aSHari Bathini */ 141742a265aSHari Bathini fadump_conf->kernel_metadata = (fadump_conf->reserve_dump_area_start + 142742a265aSHari Bathini fadump_conf->reserve_dump_area_size - 143742a265aSHari Bathini opal_fadump_get_metadata_size()); 144742a265aSHari Bathini pr_info("Kernel metadata addr: %llx\n", fadump_conf->kernel_metadata); 145742a265aSHari Bathini 146742a265aSHari Bathini /* Initialize kernel metadata before registering the address with f/w */ 147742a265aSHari Bathini opal_fdm = __va(fadump_conf->kernel_metadata); 148742a265aSHari Bathini opal_fadump_init_metadata(opal_fdm); 149742a265aSHari Bathini 150742a265aSHari Bathini /* 151742a265aSHari Bathini * Register metadata address with f/w. Can be retrieved in 152742a265aSHari Bathini * the capture kernel. 153742a265aSHari Bathini */ 154742a265aSHari Bathini ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_KERNEL, 155742a265aSHari Bathini fadump_conf->kernel_metadata); 156742a265aSHari Bathini if (ret != OPAL_SUCCESS) { 157742a265aSHari Bathini pr_err("Failed to set kernel metadata tag!\n"); 158742a265aSHari Bathini err = -EPERM; 159742a265aSHari Bathini } 160742a265aSHari Bathini 161742a265aSHari Bathini return err; 16241df5928SHari Bathini } 16341df5928SHari Bathini 16441df5928SHari Bathini static int opal_fadump_register(struct fw_dump *fadump_conf) 16541df5928SHari Bathini { 166a20a8fa4SHari Bathini s64 rc = OPAL_PARAMETER; 167a20a8fa4SHari Bathini int i, err = -EIO; 168a20a8fa4SHari Bathini 169a20a8fa4SHari Bathini for (i = 0; i < opal_fdm->region_cnt; i++) { 170a20a8fa4SHari Bathini rc = opal_mpipl_update(OPAL_MPIPL_ADD_RANGE, 171a20a8fa4SHari Bathini opal_fdm->rgn[i].src, 172a20a8fa4SHari Bathini opal_fdm->rgn[i].dest, 173a20a8fa4SHari Bathini opal_fdm->rgn[i].size); 174a20a8fa4SHari Bathini if (rc != OPAL_SUCCESS) 175a20a8fa4SHari Bathini break; 176a20a8fa4SHari Bathini 177a20a8fa4SHari Bathini opal_fdm->registered_regions++; 178a20a8fa4SHari Bathini } 179a20a8fa4SHari Bathini 180a20a8fa4SHari Bathini switch (rc) { 181a20a8fa4SHari Bathini case OPAL_SUCCESS: 182a20a8fa4SHari Bathini pr_info("Registration is successful!\n"); 183a20a8fa4SHari Bathini fadump_conf->dump_registered = 1; 184a20a8fa4SHari Bathini err = 0; 185a20a8fa4SHari Bathini break; 186a20a8fa4SHari Bathini case OPAL_RESOURCE: 187a20a8fa4SHari Bathini /* If MAX regions limit in f/w is hit, warn and proceed. */ 188a20a8fa4SHari Bathini pr_warn("%d regions could not be registered for MPIPL as MAX limit is reached!\n", 189a20a8fa4SHari Bathini (opal_fdm->region_cnt - opal_fdm->registered_regions)); 190a20a8fa4SHari Bathini fadump_conf->dump_registered = 1; 191a20a8fa4SHari Bathini err = 0; 192a20a8fa4SHari Bathini break; 193a20a8fa4SHari Bathini case OPAL_PARAMETER: 194a20a8fa4SHari Bathini pr_err("Failed to register. Parameter Error(%lld).\n", rc); 195a20a8fa4SHari Bathini break; 196a20a8fa4SHari Bathini case OPAL_HARDWARE: 197a20a8fa4SHari Bathini pr_err("Support not available.\n"); 198a20a8fa4SHari Bathini fadump_conf->fadump_supported = 0; 199a20a8fa4SHari Bathini fadump_conf->fadump_enabled = 0; 200a20a8fa4SHari Bathini break; 201a20a8fa4SHari Bathini default: 202a20a8fa4SHari Bathini pr_err("Failed to register. Unknown Error(%lld).\n", rc); 203a20a8fa4SHari Bathini break; 204a20a8fa4SHari Bathini } 205a20a8fa4SHari Bathini 206a20a8fa4SHari Bathini /* 207a20a8fa4SHari Bathini * If some regions were registered before OPAL_MPIPL_ADD_RANGE 208a20a8fa4SHari Bathini * OPAL call failed, unregister all regions. 209a20a8fa4SHari Bathini */ 210a20a8fa4SHari Bathini if ((err < 0) && (opal_fdm->registered_regions > 0)) 211a20a8fa4SHari Bathini opal_fadump_unregister(fadump_conf); 212a20a8fa4SHari Bathini 213a20a8fa4SHari Bathini return err; 21441df5928SHari Bathini } 21541df5928SHari Bathini 21641df5928SHari Bathini static int opal_fadump_unregister(struct fw_dump *fadump_conf) 21741df5928SHari Bathini { 218a20a8fa4SHari Bathini s64 rc; 219a20a8fa4SHari Bathini 220a20a8fa4SHari Bathini rc = opal_mpipl_update(OPAL_MPIPL_REMOVE_ALL, 0, 0, 0); 221a20a8fa4SHari Bathini if (rc) { 222a20a8fa4SHari Bathini pr_err("Failed to un-register - unexpected Error(%lld).\n", rc); 22341df5928SHari Bathini return -EIO; 22441df5928SHari Bathini } 22541df5928SHari Bathini 226a20a8fa4SHari Bathini opal_fdm->registered_regions = 0; 227a20a8fa4SHari Bathini fadump_conf->dump_registered = 0; 228a20a8fa4SHari Bathini return 0; 229a20a8fa4SHari Bathini } 230a20a8fa4SHari Bathini 23141df5928SHari Bathini static int opal_fadump_invalidate(struct fw_dump *fadump_conf) 23241df5928SHari Bathini { 23341df5928SHari Bathini return -EIO; 23441df5928SHari Bathini } 23541df5928SHari Bathini 2362790d01dSHari Bathini static void opal_fadump_cleanup(struct fw_dump *fadump_conf) 2372790d01dSHari Bathini { 2382790d01dSHari Bathini s64 ret; 2392790d01dSHari Bathini 2402790d01dSHari Bathini ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_KERNEL, 0); 2412790d01dSHari Bathini if (ret != OPAL_SUCCESS) 2422790d01dSHari Bathini pr_warn("Could not reset (%llu) kernel metadata tag!\n", ret); 2432790d01dSHari Bathini } 2442790d01dSHari Bathini 2452a1b06ddSHari Bathini /* 2462a1b06ddSHari Bathini * Convert CPU state data saved at the time of crash into ELF notes. 2472a1b06ddSHari Bathini * 2482a1b06ddSHari Bathini * Append crashing CPU's register data saved by the kernel in the PT_NOTE. 2492a1b06ddSHari Bathini */ 2502a1b06ddSHari Bathini static int __init 2512a1b06ddSHari Bathini opal_fadump_build_cpu_notes(struct fw_dump *fadump_conf, 2522a1b06ddSHari Bathini struct fadump_crash_info_header *fdh) 2532a1b06ddSHari Bathini { 2542a1b06ddSHari Bathini u32 num_cpus = 1, *note_buf; 2552a1b06ddSHari Bathini int rc; 2562a1b06ddSHari Bathini 2572a1b06ddSHari Bathini if (fdh->crashing_cpu == FADUMP_CPU_UNKNOWN) 2582a1b06ddSHari Bathini return -ENODEV; 2592a1b06ddSHari Bathini 2602a1b06ddSHari Bathini /* Allocate CPU notes buffer to hold crashing cpu notes. */ 2612a1b06ddSHari Bathini rc = fadump_setup_cpu_notes_buf(num_cpus); 2622a1b06ddSHari Bathini if (rc != 0) 2632a1b06ddSHari Bathini return rc; 2642a1b06ddSHari Bathini 2652a1b06ddSHari Bathini note_buf = (u32 *)fadump_conf->cpu_notes_buf_vaddr; 2662a1b06ddSHari Bathini note_buf = fadump_regs_to_elf_notes(note_buf, &(fdh->regs)); 2672a1b06ddSHari Bathini final_note(note_buf); 2682a1b06ddSHari Bathini 2692a1b06ddSHari Bathini pr_debug("Updating elfcore header (%llx) with cpu notes\n", 2702a1b06ddSHari Bathini fdh->elfcorehdr_addr); 2712a1b06ddSHari Bathini fadump_update_elfcore_header(__va(fdh->elfcorehdr_addr)); 2722a1b06ddSHari Bathini return 0; 2732a1b06ddSHari Bathini } 2742a1b06ddSHari Bathini 27541df5928SHari Bathini static int __init opal_fadump_process(struct fw_dump *fadump_conf) 27641df5928SHari Bathini { 2772a1b06ddSHari Bathini struct fadump_crash_info_header *fdh; 2782a1b06ddSHari Bathini int rc = -EINVAL; 2792a1b06ddSHari Bathini 2802a1b06ddSHari Bathini if (!opal_fdm_active || !fadump_conf->fadumphdr_addr) 2812a1b06ddSHari Bathini return rc; 2822a1b06ddSHari Bathini 2832a1b06ddSHari Bathini /* Validate the fadump crash info header */ 2842a1b06ddSHari Bathini fdh = __va(fadump_conf->fadumphdr_addr); 2852a1b06ddSHari Bathini if (fdh->magic_number != FADUMP_CRASH_INFO_MAGIC) { 2862a1b06ddSHari Bathini pr_err("Crash info header is not valid.\n"); 2872a1b06ddSHari Bathini return rc; 2882a1b06ddSHari Bathini } 2892a1b06ddSHari Bathini 2902a1b06ddSHari Bathini rc = opal_fadump_build_cpu_notes(fadump_conf, fdh); 2912a1b06ddSHari Bathini if (rc) 2922a1b06ddSHari Bathini return rc; 2932a1b06ddSHari Bathini 2942a1b06ddSHari Bathini /* 2952a1b06ddSHari Bathini * We are done validating dump info and elfcore header is now ready 2962a1b06ddSHari Bathini * to be exported. set elfcorehdr_addr so that vmcore module will 2972a1b06ddSHari Bathini * export the elfcore header through '/proc/vmcore'. 2982a1b06ddSHari Bathini */ 2992a1b06ddSHari Bathini elfcorehdr_addr = fdh->elfcorehdr_addr; 3002a1b06ddSHari Bathini 3012a1b06ddSHari Bathini return rc; 30241df5928SHari Bathini } 30341df5928SHari Bathini 30441df5928SHari Bathini static void opal_fadump_region_show(struct fw_dump *fadump_conf, 30541df5928SHari Bathini struct seq_file *m) 30641df5928SHari Bathini { 3072a1b06ddSHari Bathini const struct opal_fadump_mem_struct *fdm_ptr; 308742a265aSHari Bathini u64 dumped_bytes = 0; 309742a265aSHari Bathini int i; 310742a265aSHari Bathini 3112a1b06ddSHari Bathini if (fadump_conf->dump_active) 3122a1b06ddSHari Bathini fdm_ptr = opal_fdm_active; 3132a1b06ddSHari Bathini else 3142a1b06ddSHari Bathini fdm_ptr = opal_fdm; 3152a1b06ddSHari Bathini 316742a265aSHari Bathini for (i = 0; i < fdm_ptr->region_cnt; i++) { 3172a1b06ddSHari Bathini /* 3182a1b06ddSHari Bathini * Only regions that are registered for MPIPL 3192a1b06ddSHari Bathini * would have dump data. 3202a1b06ddSHari Bathini */ 3212a1b06ddSHari Bathini if ((fadump_conf->dump_active) && 3222a1b06ddSHari Bathini (i < fdm_ptr->registered_regions)) 3232a1b06ddSHari Bathini dumped_bytes = fdm_ptr->rgn[i].size; 3242a1b06ddSHari Bathini 325742a265aSHari Bathini seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ", 326742a265aSHari Bathini fdm_ptr->rgn[i].src, fdm_ptr->rgn[i].dest); 327742a265aSHari Bathini seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n", 328742a265aSHari Bathini fdm_ptr->rgn[i].size, dumped_bytes); 329742a265aSHari Bathini } 3302a1b06ddSHari Bathini 3312a1b06ddSHari Bathini /* Dump is active. Show reserved area start address. */ 3322a1b06ddSHari Bathini if (fadump_conf->dump_active) { 3332a1b06ddSHari Bathini seq_printf(m, "\nMemory above %#016lx is reserved for saving crash dump\n", 3342a1b06ddSHari Bathini fadump_conf->reserve_dump_area_start); 3352a1b06ddSHari Bathini } 33641df5928SHari Bathini } 33741df5928SHari Bathini 33841df5928SHari Bathini static void opal_fadump_trigger(struct fadump_crash_info_header *fdh, 33941df5928SHari Bathini const char *msg) 34041df5928SHari Bathini { 34141df5928SHari Bathini int rc; 34241df5928SHari Bathini 34341df5928SHari Bathini rc = opal_cec_reboot2(OPAL_REBOOT_MPIPL, msg); 34441df5928SHari Bathini if (rc == OPAL_UNSUPPORTED) { 34541df5928SHari Bathini pr_emerg("Reboot type %d not supported.\n", 34641df5928SHari Bathini OPAL_REBOOT_MPIPL); 34741df5928SHari Bathini } else if (rc == OPAL_HARDWARE) 34841df5928SHari Bathini pr_emerg("No backend support for MPIPL!\n"); 34941df5928SHari Bathini } 35041df5928SHari Bathini 35141df5928SHari Bathini static struct fadump_ops opal_fadump_ops = { 35241df5928SHari Bathini .fadump_init_mem_struct = opal_fadump_init_mem_struct, 353742a265aSHari Bathini .fadump_get_metadata_size = opal_fadump_get_metadata_size, 354742a265aSHari Bathini .fadump_setup_metadata = opal_fadump_setup_metadata, 35541df5928SHari Bathini .fadump_register = opal_fadump_register, 35641df5928SHari Bathini .fadump_unregister = opal_fadump_unregister, 35741df5928SHari Bathini .fadump_invalidate = opal_fadump_invalidate, 3582790d01dSHari Bathini .fadump_cleanup = opal_fadump_cleanup, 35941df5928SHari Bathini .fadump_process = opal_fadump_process, 36041df5928SHari Bathini .fadump_region_show = opal_fadump_region_show, 36141df5928SHari Bathini .fadump_trigger = opal_fadump_trigger, 36241df5928SHari Bathini }; 36341df5928SHari Bathini 36441df5928SHari Bathini void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node) 36541df5928SHari Bathini { 3662a1b06ddSHari Bathini const __be32 *prop; 36741df5928SHari Bathini unsigned long dn; 3682a1b06ddSHari Bathini u64 addr = 0; 3692a1b06ddSHari Bathini s64 ret; 3702a1b06ddSHari Bathini 37141df5928SHari Bathini 37241df5928SHari Bathini /* 37341df5928SHari Bathini * Check if Firmware-Assisted Dump is supported. if yes, check 37441df5928SHari Bathini * if dump has been initiated on last reboot. 37541df5928SHari Bathini */ 37641df5928SHari Bathini dn = of_get_flat_dt_subnode_by_name(node, "dump"); 37741df5928SHari Bathini if (dn == -FDT_ERR_NOTFOUND) { 37841df5928SHari Bathini pr_debug("FADump support is missing!\n"); 37941df5928SHari Bathini return; 38041df5928SHari Bathini } 38141df5928SHari Bathini 38241df5928SHari Bathini if (!of_flat_dt_is_compatible(dn, "ibm,opal-dump")) { 38341df5928SHari Bathini pr_err("Support missing for this f/w version!\n"); 38441df5928SHari Bathini return; 38541df5928SHari Bathini } 38641df5928SHari Bathini 38741df5928SHari Bathini fadump_conf->ops = &opal_fadump_ops; 38841df5928SHari Bathini fadump_conf->fadump_supported = 1; 3892a1b06ddSHari Bathini 3902a1b06ddSHari Bathini /* 3912a1b06ddSHari Bathini * Check if dump has been initiated on last reboot. 3922a1b06ddSHari Bathini */ 3932a1b06ddSHari Bathini prop = of_get_flat_dt_prop(dn, "mpipl-boot", NULL); 3942a1b06ddSHari Bathini if (!prop) 3952a1b06ddSHari Bathini return; 3962a1b06ddSHari Bathini 3972a1b06ddSHari Bathini ret = opal_mpipl_query_tag(OPAL_MPIPL_TAG_KERNEL, &addr); 3982a1b06ddSHari Bathini if ((ret != OPAL_SUCCESS) || !addr) { 3992a1b06ddSHari Bathini pr_err("Failed to get Kernel metadata (%lld)\n", ret); 4002a1b06ddSHari Bathini return; 4012a1b06ddSHari Bathini } 4022a1b06ddSHari Bathini 4032a1b06ddSHari Bathini addr = be64_to_cpu(addr); 4042a1b06ddSHari Bathini pr_debug("Kernel metadata addr: %llx\n", addr); 4052a1b06ddSHari Bathini 4062a1b06ddSHari Bathini opal_fdm_active = __va(addr); 4072a1b06ddSHari Bathini if (opal_fdm_active->version != OPAL_FADUMP_VERSION) { 4082a1b06ddSHari Bathini pr_warn("Supported kernel metadata version: %u, found: %d!\n", 4092a1b06ddSHari Bathini OPAL_FADUMP_VERSION, opal_fdm_active->version); 4102a1b06ddSHari Bathini pr_warn("WARNING: Kernel metadata format mismatch identified! Core file maybe corrupted..\n"); 4112a1b06ddSHari Bathini } 4122a1b06ddSHari Bathini 4132a1b06ddSHari Bathini /* Kernel regions not registered with f/w for MPIPL */ 4142a1b06ddSHari Bathini if (opal_fdm_active->registered_regions == 0) { 4152a1b06ddSHari Bathini opal_fdm_active = NULL; 4162a1b06ddSHari Bathini return; 4172a1b06ddSHari Bathini } 4182a1b06ddSHari Bathini 4192a1b06ddSHari Bathini pr_info("Firmware-assisted dump is active.\n"); 4202a1b06ddSHari Bathini fadump_conf->dump_active = 1; 4212a1b06ddSHari Bathini opal_fadump_get_config(fadump_conf, opal_fdm_active); 42241df5928SHari Bathini } 423