summaryrefslogtreecommitdiff
path: root/arch/powerpc/platforms/powernv/opal-fadump.h
blob: 5eeb794b5eb1ec26285eaf651a4c42b95af6292b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
/* 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
 * in the capture kernel to process the crash dump.
 */
struct opal_fadump_mem_struct {
	u8	version;
	u8	reserved[3];
	__be16	region_cnt;		/* number of regions */
	__be16	registered_regions;	/* Regions registered for MPIPL */
	__be64	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) :
		       (u64 __force)(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 */