ras_common.c 3.2 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
13
/*
 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
 *
 * SPDX-License-Identifier: BSD-3-Clause
 */

#include <arch_helpers.h>
#include <debug.h>
#include <ea_handle.h>
#include <ehf.h>
#include <platform.h>
#include <ras.h>
#include <ras_arch.h>
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
14
#include <stdbool.h>
15

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

20
21
22
23
/* 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
24
25
	unsigned int i, n_handled = 0;
	int probe_data, ret;
26
27
28
29
30
	struct err_record_info *info;

	const struct err_handler_data err_data = {
		.version = ERR_HANDLER_VERSION,
		.ea_reason = ea_reason,
31
		.interrupt = 0,
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
32
		.syndrome = (uint32_t) syndrome,
33
34
35
36
37
38
39
40
41
42
		.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
43
		while (true) {
44
45
46
47
48
49
50
51
52
53
54
55
			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
56
	return (n_handled != 0U) ? 1 : 0;
57
}
58
59
60
61
62

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

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

	last = start[0].intr_number;
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
69
	for (i = 1; i < ras_interrupt_mappings.num_intrs; i++) {
70
71
72
73
74
75
76
77
78
79
80
81
82
		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
83
	struct ras_interrupt *ras_inrs = ras_interrupt_mappings.intrs;
84
85
86
87
88
89
90
91
92
93
94
	struct ras_interrupt *selected = NULL;
	int start, end, mid, probe_data, ret __unused;

	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
95
	assert(ras_interrupt_mappings.num_intrs > 0UL);
96
97

	start = 0;
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
98
	end = (int) ras_interrupt_mappings.num_intrs;
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
	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
118
	if (selected->err_record->probe != NULL) {
119
120
121
		ret = selected->err_record->probe(selected->err_record, &probe_data);
		assert(ret != 0);
	}
122
123
124

	/* Call error handler for the record group */
	assert(selected->err_record->handler != NULL);
Jeenu Viswambharan's avatar
Jeenu Viswambharan committed
125
	(void) selected->err_record->handler(selected->err_record, probe_data,
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
			&err_data);

	return 0;
}

void ras_init(void)
{
#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);
}