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> 1541df5928SHari Bathini 16742a265aSHari Bathini #include <asm/page.h> 1741df5928SHari Bathini #include <asm/opal.h> 1841df5928SHari Bathini #include <asm/fadump-internal.h> 1941df5928SHari Bathini 20742a265aSHari Bathini #include "opal-fadump.h" 21742a265aSHari Bathini 22742a265aSHari Bathini static struct opal_fadump_mem_struct *opal_fdm; 23742a265aSHari Bathini 24742a265aSHari Bathini /* Initialize kernel metadata */ 25742a265aSHari Bathini static void opal_fadump_init_metadata(struct opal_fadump_mem_struct *fdm) 26742a265aSHari Bathini { 27742a265aSHari Bathini fdm->version = OPAL_FADUMP_VERSION; 28742a265aSHari Bathini fdm->region_cnt = 0; 29742a265aSHari Bathini fdm->registered_regions = 0; 30742a265aSHari Bathini fdm->fadumphdr_addr = 0; 31742a265aSHari Bathini } 32742a265aSHari Bathini 3341df5928SHari Bathini static u64 opal_fadump_init_mem_struct(struct fw_dump *fadump_conf) 3441df5928SHari Bathini { 35742a265aSHari Bathini u64 addr = fadump_conf->reserve_dump_area_start; 36742a265aSHari Bathini 37742a265aSHari Bathini opal_fdm = __va(fadump_conf->kernel_metadata); 38742a265aSHari Bathini opal_fadump_init_metadata(opal_fdm); 39742a265aSHari Bathini 40742a265aSHari Bathini opal_fdm->region_cnt = 1; 41742a265aSHari Bathini opal_fdm->rgn[0].src = 0; 42742a265aSHari Bathini opal_fdm->rgn[0].dest = addr; 43742a265aSHari Bathini opal_fdm->rgn[0].size = fadump_conf->boot_memory_size; 44742a265aSHari Bathini addr += fadump_conf->boot_memory_size; 45742a265aSHari Bathini 46742a265aSHari Bathini /* 47742a265aSHari Bathini * Kernel metadata is passed to f/w and retrieved in capture kerenl. 48742a265aSHari Bathini * So, use it to save fadump header address instead of calculating it. 49742a265aSHari Bathini */ 50742a265aSHari Bathini opal_fdm->fadumphdr_addr = (opal_fdm->rgn[0].dest + 51742a265aSHari Bathini fadump_conf->boot_memory_size); 52742a265aSHari Bathini 53742a265aSHari Bathini return addr; 54742a265aSHari Bathini } 55742a265aSHari Bathini 56742a265aSHari Bathini static u64 opal_fadump_get_metadata_size(void) 57742a265aSHari Bathini { 58742a265aSHari Bathini return PAGE_ALIGN(sizeof(struct opal_fadump_mem_struct)); 59742a265aSHari Bathini } 60742a265aSHari Bathini 61742a265aSHari Bathini static int opal_fadump_setup_metadata(struct fw_dump *fadump_conf) 62742a265aSHari Bathini { 63742a265aSHari Bathini int err = 0; 64742a265aSHari Bathini s64 ret; 65742a265aSHari Bathini 66742a265aSHari Bathini /* 67742a265aSHari Bathini * Use the last page(s) in FADump memory reservation for 68742a265aSHari Bathini * kernel metadata. 69742a265aSHari Bathini */ 70742a265aSHari Bathini fadump_conf->kernel_metadata = (fadump_conf->reserve_dump_area_start + 71742a265aSHari Bathini fadump_conf->reserve_dump_area_size - 72742a265aSHari Bathini opal_fadump_get_metadata_size()); 73742a265aSHari Bathini pr_info("Kernel metadata addr: %llx\n", fadump_conf->kernel_metadata); 74742a265aSHari Bathini 75742a265aSHari Bathini /* Initialize kernel metadata before registering the address with f/w */ 76742a265aSHari Bathini opal_fdm = __va(fadump_conf->kernel_metadata); 77742a265aSHari Bathini opal_fadump_init_metadata(opal_fdm); 78742a265aSHari Bathini 79742a265aSHari Bathini /* 80742a265aSHari Bathini * Register metadata address with f/w. Can be retrieved in 81742a265aSHari Bathini * the capture kernel. 82742a265aSHari Bathini */ 83742a265aSHari Bathini ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_KERNEL, 84742a265aSHari Bathini fadump_conf->kernel_metadata); 85742a265aSHari Bathini if (ret != OPAL_SUCCESS) { 86742a265aSHari Bathini pr_err("Failed to set kernel metadata tag!\n"); 87742a265aSHari Bathini err = -EPERM; 88742a265aSHari Bathini } 89742a265aSHari Bathini 90742a265aSHari Bathini return err; 9141df5928SHari Bathini } 9241df5928SHari Bathini 9341df5928SHari Bathini static int opal_fadump_register(struct fw_dump *fadump_conf) 9441df5928SHari Bathini { 9541df5928SHari Bathini return -EIO; 9641df5928SHari Bathini } 9741df5928SHari Bathini 9841df5928SHari Bathini static int opal_fadump_unregister(struct fw_dump *fadump_conf) 9941df5928SHari Bathini { 10041df5928SHari Bathini return -EIO; 10141df5928SHari Bathini } 10241df5928SHari Bathini 10341df5928SHari Bathini static int opal_fadump_invalidate(struct fw_dump *fadump_conf) 10441df5928SHari Bathini { 10541df5928SHari Bathini return -EIO; 10641df5928SHari Bathini } 10741df5928SHari Bathini 10841df5928SHari Bathini static int __init opal_fadump_process(struct fw_dump *fadump_conf) 10941df5928SHari Bathini { 11041df5928SHari Bathini return -EINVAL; 11141df5928SHari Bathini } 11241df5928SHari Bathini 11341df5928SHari Bathini static void opal_fadump_region_show(struct fw_dump *fadump_conf, 11441df5928SHari Bathini struct seq_file *m) 11541df5928SHari Bathini { 116742a265aSHari Bathini const struct opal_fadump_mem_struct *fdm_ptr = opal_fdm; 117742a265aSHari Bathini u64 dumped_bytes = 0; 118742a265aSHari Bathini int i; 119742a265aSHari Bathini 120742a265aSHari Bathini for (i = 0; i < fdm_ptr->region_cnt; i++) { 121742a265aSHari Bathini seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ", 122742a265aSHari Bathini fdm_ptr->rgn[i].src, fdm_ptr->rgn[i].dest); 123742a265aSHari Bathini seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n", 124742a265aSHari Bathini fdm_ptr->rgn[i].size, dumped_bytes); 125742a265aSHari Bathini } 12641df5928SHari Bathini } 12741df5928SHari Bathini 12841df5928SHari Bathini static void opal_fadump_trigger(struct fadump_crash_info_header *fdh, 12941df5928SHari Bathini const char *msg) 13041df5928SHari Bathini { 13141df5928SHari Bathini int rc; 13241df5928SHari Bathini 13341df5928SHari Bathini rc = opal_cec_reboot2(OPAL_REBOOT_MPIPL, msg); 13441df5928SHari Bathini if (rc == OPAL_UNSUPPORTED) { 13541df5928SHari Bathini pr_emerg("Reboot type %d not supported.\n", 13641df5928SHari Bathini OPAL_REBOOT_MPIPL); 13741df5928SHari Bathini } else if (rc == OPAL_HARDWARE) 13841df5928SHari Bathini pr_emerg("No backend support for MPIPL!\n"); 13941df5928SHari Bathini } 14041df5928SHari Bathini 14141df5928SHari Bathini static struct fadump_ops opal_fadump_ops = { 14241df5928SHari Bathini .fadump_init_mem_struct = opal_fadump_init_mem_struct, 143742a265aSHari Bathini .fadump_get_metadata_size = opal_fadump_get_metadata_size, 144742a265aSHari Bathini .fadump_setup_metadata = opal_fadump_setup_metadata, 14541df5928SHari Bathini .fadump_register = opal_fadump_register, 14641df5928SHari Bathini .fadump_unregister = opal_fadump_unregister, 14741df5928SHari Bathini .fadump_invalidate = opal_fadump_invalidate, 14841df5928SHari Bathini .fadump_process = opal_fadump_process, 14941df5928SHari Bathini .fadump_region_show = opal_fadump_region_show, 15041df5928SHari Bathini .fadump_trigger = opal_fadump_trigger, 15141df5928SHari Bathini }; 15241df5928SHari Bathini 15341df5928SHari Bathini void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node) 15441df5928SHari Bathini { 15541df5928SHari Bathini unsigned long dn; 15641df5928SHari Bathini 15741df5928SHari Bathini /* 15841df5928SHari Bathini * Check if Firmware-Assisted Dump is supported. if yes, check 15941df5928SHari Bathini * if dump has been initiated on last reboot. 16041df5928SHari Bathini */ 16141df5928SHari Bathini dn = of_get_flat_dt_subnode_by_name(node, "dump"); 16241df5928SHari Bathini if (dn == -FDT_ERR_NOTFOUND) { 16341df5928SHari Bathini pr_debug("FADump support is missing!\n"); 16441df5928SHari Bathini return; 16541df5928SHari Bathini } 16641df5928SHari Bathini 16741df5928SHari Bathini if (!of_flat_dt_is_compatible(dn, "ibm,opal-dump")) { 16841df5928SHari Bathini pr_err("Support missing for this f/w version!\n"); 16941df5928SHari Bathini return; 17041df5928SHari Bathini } 17141df5928SHari Bathini 17241df5928SHari Bathini fadump_conf->ops = &opal_fadump_ops; 17341df5928SHari Bathini fadump_conf->fadump_supported = 1; 17441df5928SHari Bathini } 175