18c2ecf20Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0-or-later */ 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Firmware-Assisted Dump support on POWER platform (OPAL). 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2019, Hari Bathini, IBM Corporation. 68c2ecf20Sopenharmony_ci */ 78c2ecf20Sopenharmony_ci 88c2ecf20Sopenharmony_ci#ifndef _POWERNV_OPAL_FADUMP_H 98c2ecf20Sopenharmony_ci#define _POWERNV_OPAL_FADUMP_H 108c2ecf20Sopenharmony_ci 118c2ecf20Sopenharmony_ci#include <asm/reg.h> 128c2ecf20Sopenharmony_ci 138c2ecf20Sopenharmony_ci/* 148c2ecf20Sopenharmony_ci * With kernel & initrd loaded at 512MB (with 256MB size), enforce a minimum 158c2ecf20Sopenharmony_ci * boot memory size of 768MB to ensure f/w loading kernel and initrd doesn't 168c2ecf20Sopenharmony_ci * mess with crash'ed kernel's memory during MPIPL. 178c2ecf20Sopenharmony_ci */ 188c2ecf20Sopenharmony_ci#define OPAL_FADUMP_MIN_BOOT_MEM (0x30000000UL) 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci/* 218c2ecf20Sopenharmony_ci * OPAL FADump metadata structure format version 228c2ecf20Sopenharmony_ci * 238c2ecf20Sopenharmony_ci * OPAL FADump kernel metadata structure stores kernel metadata needed to 248c2ecf20Sopenharmony_ci * register-for/process crash dump. Format version is used to keep a tab on 258c2ecf20Sopenharmony_ci * the changes in the structure format. The changes, if any, to the format 268c2ecf20Sopenharmony_ci * are expected to be minimal and backward compatible. 278c2ecf20Sopenharmony_ci */ 288c2ecf20Sopenharmony_ci#define OPAL_FADUMP_VERSION 0x1 298c2ecf20Sopenharmony_ci 308c2ecf20Sopenharmony_ci/* 318c2ecf20Sopenharmony_ci * OPAL FADump kernel metadata 328c2ecf20Sopenharmony_ci * 338c2ecf20Sopenharmony_ci * The address of this structure will be registered with f/w for retrieving 348c2ecf20Sopenharmony_ci * in the capture kernel to process the crash dump. 358c2ecf20Sopenharmony_ci */ 368c2ecf20Sopenharmony_cistruct opal_fadump_mem_struct { 378c2ecf20Sopenharmony_ci u8 version; 388c2ecf20Sopenharmony_ci u8 reserved[3]; 398c2ecf20Sopenharmony_ci __be16 region_cnt; /* number of regions */ 408c2ecf20Sopenharmony_ci __be16 registered_regions; /* Regions registered for MPIPL */ 418c2ecf20Sopenharmony_ci __be64 fadumphdr_addr; 428c2ecf20Sopenharmony_ci struct opal_mpipl_region rgn[FADUMP_MAX_MEM_REGS]; 438c2ecf20Sopenharmony_ci} __packed; 448c2ecf20Sopenharmony_ci 458c2ecf20Sopenharmony_ci/* 468c2ecf20Sopenharmony_ci * CPU state data 478c2ecf20Sopenharmony_ci * 488c2ecf20Sopenharmony_ci * CPU state data information is provided by f/w. The format for this data 498c2ecf20Sopenharmony_ci * is defined in the HDAT spec. Version is used to keep a tab on the changes 508c2ecf20Sopenharmony_ci * in this CPU state data format. Changes to this format are unlikely, but 518c2ecf20Sopenharmony_ci * if there are any changes, please refer to latest HDAT specification. 528c2ecf20Sopenharmony_ci */ 538c2ecf20Sopenharmony_ci#define HDAT_FADUMP_CPU_DATA_VER 1 548c2ecf20Sopenharmony_ci 558c2ecf20Sopenharmony_ci#define HDAT_FADUMP_CORE_INACTIVE (0x0F) 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci/* HDAT thread header for register entries */ 588c2ecf20Sopenharmony_cistruct hdat_fadump_thread_hdr { 598c2ecf20Sopenharmony_ci __be32 pir; 608c2ecf20Sopenharmony_ci /* 0x00 - 0x0F - The corresponding stop state of the core */ 618c2ecf20Sopenharmony_ci u8 core_state; 628c2ecf20Sopenharmony_ci u8 reserved[3]; 638c2ecf20Sopenharmony_ci 648c2ecf20Sopenharmony_ci __be32 offset; /* Offset to Register Entries array */ 658c2ecf20Sopenharmony_ci __be32 ecnt; /* Number of entries */ 668c2ecf20Sopenharmony_ci __be32 esize; /* Alloc size of each array entry in bytes */ 678c2ecf20Sopenharmony_ci __be32 eactsz; /* Actual size of each array entry in bytes */ 688c2ecf20Sopenharmony_ci} __packed; 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_ci/* Register types populated by f/w */ 718c2ecf20Sopenharmony_ci#define HDAT_FADUMP_REG_TYPE_GPR 0x01 728c2ecf20Sopenharmony_ci#define HDAT_FADUMP_REG_TYPE_SPR 0x02 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_ci/* ID numbers used by f/w while populating certain registers */ 758c2ecf20Sopenharmony_ci#define HDAT_FADUMP_REG_ID_NIP 0x7D0 768c2ecf20Sopenharmony_ci#define HDAT_FADUMP_REG_ID_MSR 0x7D1 778c2ecf20Sopenharmony_ci#define HDAT_FADUMP_REG_ID_CCR 0x7D2 788c2ecf20Sopenharmony_ci 798c2ecf20Sopenharmony_ci/* HDAT register entry. */ 808c2ecf20Sopenharmony_cistruct hdat_fadump_reg_entry { 818c2ecf20Sopenharmony_ci __be32 reg_type; 828c2ecf20Sopenharmony_ci __be32 reg_num; 838c2ecf20Sopenharmony_ci __be64 reg_val; 848c2ecf20Sopenharmony_ci} __packed; 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_cistatic inline void opal_fadump_set_regval_regnum(struct pt_regs *regs, 878c2ecf20Sopenharmony_ci u32 reg_type, u32 reg_num, 888c2ecf20Sopenharmony_ci u64 reg_val) 898c2ecf20Sopenharmony_ci{ 908c2ecf20Sopenharmony_ci if (reg_type == HDAT_FADUMP_REG_TYPE_GPR) { 918c2ecf20Sopenharmony_ci if (reg_num < 32) 928c2ecf20Sopenharmony_ci regs->gpr[reg_num] = reg_val; 938c2ecf20Sopenharmony_ci return; 948c2ecf20Sopenharmony_ci } 958c2ecf20Sopenharmony_ci 968c2ecf20Sopenharmony_ci switch (reg_num) { 978c2ecf20Sopenharmony_ci case SPRN_CTR: 988c2ecf20Sopenharmony_ci regs->ctr = reg_val; 998c2ecf20Sopenharmony_ci break; 1008c2ecf20Sopenharmony_ci case SPRN_LR: 1018c2ecf20Sopenharmony_ci regs->link = reg_val; 1028c2ecf20Sopenharmony_ci break; 1038c2ecf20Sopenharmony_ci case SPRN_XER: 1048c2ecf20Sopenharmony_ci regs->xer = reg_val; 1058c2ecf20Sopenharmony_ci break; 1068c2ecf20Sopenharmony_ci case SPRN_DAR: 1078c2ecf20Sopenharmony_ci regs->dar = reg_val; 1088c2ecf20Sopenharmony_ci break; 1098c2ecf20Sopenharmony_ci case SPRN_DSISR: 1108c2ecf20Sopenharmony_ci regs->dsisr = reg_val; 1118c2ecf20Sopenharmony_ci break; 1128c2ecf20Sopenharmony_ci case HDAT_FADUMP_REG_ID_NIP: 1138c2ecf20Sopenharmony_ci regs->nip = reg_val; 1148c2ecf20Sopenharmony_ci break; 1158c2ecf20Sopenharmony_ci case HDAT_FADUMP_REG_ID_MSR: 1168c2ecf20Sopenharmony_ci regs->msr = reg_val; 1178c2ecf20Sopenharmony_ci break; 1188c2ecf20Sopenharmony_ci case HDAT_FADUMP_REG_ID_CCR: 1198c2ecf20Sopenharmony_ci regs->ccr = reg_val; 1208c2ecf20Sopenharmony_ci break; 1218c2ecf20Sopenharmony_ci } 1228c2ecf20Sopenharmony_ci} 1238c2ecf20Sopenharmony_ci 1248c2ecf20Sopenharmony_cistatic inline void opal_fadump_read_regs(char *bufp, unsigned int regs_cnt, 1258c2ecf20Sopenharmony_ci unsigned int reg_entry_size, 1268c2ecf20Sopenharmony_ci bool cpu_endian, 1278c2ecf20Sopenharmony_ci struct pt_regs *regs) 1288c2ecf20Sopenharmony_ci{ 1298c2ecf20Sopenharmony_ci struct hdat_fadump_reg_entry *reg_entry; 1308c2ecf20Sopenharmony_ci u64 val; 1318c2ecf20Sopenharmony_ci int i; 1328c2ecf20Sopenharmony_ci 1338c2ecf20Sopenharmony_ci memset(regs, 0, sizeof(struct pt_regs)); 1348c2ecf20Sopenharmony_ci 1358c2ecf20Sopenharmony_ci for (i = 0; i < regs_cnt; i++, bufp += reg_entry_size) { 1368c2ecf20Sopenharmony_ci reg_entry = (struct hdat_fadump_reg_entry *)bufp; 1378c2ecf20Sopenharmony_ci val = (cpu_endian ? be64_to_cpu(reg_entry->reg_val) : 1388c2ecf20Sopenharmony_ci (u64)(reg_entry->reg_val)); 1398c2ecf20Sopenharmony_ci opal_fadump_set_regval_regnum(regs, 1408c2ecf20Sopenharmony_ci be32_to_cpu(reg_entry->reg_type), 1418c2ecf20Sopenharmony_ci be32_to_cpu(reg_entry->reg_num), 1428c2ecf20Sopenharmony_ci val); 1438c2ecf20Sopenharmony_ci } 1448c2ecf20Sopenharmony_ci} 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci#endif /* _POWERNV_OPAL_FADUMP_H */ 147