|  | /* SPDX-License-Identifier: GPL-2.0-or-later */ | 
|  | /* | 
|  | * Firmware-Assisted Dump support on POWER platform (OPAL). | 
|  | * | 
|  | * Copyright 2019, Hari Bathini, IBM Corporation. | 
|  | */ | 
|  |  | 
|  | #ifndef _POWERNV_OPAL_FADUMP_H | 
|  | #define _POWERNV_OPAL_FADUMP_H | 
|  |  | 
|  | #include <asm/reg.h> | 
|  |  | 
|  | /* | 
|  | * With kernel & initrd loaded at 512MB (with 256MB size), enforce a minimum | 
|  | * boot memory size of 768MB to ensure f/w loading kernel and initrd doesn't | 
|  | * mess with crash'ed kernel's memory during MPIPL. | 
|  | */ | 
|  | #define OPAL_FADUMP_MIN_BOOT_MEM		(0x30000000UL) | 
|  |  | 
|  | /* | 
|  | * OPAL FADump metadata structure format version | 
|  | * | 
|  | * OPAL FADump kernel metadata structure stores kernel metadata needed to | 
|  | * register-for/process crash dump. Format version is used to keep a tab on | 
|  | * the changes in the structure format. The changes, if any, to the format | 
|  | * are expected to be minimal and backward compatible. | 
|  | */ | 
|  | #define OPAL_FADUMP_VERSION			0x1 | 
|  |  | 
|  | /* | 
|  | * OPAL FADump kernel metadata | 
|  | * | 
|  | * The address of this structure will be registered with f/w for retrieving | 
|  | * and processing during crash dump. | 
|  | */ | 
|  | struct opal_fadump_mem_struct { | 
|  | u8	version; | 
|  | u8	reserved[3]; | 
|  | u16	region_cnt;		/* number of regions */ | 
|  | u16	registered_regions;	/* Regions registered for MPIPL */ | 
|  | u64	fadumphdr_addr; | 
|  | struct opal_mpipl_region	rgn[FADUMP_MAX_MEM_REGS]; | 
|  | } __packed; | 
|  |  | 
|  | /* | 
|  | * CPU state data | 
|  | * | 
|  | * CPU state data information is provided by f/w. The format for this data | 
|  | * is defined in the HDAT spec. Version is used to keep a tab on the changes | 
|  | * in this CPU state data format. Changes to this format are unlikely, but | 
|  | * if there are any changes, please refer to latest HDAT specification. | 
|  | */ | 
|  | #define HDAT_FADUMP_CPU_DATA_VER		1 | 
|  |  | 
|  | #define HDAT_FADUMP_CORE_INACTIVE		(0x0F) | 
|  |  | 
|  | /* HDAT thread header for register entries */ | 
|  | struct hdat_fadump_thread_hdr { | 
|  | __be32  pir; | 
|  | /* 0x00 - 0x0F - The corresponding stop state of the core */ | 
|  | u8      core_state; | 
|  | u8      reserved[3]; | 
|  |  | 
|  | __be32	offset;	/* Offset to Register Entries array */ | 
|  | __be32	ecnt;	/* Number of entries */ | 
|  | __be32	esize;	/* Alloc size of each array entry in bytes */ | 
|  | __be32	eactsz;	/* Actual size of each array entry in bytes */ | 
|  | } __packed; | 
|  |  | 
|  | /* Register types populated by f/w */ | 
|  | #define HDAT_FADUMP_REG_TYPE_GPR		0x01 | 
|  | #define HDAT_FADUMP_REG_TYPE_SPR		0x02 | 
|  |  | 
|  | /* ID numbers used by f/w while populating certain registers */ | 
|  | #define HDAT_FADUMP_REG_ID_NIP			0x7D0 | 
|  | #define HDAT_FADUMP_REG_ID_MSR			0x7D1 | 
|  | #define HDAT_FADUMP_REG_ID_CCR			0x7D2 | 
|  |  | 
|  | /* HDAT register entry. */ | 
|  | struct hdat_fadump_reg_entry { | 
|  | __be32		reg_type; | 
|  | __be32		reg_num; | 
|  | __be64		reg_val; | 
|  | } __packed; | 
|  |  | 
|  | static inline void opal_fadump_set_regval_regnum(struct pt_regs *regs, | 
|  | u32 reg_type, u32 reg_num, | 
|  | u64 reg_val) | 
|  | { | 
|  | if (reg_type == HDAT_FADUMP_REG_TYPE_GPR) { | 
|  | if (reg_num < 32) | 
|  | regs->gpr[reg_num] = reg_val; | 
|  | return; | 
|  | } | 
|  |  | 
|  | switch (reg_num) { | 
|  | case SPRN_CTR: | 
|  | regs->ctr = reg_val; | 
|  | break; | 
|  | case SPRN_LR: | 
|  | regs->link = reg_val; | 
|  | break; | 
|  | case SPRN_XER: | 
|  | regs->xer = reg_val; | 
|  | break; | 
|  | case SPRN_DAR: | 
|  | regs->dar = reg_val; | 
|  | break; | 
|  | case SPRN_DSISR: | 
|  | regs->dsisr = reg_val; | 
|  | break; | 
|  | case HDAT_FADUMP_REG_ID_NIP: | 
|  | regs->nip = reg_val; | 
|  | break; | 
|  | case HDAT_FADUMP_REG_ID_MSR: | 
|  | regs->msr = reg_val; | 
|  | break; | 
|  | case HDAT_FADUMP_REG_ID_CCR: | 
|  | regs->ccr = reg_val; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | static inline void opal_fadump_read_regs(char *bufp, unsigned int regs_cnt, | 
|  | unsigned int reg_entry_size, | 
|  | bool cpu_endian, | 
|  | struct pt_regs *regs) | 
|  | { | 
|  | struct hdat_fadump_reg_entry *reg_entry; | 
|  | u64 val; | 
|  | int i; | 
|  |  | 
|  | memset(regs, 0, sizeof(struct pt_regs)); | 
|  |  | 
|  | for (i = 0; i < regs_cnt; i++, bufp += reg_entry_size) { | 
|  | reg_entry = (struct hdat_fadump_reg_entry *)bufp; | 
|  | val = (cpu_endian ? be64_to_cpu(reg_entry->reg_val) : | 
|  | reg_entry->reg_val); | 
|  | opal_fadump_set_regval_regnum(regs, | 
|  | be32_to_cpu(reg_entry->reg_type), | 
|  | be32_to_cpu(reg_entry->reg_num), | 
|  | val); | 
|  | } | 
|  | } | 
|  |  | 
|  | #endif /* _POWERNV_OPAL_FADUMP_H */ |