xref: /rk3399_ARM-atf/lib/extensions/ras/ras_common.c (revision 72e8f2456af54b75a0a1d92aadfce0b4bcde6ba1)
1362599ecSJeenu Viswambharan /*
2*4c700c15SGovindraj Raja  * Copyright (c) 2018-2021, Arm Limited and Contributors. All rights reserved.
38ca61538SDavid Pu  * Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
4362599ecSJeenu Viswambharan  *
5362599ecSJeenu Viswambharan  * SPDX-License-Identifier: BSD-3-Clause
6362599ecSJeenu Viswambharan  */
7362599ecSJeenu Viswambharan 
830a8d96eSJeenu Viswambharan #include <stdbool.h>
9362599ecSJeenu Viswambharan 
1009d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
1109d40e0eSAntonio Nino Diaz #include <bl31/ea_handle.h>
1209d40e0eSAntonio Nino Diaz #include <bl31/ehf.h>
1309d40e0eSAntonio Nino Diaz #include <common/debug.h>
1409d40e0eSAntonio Nino Diaz #include <lib/extensions/ras.h>
1509d40e0eSAntonio Nino Diaz #include <lib/extensions/ras_arch.h>
1609d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
1709d40e0eSAntonio Nino Diaz 
18ca6d9185SJeenu Viswambharan #ifndef PLAT_RAS_PRI
19ca6d9185SJeenu Viswambharan # error Platform must define RAS priority value
20ca6d9185SJeenu Viswambharan #endif
21ca6d9185SJeenu Viswambharan 
228ca61538SDavid Pu /*
238ca61538SDavid Pu  * Function to convert architecturally-defined primary error code SERR,
248ca61538SDavid Pu  * bits[7:0] from ERR<n>STATUS to its corresponding error string.
258ca61538SDavid Pu  */
ras_serr_to_str(unsigned int serr)268ca61538SDavid Pu const char *ras_serr_to_str(unsigned int serr)
278ca61538SDavid Pu {
288ca61538SDavid Pu 	const char *str[ERROR_STATUS_NUM_SERR] = {
298ca61538SDavid Pu 		"No error",
308ca61538SDavid Pu 		"IMPLEMENTATION DEFINED error",
318ca61538SDavid Pu 		"Data value from (non-associative) internal memory",
328ca61538SDavid Pu 		"IMPLEMENTATION DEFINED pin",
338ca61538SDavid Pu 		"Assertion failure",
348ca61538SDavid Pu 		"Error detected on internal data path",
358ca61538SDavid Pu 		"Data value from associative memory",
368ca61538SDavid Pu 		"Address/control value from associative memory",
378ca61538SDavid Pu 		"Data value from a TLB",
388ca61538SDavid Pu 		"Address/control value from a TLB",
398ca61538SDavid Pu 		"Data value from producer",
408ca61538SDavid Pu 		"Address/control value from producer",
418ca61538SDavid Pu 		"Data value from (non-associative) external memory",
428ca61538SDavid Pu 		"Illegal address (software fault)",
438ca61538SDavid Pu 		"Illegal access (software fault)",
448ca61538SDavid Pu 		"Illegal state (software fault)",
458ca61538SDavid Pu 		"Internal data register",
468ca61538SDavid Pu 		"Internal control register",
478ca61538SDavid Pu 		"Error response from slave",
488ca61538SDavid Pu 		"External timeout",
498ca61538SDavid Pu 		"Internal timeout",
508ca61538SDavid Pu 		"Deferred error from slave not supported at master"
518ca61538SDavid Pu 	};
528ca61538SDavid Pu 
538ca61538SDavid Pu 	/*
548ca61538SDavid Pu 	 * All other values are reserved. Reserved values might be defined
558ca61538SDavid Pu 	 * in a future version of the architecture
568ca61538SDavid Pu 	 */
578ca61538SDavid Pu 	if (serr >= ERROR_STATUS_NUM_SERR)
588ca61538SDavid Pu 		return "unknown SERR";
598ca61538SDavid Pu 
608ca61538SDavid Pu 	return str[serr];
618ca61538SDavid Pu }
628ca61538SDavid Pu 
63362599ecSJeenu Viswambharan /* Handler that receives External Aborts on RAS-capable systems */
ras_ea_handler(unsigned int ea_reason,uint64_t syndrome,void * cookie,void * handle,uint64_t flags)64362599ecSJeenu Viswambharan int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
65362599ecSJeenu Viswambharan 		void *handle, uint64_t flags)
66362599ecSJeenu Viswambharan {
6730a8d96eSJeenu Viswambharan 	unsigned int i, n_handled = 0;
6830a8d96eSJeenu Viswambharan 	int probe_data, ret;
69362599ecSJeenu Viswambharan 	struct err_record_info *info;
70362599ecSJeenu Viswambharan 
71362599ecSJeenu Viswambharan 	const struct err_handler_data err_data = {
72362599ecSJeenu Viswambharan 		.version = ERR_HANDLER_VERSION,
73362599ecSJeenu Viswambharan 		.ea_reason = ea_reason,
74ca6d9185SJeenu Viswambharan 		.interrupt = 0,
7530a8d96eSJeenu Viswambharan 		.syndrome = (uint32_t) syndrome,
76362599ecSJeenu Viswambharan 		.flags = flags,
77362599ecSJeenu Viswambharan 		.cookie = cookie,
78362599ecSJeenu Viswambharan 		.handle = handle
79362599ecSJeenu Viswambharan 	};
80362599ecSJeenu Viswambharan 
81362599ecSJeenu Viswambharan 	for_each_err_record_info(i, info) {
82362599ecSJeenu Viswambharan 		assert(info->probe != NULL);
83362599ecSJeenu Viswambharan 		assert(info->handler != NULL);
84362599ecSJeenu Viswambharan 
85362599ecSJeenu Viswambharan 		/* Continue probing until the record group signals no error */
8630a8d96eSJeenu Viswambharan 		while (true) {
87362599ecSJeenu Viswambharan 			if (info->probe(info, &probe_data) == 0)
88362599ecSJeenu Viswambharan 				break;
89362599ecSJeenu Viswambharan 
90362599ecSJeenu Viswambharan 			/* Handle error */
91362599ecSJeenu Viswambharan 			ret = info->handler(info, probe_data, &err_data);
92362599ecSJeenu Viswambharan 			if (ret != 0)
93362599ecSJeenu Viswambharan 				return ret;
94362599ecSJeenu Viswambharan 
95362599ecSJeenu Viswambharan 			n_handled++;
96362599ecSJeenu Viswambharan 		}
97362599ecSJeenu Viswambharan 	}
98362599ecSJeenu Viswambharan 
9930a8d96eSJeenu Viswambharan 	return (n_handled != 0U) ? 1 : 0;
100362599ecSJeenu Viswambharan }
101ca6d9185SJeenu Viswambharan 
102ca6d9185SJeenu Viswambharan #if ENABLE_ASSERTIONS
assert_interrupts_sorted(void)103ca6d9185SJeenu Viswambharan static void assert_interrupts_sorted(void)
104ca6d9185SJeenu Viswambharan {
105ca6d9185SJeenu Viswambharan 	unsigned int i, last;
10630a8d96eSJeenu Viswambharan 	struct ras_interrupt *start = ras_interrupt_mappings.intrs;
107ca6d9185SJeenu Viswambharan 
10830a8d96eSJeenu Viswambharan 	if (ras_interrupt_mappings.num_intrs == 0UL)
109ca6d9185SJeenu Viswambharan 		return;
110ca6d9185SJeenu Viswambharan 
111ca6d9185SJeenu Viswambharan 	last = start[0].intr_number;
11230a8d96eSJeenu Viswambharan 	for (i = 1; i < ras_interrupt_mappings.num_intrs; i++) {
113ca6d9185SJeenu Viswambharan 		assert(start[i].intr_number > last);
114ca6d9185SJeenu Viswambharan 		last = start[i].intr_number;
115ca6d9185SJeenu Viswambharan 	}
116ca6d9185SJeenu Viswambharan }
117ca6d9185SJeenu Viswambharan #endif
118ca6d9185SJeenu Viswambharan 
119ca6d9185SJeenu Viswambharan /*
120ca6d9185SJeenu Viswambharan  * Given an RAS interrupt number, locate the registered handler and call it. If
121ca6d9185SJeenu Viswambharan  * no handler was found for the interrupt number, this function panics.
122ca6d9185SJeenu Viswambharan  */
ras_interrupt_handler(uint32_t intr_raw,uint32_t flags,void * handle,void * cookie)123ca6d9185SJeenu Viswambharan static int ras_interrupt_handler(uint32_t intr_raw, uint32_t flags,
124ca6d9185SJeenu Viswambharan 		void *handle, void *cookie)
125ca6d9185SJeenu Viswambharan {
12630a8d96eSJeenu Viswambharan 	struct ras_interrupt *ras_inrs = ras_interrupt_mappings.intrs;
127ca6d9185SJeenu Viswambharan 	struct ras_interrupt *selected = NULL;
128dbff5263SJustin Chadwell 	int probe_data = 0;
129dbff5263SJustin Chadwell 	int start, end, mid, ret __unused;
130ca6d9185SJeenu Viswambharan 
131ca6d9185SJeenu Viswambharan 	const struct err_handler_data err_data = {
132ca6d9185SJeenu Viswambharan 		.version = ERR_HANDLER_VERSION,
133ca6d9185SJeenu Viswambharan 		.interrupt = intr_raw,
134ca6d9185SJeenu Viswambharan 		.flags = flags,
135ca6d9185SJeenu Viswambharan 		.cookie = cookie,
136ca6d9185SJeenu Viswambharan 		.handle = handle
137ca6d9185SJeenu Viswambharan 	};
138ca6d9185SJeenu Viswambharan 
13930a8d96eSJeenu Viswambharan 	assert(ras_interrupt_mappings.num_intrs > 0UL);
140ca6d9185SJeenu Viswambharan 
141ca6d9185SJeenu Viswambharan 	start = 0;
1420b1838a9SHeyi Guo 	end = (int)ras_interrupt_mappings.num_intrs - 1;
143ca6d9185SJeenu Viswambharan 	while (start <= end) {
144ca6d9185SJeenu Viswambharan 		mid = ((end + start) / 2);
145ca6d9185SJeenu Viswambharan 		if (intr_raw == ras_inrs[mid].intr_number) {
146ca6d9185SJeenu Viswambharan 			selected = &ras_inrs[mid];
147ca6d9185SJeenu Viswambharan 			break;
148ca6d9185SJeenu Viswambharan 		} else if (intr_raw < ras_inrs[mid].intr_number) {
149ca6d9185SJeenu Viswambharan 			/* Move left */
150ca6d9185SJeenu Viswambharan 			end = mid - 1;
151ca6d9185SJeenu Viswambharan 		} else {
152ca6d9185SJeenu Viswambharan 			/* Move right */
153ca6d9185SJeenu Viswambharan 			start = mid + 1;
154ca6d9185SJeenu Viswambharan 		}
155ca6d9185SJeenu Viswambharan 	}
156ca6d9185SJeenu Viswambharan 
157ca6d9185SJeenu Viswambharan 	if (selected == NULL) {
158ca6d9185SJeenu Viswambharan 		ERROR("RAS interrupt %u has no handler!\n", intr_raw);
159ca6d9185SJeenu Viswambharan 		panic();
160ca6d9185SJeenu Viswambharan 	}
161ca6d9185SJeenu Viswambharan 
16230a8d96eSJeenu Viswambharan 	if (selected->err_record->probe != NULL) {
163ca6d9185SJeenu Viswambharan 		ret = selected->err_record->probe(selected->err_record, &probe_data);
164ca6d9185SJeenu Viswambharan 		assert(ret != 0);
1654576f73cSSughosh Ganu 	}
166ca6d9185SJeenu Viswambharan 
167ca6d9185SJeenu Viswambharan 	/* Call error handler for the record group */
168ca6d9185SJeenu Viswambharan 	assert(selected->err_record->handler != NULL);
16930a8d96eSJeenu Viswambharan 	(void) selected->err_record->handler(selected->err_record, probe_data,
170ca6d9185SJeenu Viswambharan 			&err_data);
171ca6d9185SJeenu Viswambharan 
172ca6d9185SJeenu Viswambharan 	return 0;
173ca6d9185SJeenu Viswambharan }
174ca6d9185SJeenu Viswambharan 
ras_init(void)17587c85134SDaniel Boulby void __init ras_init(void)
176ca6d9185SJeenu Viswambharan {
177ca6d9185SJeenu Viswambharan #if ENABLE_ASSERTIONS
178ca6d9185SJeenu Viswambharan 	/* Check RAS interrupts are sorted */
179ca6d9185SJeenu Viswambharan 	assert_interrupts_sorted();
180ca6d9185SJeenu Viswambharan #endif
181ca6d9185SJeenu Viswambharan 
182ca6d9185SJeenu Viswambharan 	/* Register RAS priority handler */
183ca6d9185SJeenu Viswambharan 	ehf_register_priority_handler(PLAT_RAS_PRI, ras_interrupt_handler);
184ca6d9185SJeenu Viswambharan }
185