plat_ras.c 11.5 KB
Newer Older
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
/*
 * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <stdbool.h>
#include <stdint.h>

#include <common/debug.h>
#include <lib/bakery_lock.h>
#include <lib/extensions/ras.h>
#include <lib/utils_def.h>
#include <services/sdei.h>

#include <plat/common/platform.h>
#include <platform_def.h>
#include <tegra194_ras_private.h>
#include <tegra_def.h>
#include <tegra_platform.h>
#include <tegra_private.h>

/*
 * ERR<n>FR bits[63:32], it indicates supported RAS errors which can be enabled
 * by setting corresponding bits in ERR<n>CTLR
 */
#define ERR_FR_EN_BITS_MASK	0xFFFFFFFF00000000ULL

/* bakery lock for platform RAS handler. */
static DEFINE_BAKERY_LOCK(ras_handler_lock);
#define ras_lock()		bakery_lock_get(&ras_handler_lock)
#define ras_unlock()		bakery_lock_release(&ras_handler_lock)

/*
 * Function to handle an External Abort received at EL3.
 * This function is invoked by RAS framework.
 */
static void tegra194_ea_handler(unsigned int ea_reason, uint64_t syndrome,
		void *cookie, void *handle, uint64_t flags)
{
	int32_t ret;

	ras_lock();

45
46
	ERROR("MPIDR 0x%lx: exception reason=%u syndrome=0x%llx\n",
		read_mpidr(), ea_reason, syndrome);
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

	/* Call RAS EA handler */
	ret = ras_ea_handler(ea_reason, syndrome, cookie, handle, flags);
	if (ret != 0) {
		ERROR("RAS error handled!\n");
		ret = sdei_dispatch_event(TEGRA_SDEI_EP_EVENT_0 +
				plat_my_core_pos());
		if (ret != 0)
			ERROR("sdei_dispatch_event returned %d\n", ret);
	} else {
		ERROR("Not a RAS error!\n");
	}

	ras_unlock();
}

63
64
65
66
67
68
/*
 * Function to enable all supported RAS error report.
 *
 * Uncorrected errors are set to report as External abort (SError)
 * Corrected errors are set to report as interrupt.
 */
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
void tegra194_ras_enable(void)
{
	VERBOSE("%s\n", __func__);

	/* skip RAS enablement if not a silicon platform. */
	if (!tegra_platform_is_silicon()) {
		return;
	}

	/*
	 * Iterate for each group(num_idx ERRSELRs starting from idx_start)
	 * use normal for loop instead of for_each_err_record_info to get rid
	 * of MISRA noise..
	 */
	for (uint32_t i = 0U; i < err_record_mappings.num_err_records; i++) {

		const struct err_record_info *info = &err_record_mappings.err_records[i];

		uint32_t idx_start = info->sysreg.idx_start;
		uint32_t num_idx = info->sysreg.num_idx;
		const struct ras_aux_data *aux_data = (const struct ras_aux_data *)info->aux_data;

		assert(aux_data != NULL);

		for (uint32_t j = 0; j < num_idx; j++) {

95
96
97
98
99
100
101
102
			/* ERR<n>CTLR register value. */
			uint64_t err_ctrl = 0ULL;
			/* all supported errors for this node. */
			uint64_t err_fr;
			/* uncorrectable errors */
			uint64_t uncorr_errs;
			/* correctable errors */
			uint64_t corr_errs;
103
104
105
106
107
108
109

			/*
			 * Catch error if something wrong with the RAS aux data
			 * record table.
			 */
			assert(aux_data[j].err_ctrl != NULL);

110
111
112
113
114
			/*
			 * Write to ERRSELR_EL1 to select the RAS error node.
			 * Always program this at first to select corresponding
			 * RAS node before any other RAS register r/w.
			 */
115
116
			ser_sys_select_record(idx_start + j);

117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
			err_fr = read_erxfr_el1() & ERR_FR_EN_BITS_MASK;
			uncorr_errs = aux_data[j].err_ctrl();
			corr_errs = ~uncorr_errs & err_fr;

			/* enable error reporting */
			ERR_CTLR_ENABLE_FIELD(err_ctrl, ED);

			/* enable SError reporting for uncorrectable errors */
			if ((uncorr_errs & err_fr) != 0ULL) {
				ERR_CTLR_ENABLE_FIELD(err_ctrl, UE);
			}

			/* generate interrupt for corrected errors. */
			if (corr_errs != 0ULL) {
				ERR_CTLR_ENABLE_FIELD(err_ctrl, CFI);
			}

			/* enable the supported errors */
			err_ctrl |= err_fr;

			VERBOSE("errselr_el1:0x%x, erxfr:0x%llx, err_ctrl:0x%llx\n",
				idx_start + j, err_fr, err_ctrl);

			/* enable specified errors, or set to 0 if no supported error */
141
142
143
144
145
146
147
148
149
150
151
			write_erxctlr_el1(err_ctrl);

			/*
			 * Check if all the bit settings have been enabled to detect
			 * uncorrected/corrected errors, if not assert.
			 */
			assert(read_erxctlr_el1() == err_ctrl);
		}
	}
}

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
/*
 * Function to clear RAS ERR<n>STATUS for corrected RAS error.
 * This function ignores any new RAS error signaled during clearing; it is not
 * multi-core safe(no ras_lock is taken to reduce overhead).
 */
