xref: /rk3399_ARM-atf/lib/extensions/ras/ras_common.c (revision dbff52633a6edb8f69a69fc7040a93ff388083a1)
1362599ecSJeenu Viswambharan /*
2*dbff5263SJustin Chadwell  * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
3362599ecSJeenu Viswambharan  *
4362599ecSJeenu Viswambharan  * SPDX-License-Identifier: BSD-3-Clause
5362599ecSJeenu Viswambharan  */
6362599ecSJeenu Viswambharan 
730a8d96eSJeenu Viswambharan #include <stdbool.h>
8362599ecSJeenu Viswambharan 
909d40e0eSAntonio Nino Diaz #include <arch_helpers.h>
1009d40e0eSAntonio Nino Diaz #include <bl31/ea_handle.h>
1109d40e0eSAntonio Nino Diaz #include <bl31/ehf.h>
1209d40e0eSAntonio Nino Diaz #include <common/debug.h>
1309d40e0eSAntonio Nino Diaz #include <lib/extensions/ras.h>
1409d40e0eSAntonio Nino Diaz #include <lib/extensions/ras_arch.h>
1509d40e0eSAntonio Nino Diaz #include <plat/common/platform.h>
1609d40e0eSAntonio Nino Diaz 
17ca6d9185SJeenu Viswambharan #ifndef PLAT_RAS_PRI
18ca6d9185SJeenu Viswambharan # error Platform must define RAS priority value
19ca6d9185SJeenu Viswambharan #endif
20ca6d9185SJeenu Viswambharan 
21362599ecSJeenu Viswambharan /* Handler that receives External Aborts on RAS-capable systems */
22362599ecSJeenu Viswambharan int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
23362599ecSJeenu Viswambharan 		void *handle, uint64_t flags)
24362599ecSJeenu Viswambharan {
2530a8d96eSJeenu Viswambharan 	unsigned int i, n_handled = 0;
2630a8d96eSJeenu Viswambharan 	int probe_data, ret;
27362599ecSJeenu Viswambharan 	struct err_record_info *info;
28362599ecSJeenu Viswambharan 
29362599ecSJeenu Viswambharan 	const struct err_handler_data err_data = {
30362599ecSJeenu Viswambharan 		.version = ERR_HANDLER_VERSION,
31362599ecSJeenu Viswambharan 		.ea_reason = ea_reason,
32ca6d9185SJeenu Viswambharan 		.interrupt = 0,
3330a8d96eSJeenu Viswambharan 		.syndrome = (uint32_t) syndrome,
34362599ecSJeenu Viswambharan 		.flags = flags,
35362599ecSJeenu Viswambharan 		.cookie = cookie,
36362599ecSJeenu Viswambharan 		.handle = handle
37362599ecSJeenu Viswambharan 	};
38362599ecSJeenu Viswambharan 
39362599ecSJeenu Viswambharan 	for_each_err_record_info(i, info) {
40362599ecSJeenu Viswambharan 		assert(info->probe != NULL);
41362599ecSJeenu Viswambharan 		assert(info->handler != NULL);
42362599ecSJeenu Viswambharan 
43362599ecSJeenu Viswambharan 		/* Continue probing until the record group signals no error */
4430a8d96eSJeenu Viswambharan 		while (true) {
45362599ecSJeenu Viswambharan 			if (info->probe(info, &probe_data) == 0)
46362599ecSJeenu Viswambharan 				break;
47362599ecSJeenu Viswambharan 
48362599ecSJeenu Viswambharan 			/* Handle error */
49362599ecSJeenu Viswambharan 			ret = info->handler(info, probe_data, &err_data);
50362599ecSJeenu Viswambharan 			if (ret != 0)
51362599ecSJeenu Viswambharan 				return ret;
52362599ecSJeenu Viswambharan 
53362599ecSJeenu Viswambharan 			n_handled++;
54362599ecSJeenu Viswambharan 		}
55362599ecSJeenu Viswambharan 	}
56362599ecSJeenu Viswambharan 
5730a8d96eSJeenu Viswambharan 	return (n_handled != 0U) ? 1 : 0;
58362599ecSJeenu Viswambharan }
59ca6d9185SJeenu Viswambharan 
60ca6d9185SJeenu Viswambharan #if ENABLE_ASSERTIONS
61ca6d9185SJeenu Viswambharan static void assert_interrupts_sorted(void)
62ca6d9185SJeenu Viswambharan {
63ca6d9185SJeenu Viswambharan 	unsigned int i, last;
6430a8d96eSJeenu Viswambharan 	struct ras_interrupt *start = ras_interrupt_mappings.intrs;
65ca6d9185SJeenu Viswambharan 
6630a8d96eSJeenu Viswambharan 	if (ras_interrupt_mappings.num_intrs == 0UL)
67ca6d9185SJeenu Viswambharan 		return;
68ca6d9185SJeenu Viswambharan 
69ca6d9185SJeenu Viswambharan 	last = start[0].intr_number;
7030a8d96eSJeenu Viswambharan 	for (i = 1; i < ras_interrupt_mappings.num_intrs; i++) {
71ca6d9185SJeenu Viswambharan 		assert(start[i].intr_number > last);
72ca6d9185SJeenu Viswambharan 		last = start[i].intr_number;
73ca6d9185SJeenu Viswambharan 	}
74ca6d9185SJeenu Viswambharan }
75ca6d9185SJeenu Viswambharan #endif
76ca6d9185SJeenu Viswambharan 
77ca6d9185SJeenu Viswambharan /*
78ca6d9185SJeenu Viswambharan  * Given an RAS interrupt number, locate the registered handler and call it. If
79ca6d9185SJeenu Viswambharan  * no handler was found for the interrupt number, this function panics.
80ca6d9185SJeenu Viswambharan  */
81ca6d9185SJeenu Viswambharan static int ras_interrupt_handler(uint32_t intr_raw, uint32_t flags,
82ca6d9185SJeenu Viswambharan 		void *handle, void *cookie)
83ca6d9185SJeenu Viswambharan {
8430a8d96eSJeenu Viswambharan 	struct ras_interrupt *ras_inrs = ras_interrupt_mappings.intrs;
85ca6d9185SJeenu Viswambharan 	struct ras_interrupt *selected = NULL;
86*dbff5263SJustin Chadwell 	int probe_data = 0;
87*dbff5263SJustin Chadwell 	int start, end, mid, ret __unused;
88ca6d9185SJeenu Viswambharan 
89ca6d9185SJeenu Viswambharan 	const struct err_handler_data err_data = {
90ca6d9185SJeenu Viswambharan 		.version = ERR_HANDLER_VERSION,
91ca6d9185SJeenu Viswambharan 		.interrupt = intr_raw,
92ca6d9185SJeenu Viswambharan 		.flags = flags,
93ca6d9185SJeenu Viswambharan 		.cookie = cookie,
94ca6d9185SJeenu Viswambharan 		.handle = handle
95ca6d9185SJeenu Viswambharan 	};
96ca6d9185SJeenu Viswambharan 
9730a8d96eSJeenu Viswambharan 	assert(ras_interrupt_mappings.num_intrs > 0UL);
98ca6d9185SJeenu Viswambharan 
99ca6d9185SJeenu Viswambharan 	start = 0;
10030a8d96eSJeenu Viswambharan 	end = (int) ras_interrupt_mappings.num_intrs;
101ca6d9185SJeenu Viswambharan 	while (start <= end) {
102ca6d9185SJeenu Viswambharan 		mid = ((end + start) / 2);
103ca6d9185SJeenu Viswambharan 		if (intr_raw == ras_inrs[mid].intr_number) {
104ca6d9185SJeenu Viswambharan 			selected = &ras_inrs[mid];
105ca6d9185SJeenu Viswambharan 			break;
106ca6d9185SJeenu Viswambharan 		} else if (intr_raw < ras_inrs[mid].intr_number) {
107ca6d9185SJeenu Viswambharan 			/* Move left */
108ca6d9185SJeenu Viswambharan 			end = mid - 1;
109ca6d9185SJeenu Viswambharan 		} else {
110ca6d9185SJeenu Viswambharan 			/* Move right */
111ca6d9185SJeenu Viswambharan 			start = mid + 1;
112ca6d9185SJeenu Viswambharan 		}
113ca6d9185SJeenu Viswambharan 	}
114ca6d9185SJeenu Viswambharan 
115ca6d9185SJeenu Viswambharan 	if (selected == NULL) {
116ca6d9185SJeenu Viswambharan 		ERROR("RAS interrupt %u has no handler!\n", intr_raw);
117ca6d9185SJeenu Viswambharan 		panic();
118ca6d9185SJeenu Viswambharan 	}
119ca6d9185SJeenu Viswambharan 
12030a8d96eSJeenu Viswambharan 	if (selected->err_record->probe != NULL) {
121ca6d9185SJeenu Viswambharan 		ret = selected->err_record->probe(selected->err_record, &probe_data);
122ca6d9185SJeenu Viswambharan 		assert(ret != 0);
1234576f73cSSughosh Ganu 	}
124ca6d9185SJeenu Viswambharan 
125ca6d9185SJeenu Viswambharan 	/* Call error handler for the record group */
126ca6d9185SJeenu Viswambharan 	assert(selected->err_record->handler != NULL);
12730a8d96eSJeenu Viswambharan 	(void) selected->err_record->handler(selected->err_record, probe_data,
128ca6d9185SJeenu Viswambharan 			&err_data);
129ca6d9185SJeenu Viswambharan 
130ca6d9185SJeenu Viswambharan 	return 0;
131ca6d9185SJeenu Viswambharan }
132ca6d9185SJeenu Viswambharan 
13387c85134SDaniel Boulby void __init ras_init(void)
134ca6d9185SJeenu Viswambharan {
135ca6d9185SJeenu Viswambharan #if ENABLE_ASSERTIONS
136ca6d9185SJeenu Viswambharan 	/* Check RAS interrupts are sorted */
137ca6d9185SJeenu Viswambharan 	assert_interrupts_sorted();
138ca6d9185SJeenu Viswambharan #endif
139ca6d9185SJeenu Viswambharan 
140ca6d9185SJeenu Viswambharan 	/* Register RAS priority handler */
141ca6d9185SJeenu Viswambharan 	ehf_register_priority_handler(PLAT_RAS_PRI, ras_interrupt_handler);
142ca6d9185SJeenu Viswambharan }
143