summaryrefslogtreecommitdiffstats
path: root/include/lib/extensions/ras_arch.h
blob: e0aee50e6e7cfb43bb4e9ca0b8da37b21038481d (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
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
/*
 * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved.
 * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#ifndef RAS_ARCH_H
#define RAS_ARCH_H

/*
 * Size of nodes implementing Standard Error Records - currently only 4k is
 * supported.
 */
#define STD_ERR_NODE_SIZE_NUM_K		4U

/*
 * Individual register offsets within an error record in Standard Error Record
 * format when error records are accessed through memory-mapped registers.
 */
#define ERR_FR(n)	(0x0ULL + (64ULL * (n)))
#define ERR_CTLR(n)	(0x8ULL + (64ULL * (n)))
#define ERR_STATUS(n)	(0x10ULL + (64ULL * (n)))
#define ERR_ADDR(n)	(0x18ULL + (64ULL * (n)))
#define ERR_MISC0(n)	(0x20ULL + (64ULL * (n)))
#define ERR_MISC1(n)	(0x28ULL + (64ULL * (n)))

/* Group Status Register (ERR_STATUS) offset */
#define ERR_GSR(base, size_num_k, n) \
	((base) + (0x380ULL * (size_num_k)) + (8ULL * (n)))

/* Management register offsets */
#define ERR_DEVID(base, size_num_k) \
	((base) + ((0x400ULL * (size_num_k)) - 0x100ULL) + 0xc8ULL)

#define ERR_DEVID_MASK	0xffffUL

/* Standard Error Record status register fields */
#define ERR_STATUS_AV_SHIFT	31
#define ERR_STATUS_AV_MASK	U(0x1)

#define ERR_STATUS_V_SHIFT	30
#define ERR_STATUS_V_MASK	U(0x1)

#define ERR_STATUS_UE_SHIFT	29
#define ERR_STATUS_UE_MASK	U(0x1)

#define ERR_STATUS_ER_SHIFT	28
#define ERR_STATUS_ER_MASK	U(0x1)

#define ERR_STATUS_OF_SHIFT	27
#define ERR_STATUS_OF_MASK	U(0x1)

#define ERR_STATUS_MV_SHIFT	26
#define ERR_STATUS_MV_MASK	U(0x1)

#define ERR_STATUS_CE_SHIFT	24
#define ERR_STATUS_CE_MASK	U(0x3)

#define ERR_STATUS_DE_SHIFT	23
#define ERR_STATUS_DE_MASK	U(0x1)

#define ERR_STATUS_PN_SHIFT	22
#define ERR_STATUS_PN_MASK	U(0x1)

#define ERR_STATUS_UET_SHIFT	20
#define ERR_STATUS_UET_MASK	U(0x3)

#define ERR_STATUS_IERR_SHIFT	8
#define ERR_STATUS_IERR_MASK	U(0xff)

#define ERR_STATUS_SERR_SHIFT	0
#define ERR_STATUS_SERR_MASK	U(0xff)

#define ERR_STATUS_GET_FIELD(_status, _field) \
	(((_status) >> ERR_STATUS_ ##_field ##_SHIFT) & ERR_STATUS_ ##_field ##_MASK)

#define ERR_STATUS_CLR_FIELD(_status, _field) \
	(_status) &= ~(ERR_STATUS_ ##_field ##_MASK << ERR_STATUS_ ##_field ##_SHIFT)

#define ERR_STATUS_SET_FIELD(_status, _field, _value) \
	(_status) |= (((_value) & ERR_STATUS_ ##_field ##_MASK) << ERR_STATUS_ ##_field ##_SHIFT)

#define ERR_STATUS_WRITE_FIELD(_status, _field, _value) do { \
		ERR_STATUS_CLR_FIELD(_status, _field, _value); \
		ERR_STATUS_SET_FIELD(_status, _field, _value); \
	} while (0)


/* Standard Error Record control register fields */
#define ERR_CTLR_WDUI_SHIFT	11
#define ERR_CTLR_WDUI_MASK	0x1

#define ERR_CTLR_RDUI_SHIFT	10
#define ERR_CTLR_RDUI_MASK	0x1
#define ERR_CTLR_DUI_SHIFT	ERR_CTLR_RDUI_SHIFT
#define ERR_CTLR_DUI_MASK	ERR_CTLR_RDUI_MASK

#define ERR_CTLR_WCFI_SHIFT	9
#define ERR_CTLR_WCFI_MASK	0x1

#define ERR_CTLR_RCFI_SHIFT	8
#define ERR_CTLR_RCFI_MASK	0x1
#define ERR_CTLR_CFI_SHIFT	ERR_CTLR_RCFI_SHIFT
#define ERR_CTLR_CFI_MASK	ERR_CTLR_RCFI_MASK

#define ERR_CTLR_WUE_SHIFT	7
#define ERR_CTLR_WUE_MASK	0x1

#define ERR_CTLR_WFI_SHIFT	6
#define ERR_CTLR_WFI_MASK	0x1

#define ERR_CTLR_WUI_SHIFT	5
#define ERR_CTLR_WUI_MASK	0x1

#define ERR_CTLR_RUE_SHIFT	4
#define ERR_CTLR_RUE_MASK	0x1
#define ERR_CTLR_UE_SHIFT	ERR_CTLR_RUE_SHIFT
#define ERR_CTLR_UE_MASK	ERR_CTLR_RUE_MASK

#define ERR_CTLR_RFI_SHIFT	3
#define ERR_CTLR_RFI_MASK	0x1
#define ERR_CTLR_FI_SHIFT	ERR_CTLR_RFI_SHIFT
#define ERR_CTLR_FI_MASK	ERR_CTLR_RFI_MASK

#define ERR_CTLR_RUI_SHIFT	2
#define ERR_CTLR_RUI_MASK	0x1
#define ERR_CTLR_UI_SHIFT	ERR_CTLR_RUI_SHIFT
#define ERR_CTLR_UI_MASK	ERR_CTLR_RUI_MASK

#define ERR_CTLR_ED_SHIFT	0
#define ERR_CTLR_ED_MASK	0x1

#define ERR_CTLR_CLR_FIELD(_ctlr, _field) \
	(_ctlr) &= ~(ERR_CTLR_ ##_field _MASK << ERR_CTLR_ ##_field ##_SHIFT)

#define ERR_CTLR_SET_FIELD(_ctlr, _field, _value) \
	(_ctlr) |= (((_value) & ERR_CTLR_ ##_field ##_MASK) << ERR_CTLR_ ##_field ##_SHIFT)

#define ERR_CTLR_ENABLE_FIELD(_ctlr, _field) \
	ERR_CTLR_SET_FIELD(_ctlr, _field, ERR_CTLR_ ##_field ##_MASK)

/* Uncorrected error types for Asynchronous exceptions */
#define ERROR_STATUS_UET_UC	0x0	/* Uncontainable */
#define ERROR_STATUS_UET_UEU	0x1	/* Unrecoverable */
#define ERROR_STATUS_UET_UEO	0x2	/* Restable */
#define ERROR_STATUS_UET_UER	0x3	/* Recoverable */

/* Error types for Synchronous exceptions */
#define ERROR_STATUS_SET_UER	0x0	/* Recoverable */
#define ERROR_STATUS_SET_UEO	0x1	/* Restable */
#define ERROR_STATUS_SET_UC	0x2     /* Uncontainable */
#define ERROR_STATUS_SET_CE	0x3     /* Corrected */

/* Number of architecturally-defined primary error codes */
#define ERROR_STATUS_NUM_SERR	U(22)

/* Implementation Defined Syndrome bit in ESR */
#define SERROR_IDS_BIT		U(24)

/*
 * Asynchronous Error Type in exception syndrome. The field has same values in
 * both DISR_EL1 and ESR_EL3 for SError.
 */
#define EABORT_AET_SHIFT	U(10)
#define EABORT_AET_WIDTH	U(3)
#define EABORT_AET_MASK		U(0x7)

/* DFSC field in Asynchronous exception syndrome */
#define EABORT_DFSC_SHIFT	U(0)
#define EABORT_DFSC_WIDTH	U(6)
#define EABORT_DFSC_MASK	U(0x3f)

/* Synchronous Error Type in exception syndrome. */
#define EABORT_SET_SHIFT	U(11)
#define EABORT_SET_WIDTH	U(2)
#define EABORT_SET_MASK		U(0x3)

/* DFSC code for SErrors */
#define DFSC_SERROR		0x11

/* I/DFSC code for synchronous external abort */
#define SYNC_EA_FSC		0x10

#ifndef __ASSEMBLER__

#include <arch.h>
#include <arch_helpers.h>
#include <assert.h>
#include <context.h>
#include <lib/mmio.h>
#include <stdint.h>

/*
 * Standard Error Record accessors for memory-mapped registers.
 */

static inline uint64_t ser_get_feature(uintptr_t base, unsigned int idx)
{
	return mmio_read_64(base + ERR_FR(idx));
}

static inline uint64_t ser_get_control(uintptr_t base, unsigned int idx)
{
	return mmio_read_64(base + ERR_CTLR(idx));
}

static inline uint64_t ser_get_status(uintptr_t base, unsigned int idx)
{
	return mmio_read_64(base + ERR_STATUS(idx));
}

/*
 * Error handling agent would write to the status register to clear an
 * identified/handled error. Most fields in the status register are
 * conditional write-one-to-clear.
 *
 * Typically, to clear the status, it suffices to write back the same value
 * previously read. However, if there were new, higher-priority errors recorded
 * on the node since status was last read, writing read value won't clear the
 * status. Therefore, an error handling agent must wait on and verify the status
 * has indeed been cleared.
 */
static inline void ser_set_status(uintptr_t base, unsigned int idx,
		uint64_t status)
{
	mmio_write_64(base + ERR_STATUS(idx), status);
}

static inline uint64_t ser_get_addr(uintptr_t base, unsigned int idx)
{
	return mmio_read_64(base + ERR_ADDR(idx));
}

static inline uint64_t ser_get_misc0(uintptr_t base, unsigned int idx)
{
	return mmio_read_64(base + ERR_MISC0(idx));
}

static inline uint64_t ser_get_misc1(uintptr_t base, unsigned int idx)
{
	return mmio_read_64(base + ERR_MISC1(idx));
}


/*
 * Standard Error Record helpers for System registers.
 */
static inline void ser_sys_select_record(unsigned int idx)
{
	unsigned int max_idx __unused =
		(unsigned int) read_erridr_el1() & ERRIDR_MASK;

	assert(idx < max_idx);

	write_errselr_el1(idx);
	isb();
}

/* Library functions to probe Standard Error Record */
int ser_probe_memmap(uintptr_t base, unsigned int size_num_k, int *probe_data);
int ser_probe_sysreg(unsigned int idx_start, unsigned int num_idx, int *probe_data);
#endif /* __ASSEMBLER__ */

#endif /* RAS_ARCH_H */