void tegra194_ras_corrected_err_clear(void)
{
	uint64_t clear_ce_status = 0ULL;

	ERR_STATUS_SET_FIELD(clear_ce_status, AV, 0x1UL);
	ERR_STATUS_SET_FIELD(clear_ce_status, V, 0x1UL);
	ERR_STATUS_SET_FIELD(clear_ce_status, OF, 0x1UL);
	ERR_STATUS_SET_FIELD(clear_ce_status, MV, 0x1UL);
	ERR_STATUS_SET_FIELD(clear_ce_status, CE, 0x3UL);

	for (uint32_t i = 0U; i < err_record_mappings.num_err_records; i++) {

		const struct err_record_info *info = &err_record_mappings.err_records[i];
		uint32_t idx_start = info->sysreg.idx_start;
		uint32_t num_idx = info->sysreg.num_idx;

		for (uint32_t j = 0U; j < num_idx; j++) {

			uint64_t status;
			uint32_t err_idx = idx_start + j;

			write_errselr_el1(err_idx);
			status = read_erxstatus_el1();

			if (ERR_STATUS_GET_FIELD(status, CE) != 0U) {
				write_erxstatus_el1(clear_ce_status);
			}
		}
	}
}

188
189
190
191
192
193
194
195
196
197
198
199
200
/* Function to probe an error from error record group. */
static int32_t tegra194_ras_record_probe(const struct err_record_info *info,
		int *probe_data)
{
	/* Skip probing if not a silicon platform */
	if (!tegra_platform_is_silicon()) {
		return 0;
	}

	return ser_probe_sysreg(info->sysreg.idx_start, info->sysreg.num_idx, probe_data);
}

/* Function to handle error from one given node */
201
static int32_t tegra194_ras_node_handler(uint32_t errselr, const char *name,
202
		const struct ras_error *errors, uint64_t status)
