xref: /rk3399_ARM-atf/lib/extensions/ras/ras_common.c (revision ca6d9185829794f9d58dde706f94425a5c2cd9ef)
1362599ecSJeenu Viswambharan /*
2362599ecSJeenu Viswambharan  * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3362599ecSJeenu Viswambharan  *
4362599ecSJeenu Viswambharan  * SPDX-License-Identifier: BSD-3-Clause
5362599ecSJeenu Viswambharan  */
6362599ecSJeenu Viswambharan 
7362599ecSJeenu Viswambharan #include <arch_helpers.h>
8362599ecSJeenu Viswambharan #include <debug.h>
9362599ecSJeenu Viswambharan #include <ea_handle.h>
10362599ecSJeenu Viswambharan #include <ehf.h>
11362599ecSJeenu Viswambharan #include <platform.h>
12362599ecSJeenu Viswambharan #include <ras.h>
13362599ecSJeenu Viswambharan #include <ras_arch.h>
14362599ecSJeenu Viswambharan 
15*ca6d9185SJeenu Viswambharan #ifndef PLAT_RAS_PRI
16*ca6d9185SJeenu Viswambharan # error Platform must define RAS priority value
17*ca6d9185SJeenu Viswambharan #endif
18*ca6d9185SJeenu Viswambharan 
19362599ecSJeenu Viswambharan /* Handler that receives External Aborts on RAS-capable systems */
20362599ecSJeenu Viswambharan int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
21362599ecSJeenu Viswambharan 		void *handle, uint64_t flags)
22362599ecSJeenu Viswambharan {
23362599ecSJeenu Viswambharan 	unsigned int i, n_handled = 0, ret;
24362599ecSJeenu Viswambharan 	int probe_data;
25362599ecSJeenu Viswambharan 	struct err_record_info *info;
26362599ecSJeenu Viswambharan 
27362599ecSJeenu Viswambharan 	const struct err_handler_data err_data = {
28362599ecSJeenu Viswambharan 		.version = ERR_HANDLER_VERSION,
29362599ecSJeenu Viswambharan 		.ea_reason = ea_reason,
30*ca6d9185SJeenu Viswambharan 		.interrupt = 0,
31362599ecSJeenu Viswambharan 		.syndrome = syndrome,
32362599ecSJeenu Viswambharan 		.flags = flags,
33362599ecSJeenu Viswambharan 		.cookie = cookie,
34362599ecSJeenu Viswambharan 		.handle = handle
35362599ecSJeenu Viswambharan 	};
36362599ecSJeenu Viswambharan 
37362599ecSJeenu Viswambharan 	for_each_err_record_info(i, info) {
38362599ecSJeenu Viswambharan 		assert(info->probe != NULL);
39362599ecSJeenu Viswambharan 		assert(info->handler != NULL);
40362599ecSJeenu Viswambharan 
41362599ecSJeenu Viswambharan 		/* Continue probing until the record group signals no error */
42362599ecSJeenu Viswambharan 		while (1) {
43362599ecSJeenu Viswambharan 			if (info->probe(info, &probe_data) == 0)
44362599ecSJeenu Viswambharan 				break;
45362599ecSJeenu Viswambharan 
46362599ecSJeenu Viswambharan 			/* Handle error */
47362599ecSJeenu Viswambharan 			ret = info->handler(info, probe_data, &err_data);
48362599ecSJeenu Viswambharan 			if (ret != 0)
49362599ecSJeenu Viswambharan 				return ret;
50362599ecSJeenu Viswambharan 
51362599ecSJeenu Viswambharan 			n_handled++;
52362599ecSJeenu Viswambharan 		}
53362599ecSJeenu Viswambharan 	}
54362599ecSJeenu Viswambharan 
55362599ecSJeenu Viswambharan 	return (n_handled != 0);
56362599ecSJeenu Viswambharan }
57*ca6d9185SJeenu Viswambharan 
58*ca6d9185SJeenu Viswambharan #if ENABLE_ASSERTIONS
59*ca6d9185SJeenu Viswambharan static void assert_interrupts_sorted(void)
60*ca6d9185SJeenu Viswambharan {
61*ca6d9185SJeenu Viswambharan 	unsigned int i, last;
62*ca6d9185SJeenu Viswambharan 	struct ras_interrupt *start = ras_interrupt_mapping.intrs;
63*ca6d9185SJeenu Viswambharan 
64*ca6d9185SJeenu Viswambharan 	if (ras_interrupt_mapping.num_intrs == 0)
65*ca6d9185SJeenu Viswambharan 		return;
66*ca6d9185SJeenu Viswambharan 
67*ca6d9185SJeenu Viswambharan 	last = start[0].intr_number;
68*ca6d9185SJeenu Viswambharan 	for (i = 1; i < ras_interrupt_mapping.num_intrs; i++) {
69*ca6d9185SJeenu Viswambharan 		assert(start[i].intr_number > last);
70*ca6d9185SJeenu Viswambharan 		last = start[i].intr_number;
71*ca6d9185SJeenu Viswambharan 	}
72*ca6d9185SJeenu Viswambharan }
73*ca6d9185SJeenu Viswambharan #endif
74*ca6d9185SJeenu Viswambharan 
75*ca6d9185SJeenu Viswambharan /*
76*ca6d9185SJeenu Viswambharan  * Given an RAS interrupt number, locate the registered handler and call it. If
77*ca6d9185SJeenu Viswambharan  * no handler was found for the interrupt number, this function panics.
78*ca6d9185SJeenu Viswambharan  */
79*ca6d9185SJeenu Viswambharan static int ras_interrupt_handler(uint32_t intr_raw, uint32_t flags,
80*ca6d9185SJeenu Viswambharan 		void *handle, void *cookie)
81*ca6d9185SJeenu Viswambharan {
82*ca6d9185SJeenu Viswambharan 	struct ras_interrupt *ras_inrs = ras_interrupt_mapping.intrs;
83*ca6d9185SJeenu Viswambharan 	struct ras_interrupt *selected = NULL;
84*ca6d9185SJeenu Viswambharan 	int start, end, mid, probe_data, ret __unused;
85*ca6d9185SJeenu Viswambharan 
86*ca6d9185SJeenu Viswambharan 	const struct err_handler_data err_data = {
87*ca6d9185SJeenu Viswambharan 		.version = ERR_HANDLER_VERSION,
88*ca6d9185SJeenu Viswambharan 		.interrupt = intr_raw,
89*ca6d9185SJeenu Viswambharan 		.flags = flags,
90*ca6d9185SJeenu Viswambharan 		.cookie = cookie,
91*ca6d9185SJeenu Viswambharan 		.handle = handle
92*ca6d9185SJeenu Viswambharan 	};
93*ca6d9185SJeenu Viswambharan 
94*ca6d9185SJeenu Viswambharan 	assert(ras_interrupt_mapping.num_intrs > 0);
95*ca6d9185SJeenu Viswambharan 
96*ca6d9185SJeenu Viswambharan 	start = 0;
97*ca6d9185SJeenu Viswambharan 	end = ras_interrupt_mapping.num_intrs;
98*ca6d9185SJeenu Viswambharan 	while (start <= end) {
99*ca6d9185SJeenu Viswambharan 		mid = ((end + start) / 2);
100*ca6d9185SJeenu Viswambharan 		if (intr_raw == ras_inrs[mid].intr_number) {
101*ca6d9185SJeenu Viswambharan 			selected = &ras_inrs[mid];
102*ca6d9185SJeenu Viswambharan 			break;
103*ca6d9185SJeenu Viswambharan 		} else if (intr_raw < ras_inrs[mid].intr_number) {
104*ca6d9185SJeenu Viswambharan 			/* Move left */
105*ca6d9185SJeenu Viswambharan 			end = mid - 1;
106*ca6d9185SJeenu Viswambharan 		} else {
107*ca6d9185SJeenu Viswambharan 			/* Move right */
108*ca6d9185SJeenu Viswambharan 			start = mid + 1;
109*ca6d9185SJeenu Viswambharan 		}
110*ca6d9185SJeenu Viswambharan 	}
111*ca6d9185SJeenu Viswambharan 
112*ca6d9185SJeenu Viswambharan 	if (selected == NULL) {
113*ca6d9185SJeenu Viswambharan 		ERROR("RAS interrupt %u has no handler!\n", intr_raw);
114*ca6d9185SJeenu Viswambharan 		panic();
115*ca6d9185SJeenu Viswambharan 	}
116*ca6d9185SJeenu Viswambharan 
117*ca6d9185SJeenu Viswambharan 
118*ca6d9185SJeenu Viswambharan 	ret = selected->err_record->probe(selected->err_record, &probe_data);
119*ca6d9185SJeenu Viswambharan 	assert(ret != 0);
120*ca6d9185SJeenu Viswambharan 
121*ca6d9185SJeenu Viswambharan 	/* Call error handler for the record group */
122*ca6d9185SJeenu Viswambharan 	assert(selected->err_record->handler != NULL);
123*ca6d9185SJeenu Viswambharan 	selected->err_record->handler(selected->err_record, probe_data,
124*ca6d9185SJeenu Viswambharan 			&err_data);
125*ca6d9185SJeenu Viswambharan 
126*ca6d9185SJeenu Viswambharan 	return 0;
127*ca6d9185SJeenu Viswambharan }
128*ca6d9185SJeenu Viswambharan 
129*ca6d9185SJeenu Viswambharan void ras_init(void)
130*ca6d9185SJeenu Viswambharan {
131*ca6d9185SJeenu Viswambharan #if ENABLE_ASSERTIONS
132*ca6d9185SJeenu Viswambharan 	/* Check RAS interrupts are sorted */
133*ca6d9185SJeenu Viswambharan 	assert_interrupts_sorted();
134*ca6d9185SJeenu Viswambharan #endif
135*ca6d9185SJeenu Viswambharan 
136*ca6d9185SJeenu Viswambharan 	/* Register RAS priority handler */
137*ca6d9185SJeenu Viswambharan 	ehf_register_priority_handler(PLAT_RAS_PRI, ras_interrupt_handler);
138*ca6d9185SJeenu Viswambharan }
139