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 1082790d01dSHari Bathini static void opal_fadump_cleanup(struct fw_dump *fadump_conf) 1092790d01dSHari Bathini { 1102790d01dSHari Bathini s64 ret; 1112790d01dSHari Bathini 1122790d01dSHari Bathini ret = opal_mpipl_register_tag(OPAL_MPIPL_TAG_KERNEL, 0); 1132790d01dSHari Bathini if (ret != OPAL_SUCCESS) 1142790d01dSHari Bathini pr_warn("Could not reset (%llu) kernel metadata tag!\n", ret); 1152790d01dSHari Bathini } 1162790d01dSHari Bathini 11741df5928SHari Bathini static int __init opal_fadump_process(struct fw_dump *fadump_conf) 11841df5928SHari Bathini { 11941df5928SHari Bathini return -EINVAL; 12041df5928SHari Bathini } 12141df5928SHari Bathini 12241df5928SHari Bathini static void opal_fadump_region_show(struct fw_dump *fadump_conf, 12341df5928SHari Bathini struct seq_file *m) 12441df5928SHari Bathini { 125742a265aSHari Bathini const struct opal_fadump_mem_struct *fdm_ptr = opal_fdm; 126742a265aSHari Bathini u64 dumped_bytes = 0; 127742a265aSHari Bathini int i; 128742a265aSHari Bathini 129742a265aSHari Bathini for (i = 0; i < fdm_ptr->region_cnt; i++) { 130742a265aSHari Bathini seq_printf(m, "DUMP: Src: %#016llx, Dest: %#016llx, ", 131742a265aSHari Bathini fdm_ptr->rgn[i].src, fdm_ptr->rgn[i].dest); 132742a265aSHari Bathini seq_printf(m, "Size: %#llx, Dumped: %#llx bytes\n", 133742a265aSHari Bathini fdm_ptr->rgn[i].size, dumped_bytes); 134742a265aSHari Bathini } 13541df5928SHari Bathini } 13641df5928SHari Bathini 13741df5928SHari Bathini static void opal_fadump_trigger(struct fadump_crash_info_header *fdh, 13841df5928SHari Bathini const char *msg) 13941df5928SHari Bathini { 14041df5928SHari Bathini int rc; 14141df5928SHari Bathini 14241df5928SHari Bathini rc = opal_cec_reboot2(OPAL_REBOOT_MPIPL, msg); 14341df5928SHari Bathini if (rc == OPAL_UNSUPPORTED) { 14441df5928SHari Bathini pr_emerg("Reboot type %d not supported.\n", 14541df5928SHari Bathini OPAL_REBOOT_MPIPL); 14641df5928SHari Bathini } else if (rc == OPAL_HARDWARE) 14741df5928SHari Bathini pr_emerg("No backend support for MPIPL!\n"); 14841df5928SHari Bathini } 14941df5928SHari Bathini 15041df5928SHari Bathini static struct fadump_ops opal_fadump_ops = { 15141df5928SHari Bathini .fadump_init_mem_struct = opal_fadump_init_mem_struct, 152742a265aSHari Bathini .fadump_get_metadata_size = opal_fadump_get_metadata_size, 153742a265aSHari Bathini .fadump_setup_metadata = opal_fadump_setup_metadata, 15441df5928SHari Bathini .fadump_register = opal_fadump_register, 15541df5928SHari Bathini .fadump_unregister = opal_fadump_unregister, 15641df5928SHari Bathini .fadump_invalidate = opal_fadump_invalidate, 1572790d01dSHari Bathini .fadump_cleanup = opal_fadump_cleanup, 15841df5928SHari Bathini .fadump_process = opal_fadump_process, 15941df5928SHari Bathini .fadump_region_show = opal_fadump_region_show, 16041df5928SHari Bathini .fadump_trigger = opal_fadump_trigger, 16141df5928SHari Bathini }; 16241df5928SHari Bathini 16341df5928SHari Bathini void __init opal_fadump_dt_scan(struct fw_dump *fadump_conf, u64 node) 16441df5928SHari Bathini { 16541df5928SHari Bathini unsigned long dn; 16641df5928SHari Bathini 16741df5928SHari Bathini /* 16841df5928SHari Bathini * Check if Firmware-Assisted Dump is supported. if yes, check 16941df5928SHari Bathini * if dump has been initiated on last reboot. 17041df5928SHari Bathini */ 17141df5928SHari Bathini dn = of_get_flat_dt_subnode_by_name(node, "dump"); 17241df5928SHari Bathini if (dn == -FDT_ERR_NOTFOUND) { 17341df5928SHari Bathini pr_debug("FADump support is missing!\n"); 17441df5928SHari Bathini return; 17541df5928SHari Bathini } 17641df5928SHari Bathini 17741df5928SHari Bathini if (!of_flat_dt_is_compatible(dn, "ibm,opal-dump")) { 17841df5928SHari Bathini pr_err("Support missing for this f/w version!\n"); 17941df5928SHari Bathini return; 18041df5928SHari Bathini } 18141df5928SHari Bathini 18241df5928SHari Bathini fadump_conf->ops = &opal_fadump_ops; 18341df5928SHari Bathini fadump_conf->fadump_supported = 1; 18441df5928SHari Bathini } 185