203
204
205
206
{
	bool found = false;
	uint32_t ierr = (uint32_t)ERR_STATUS_GET_FIELD(status, IERR);
	uint32_t serr = (uint32_t)ERR_STATUS_GET_FIELD(status, SERR);
207
	uint64_t val = 0;
208

209
210
211
	/* not a valid error. */
	if (ERR_STATUS_GET_FIELD(status, V) == 0U) {
		return 0;
212
213
	}

214
215
216
217
218
219
220
	ERR_STATUS_SET_FIELD(val, V, 1);

	/* keep the log print same as linux arm64_ras driver. */
	ERROR("**************************************\n");
	ERROR("RAS Error in %s, ERRSELR_EL1=0x%x:\n", name, errselr);
	ERROR("\tStatus = 0x%llx\n", status);

221
222
223
	/* Print uncorrectable errror information. */
	if (ERR_STATUS_GET_FIELD(status, UE) != 0U) {

224
225
226
		ERR_STATUS_SET_FIELD(val, UE, 1);
		ERR_STATUS_SET_FIELD(val, UET, 1);

227
228
229
		/* IERR to error message */
		for (uint32_t i = 0; errors[i].error_msg != NULL; i++) {
			if (ierr == errors[i].error_code) {
230
231
232
				ERROR("\tIERR = %s: 0x%x\n",
					errors[i].error_msg, ierr);

233
234
235
236
237
238
				found = true;
				break;
			}
		}

		if (!found) {
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
266
267
268
269
			ERROR("\tUnknown IERR: 0x%x\n", ierr);
		}

		ERROR("SERR = %s: 0x%x\n", ras_serr_to_str(serr), serr);

		/* Overflow, multiple errors have been detected. */
		if (ERR_STATUS_GET_FIELD(status, OF) != 0U) {
			ERROR("\tOverflow (there may be more errors) - "
				"Uncorrectable\n");
			ERR_STATUS_SET_FIELD(val, OF, 1);
		}

		ERROR("\tUncorrectable (this is fatal)\n");

		/* Miscellaneous Register Valid. */
		if (ERR_STATUS_GET_FIELD(status, MV) != 0U) {
			ERROR("\tMISC0 = 0x%lx\n", read_erxmisc0_el1());
			ERROR("\tMISC1 = 0x%lx\n", read_erxmisc1_el1());
			ERR_STATUS_SET_FIELD(val, MV, 1);
		}

		/* Address Valid. */
		if (ERR_STATUS_GET_FIELD(status, AV) != 0U) {
			ERROR("\tADDR = 0x%lx\n", read_erxaddr_el1());
			ERR_STATUS_SET_FIELD(val, AV, 1);
		}

		/* Deferred error */
		if (ERR_STATUS_GET_FIELD(status, DE) != 0U) {
			ERROR("\tDeferred error\n");
			ERR_STATUS_SET_FIELD(val, DE, 1);
270
271
272
273
274
275
		}

	} else {
		/* For corrected error, simply clear it. */
		VERBOSE("corrected RAS error is cleared: ERRSELR_EL1:0x%x, "
			"IERR:0x%x, SERR:0x%x\n", errselr, ierr, serr);
276
		ERR_STATUS_SET_FIELD(val, CE, 1);
277
	}
278

279
280
	ERROR("**************************************\n");

281
	/* Write to clear reported errors. */
282
	write_erxstatus_el1(val);
283

284
	/* error handled */
285
286
287
288
289
	return 0;
}

/* Function to handle one error node from an error record group. */
static int32_t tegra194_ras_record_handler(const struct err_record_info *info,
290
		int probe_data, const struct err_handler_data *const data __unused)
291
292
293
294
{
	uint32_t num_idx = info->sysreg.num_idx;
	uint32_t idx_start = info->sysreg.idx_start;
	const struct ras_aux_data *aux_data = info->aux_data;
295
296
	const struct ras_error *errors;
	uint32_t offset;
297
	const char *node_name;
298
299
300
301
302
303
304
305

	uint64_t status = 0ULL;

	VERBOSE("%s\n", __func__);

	assert(probe_data >= 0);
	assert((uint32_t)probe_data < num_idx);

306
307
	offset = (uint32_t)probe_data;
	errors = aux_data[offset].error_records;
308
	node_name = aux_data[offset].name;
309
310
311
312
313
314
315
316
317

	assert(errors != NULL);

	/* Write to ERRSELR_EL1 to select the error record */
	ser_sys_select_record(idx_start + offset);

	/* Retrieve status register from the error record */
	status = read_erxstatus_el1();

318
319
	return tegra194_ras_node_handler(idx_start + offset, node_name,
			errors, status);
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
}


