xref: /rk3399_ARM-atf/lib/extensions/ras/std_err_record.c (revision 30a8d96e4689be30b2caeb23fd071fadd1ec87cd)
1 /*
2  * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 #include <ras_arch.h>
7 #include <utils_def.h>
8 
9 /*
10  * Probe for error in memory-mapped registers containing error records
11  * implemented Standard Error Record format. Upon detecting an error, set probe
12  * data to the index of the record in error, and return 1; otherwise, return 0.
13  */
14 int ser_probe_memmap(uintptr_t base, unsigned int size_num_k, int *probe_data)
15 {
16 	unsigned int num_records, num_group_regs, i;
17 	uint64_t gsr;
18 
19 	assert(base != 0UL);
20 
21 	/* Only 4K supported for now */
22 	assert(size_num_k == STD_ERR_NODE_SIZE_NUM_K);
23 
24 	num_records = (unsigned int)
25 		(mmio_read_32(ERR_DEVID(base, size_num_k)) & ERR_DEVID_MASK);
26 
27 	/* A group register shows error status for 2^6 error records */
28 	num_group_regs = (num_records >> 6U) + 1U;
29 
30 	/* Iterate through group registers to find a record in error */
31 	for (i = 0; i < num_group_regs; i++) {
32 		gsr = mmio_read_64(ERR_GSR(base, size_num_k, i));
33 		if (gsr == 0ULL)
34 			continue;
35 
36 		/* Return the index of the record in error */
37 		if (probe_data != NULL)
38 			*probe_data = (((int) (i << 6U)) + __builtin_ctzll(gsr));
39 
40 		return 1;
41 	}
42 
43 	return 0;
44 }
45 
46 /*
47  * Probe for error in System Registers where error records are implemented in
48  * Standard Error Record format. Upon detecting an error, set probe data to the
49  * index of the record in error, and return 1; otherwise, return 0.
50  */
51 int ser_probe_sysreg(unsigned int idx_start, unsigned int num_idx, int *probe_data)
52 {
53 	unsigned int i;
54 	uint64_t status;
55 	unsigned int max_idx __unused =
56 		((unsigned int) read_erridr_el1()) & ERRIDR_MASK;
57 
58 	assert(idx_start < max_idx);
59 	assert(check_u32_overflow(idx_start, num_idx));
60 	assert((idx_start + num_idx - 1U) < max_idx);
61 
62 	for (i = 0; i < num_idx; i++) {
63 		/* Select the error record */
64 		ser_sys_select_record(idx_start + i);
65 
66 		/* Retrieve status register from the error record */
67 		status = read_erxstatus_el1();
68 
69 		/* Check for valid field in status */
70 		if (ERR_STATUS_GET_FIELD(status, V) != 0U) {
71 			if (probe_data != NULL)
72 				*probe_data = (int) i;
73 			return 1;
74 		}
75 	}
76 
77 	return 0;
78 }
79