ras_common.c 3.28 KB
Newer Older
1
/*
2
 * Copyright (c) 2018-2019, ARM Limited and Contributors. All rights reserved.
3
4
5
6
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
7
#include <stdbool.h>
8

9
10
11
12
13
14
15
16
#include <arch_helpers.h>
#include <bl31/ea_handle.h>
#include <bl31/ehf.h>
#include <common/debug.h>
#include <lib/extensions/ras.h>
#include <lib/extensions/ras_arch.h>
#include <plat/common/platform.h>

17
18
19
20
#ifndef PLAT_RAS_PRI
# error Platform must define RAS priority value
#endif

21
22
23
24
/* Handler that receives External Aborts on RAS-capable systems */
int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
		void *handle, uint64_t flags)
{
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
25
26
	unsigned int i, n_handled = 0;
	int probe_data, ret;
27
28
29
30
31
	struct err_record_info *info;

	const struct err_handler_data err_data = {
		.version = ERR_HANDLER_VERSION,
		.ea_reason = ea_reason,
32
		.interrupt = 0,
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
33
		.syndrome = (uint32_t) syndrome,
34
35
36
37
38
39
40
41
42
43
		.flags = flags,
		.cookie = cookie,
		.handle = handle
	};

	for_each_err_record_info(i, info) {
		assert(info->probe != NULL);
		assert(info->handler != NULL);

		/* Continue probing until the record group signals no error */
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
44
		while (true) {
45
46
47
48
49
50
51
52
53
54
55
56
			if (info->probe(info, &probe_data) == 0)
				break;

			/* Handle error */
			ret = info->handler(info, probe_data, &err_data);
			if (ret != 0)
				return ret;

			n_handled++;
		}
	}

Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
57
	return (n_handled != 0U) ? 1 : 0;
58
}
59
60
61
62
63

#if ENABLE_ASSERTIONS
static void assert_interrupts_sorted(void)
{
	unsigned int i, last;
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
64
	struct ras_interrupt *start = ras_interrupt_mappings.intrs;
65

Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
66
	if (ras_interrupt_mappings.num_intrs == 0UL)
67
68
69
		return;

	last = start[0].intr_number;
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
70
	for (i = 1; i < ras_interrupt_mappings.num_intrs; i++) {
71
72
73
74
75
76
77
78
79
80
81
82
83
		assert(start[i].intr_number > last);
		last = start[i].intr_number;
	}
}
#endif

/*
 * Given an RAS interrupt number, locate the registered handler and call it. If
 * no handler was found for the interrupt number, this function panics.
 */
static int ras_interrupt_handler(uint32_t intr_raw, uint32_t flags,
		void *handle, void *cookie)
{
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
84
	struct ras_interrupt *ras_inrs = ras_interrupt_mappings.intrs;
85
	struct ras_interrupt *selected = NULL;
86
87
	int probe_data = 0;
	int start, end, mid, ret __unused;
88
89
90
91
92
93
94
95
96

	const struct err_handler_data err_data = {
		.version = ERR_HANDLER_VERSION,
		.interrupt = intr_raw,
		.flags = flags,
		.cookie = cookie,
		.handle = handle
	};

Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
97
	assert(ras_interrupt_mappings.num_intrs > 0UL);
98
99

	start = 0;
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
100
	end = (int) ras_interrupt_mappings.num_intrs;
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
	while (start <= end) {
		mid = ((end + start) / 2);
		if (intr_raw == ras_inrs[mid].intr_number) {
			selected = &ras_inrs[mid];
			break;
		} else if (intr_raw < ras_inrs[mid].intr_number) {
			/* Move left */
			end = mid - 1;
		} else {
			/* Move right */
			start = mid + 1;
		}
	}

	if (selected == NULL) {
		ERROR("RAS interrupt %u has no handler!\n", intr_raw);
		panic();
	}

Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
120
	if (selected->err_record->probe != NULL) {
121
122
123
		ret = selected->err_record->probe(selected->err_record, &probe_data);
		assert(ret != 0);
	}
124
125
126

	/* Call error handler for the record group */
	assert(selected->err_record->handler != NULL);
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
127
	(void) selected->err_record->handler(selected->err_record, probe_data,
128
129
130
131
132
			&err_data);

	return 0;
}

133
void __init ras_init(void)
134
135
136
137
138
139
140
141
142
{
#if ENABLE_ASSERTIONS
	/* Check RAS interrupts are sorted */
	assert_interrupts_sorted();
#endif

	/* Register RAS priority handler */
	ehf_register_priority_handler(PLAT_RAS_PRI, ras_interrupt_handler);
}