/* Instantiate RAS nodes */
PER_CORE_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
PER_CLUSTER_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
CCPLEX_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)

/* Instantiate RAS node groups */
static struct ras_aux_data per_core_ras_group[] = {
	PER_CORE_RAS_GROUP_NODES
};

static struct ras_aux_data per_cluster_ras_group[] = {
	PER_CLUSTER_RAS_GROUP_NODES
};

static struct ras_aux_data scf_l3_ras_group[] = {
	SCF_L3_BANK_RAS_GROUP_NODES
};

static struct ras_aux_data ccplex_ras_group[] = {
    CCPLEX_RAS_GROUP_NODES
};

/*
 * We have same probe and handler for each error record group, use a macro to
 * simply the record definition.
 */
#define ADD_ONE_ERR_GROUP(errselr_start, group) \
	ERR_RECORD_SYSREG_V1((errselr_start), (uint32_t)ARRAY_SIZE((group)), \
			&tegra194_ras_record_probe, \
			&tegra194_ras_record_handler, (group))

/* RAS error record group information */
static struct err_record_info carmel_ras_records[] = {
	/*
	 * Per core ras error records
	 * ERRSELR starts from 0*256 + Logical_CPU_ID*16 + 0 to
	 * 0*256 + Logical_CPU_ID*16 + 5 for each group.
	 * 8 cores/groups, 6 * 8 nodes in total.
	 */
	ADD_ONE_ERR_GROUP(0x000, per_core_ras_group),
	ADD_ONE_ERR_GROUP(0x010, per_core_ras_group),
	ADD_ONE_ERR_GROUP(0x020, per_core_ras_group),
	ADD_ONE_ERR_GROUP(0x030, per_core_ras_group),
	ADD_ONE_ERR_GROUP(0x040, per_core_ras_group),
	ADD_ONE_ERR_GROUP(0x050, per_core_ras_group),
	ADD_ONE_ERR_GROUP(0x060, per_core_ras_group),
	ADD_ONE_ERR_GROUP(0x070, per_core_ras_group),

	/*
	 * Per cluster ras error records
	 * ERRSELR starts from 2*256 + Logical_Cluster_ID*16 + 0 to
	 * 2*256 + Logical_Cluster_ID*16 + 3.
	 * 4 clusters/groups, 3 * 4 nodes in total.
	 */
	ADD_ONE_ERR_GROUP(0x200, per_cluster_ras_group),
	ADD_ONE_ERR_GROUP(0x210, per_cluster_ras_group),
	ADD_ONE_ERR_GROUP(0x220, per_cluster_ras_group),
	ADD_ONE_ERR_GROUP(0x230, per_cluster_ras_group),

	/*
	 * SCF L3_Bank ras error records
	 * ERRSELR: 3*256 + L3_Bank_ID, L3_Bank_ID: 0-3
	 * 1 groups, 4 nodes in total.
	 */
	ADD_ONE_ERR_GROUP(0x300, scf_l3_ras_group),

	/*
	 * CCPLEX ras error records
	 * ERRSELR: 4*256 + Unit_ID, Unit_ID: 0 - 4
	 * 1 groups, 5 nodes in total.
	 */
	ADD_ONE_ERR_GROUP(0x400, ccplex_ras_group),
};

REGISTER_ERR_RECORD_INFO(carmel_ras_records);

/* dummy RAS interrupt */
static struct ras_interrupt carmel_ras_interrupts[] = {};
REGISTER_RAS_INTERRUPTS(carmel_ras_interrupts);

/*******************************************************************************
 * RAS handler for the platform
 ******************************************************************************/
void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
		void *handle, uint64_t flags)
{
#if RAS_EXTENSION
	tegra194_ea_handler(ea_reason, syndrome, cookie, handle, flags);
#else
	ERROR("Unhandled External Abort received on 0x%llx at EL3!\n",
			read_mpidr_el1());
	ERROR(" exception reason=%u syndrome=0x%lx\n", ea_reason, syndrome);
	panic();
#endif
}