blob: f39e5f5f1b28b21cc7e2a93ebaf2a6539b549bc5 [file] [log] [blame]
Jeenu Viswambharan2e2e8812017-12-08 15:38:21 +00001/*
2 * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
3 *
4 * SPDX-License-Identifier: BSD-3-Clause
5 */
6
7#include <arch_helpers.h>
8#include <debug.h>
9#include <ea_handle.h>
10#include <ehf.h>
11#include <platform.h>
12#include <ras.h>
13#include <ras_arch.h>
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010014#include <stdbool.h>
Jeenu Viswambharan2e2e8812017-12-08 15:38:21 +000015
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +000016#ifndef PLAT_RAS_PRI
17# error Platform must define RAS priority value
18#endif
19
Jeenu Viswambharan2e2e8812017-12-08 15:38:21 +000020/* Handler that receives External Aborts on RAS-capable systems */
21int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
22 void *handle, uint64_t flags)
23{
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010024 unsigned int i, n_handled = 0;
25 int probe_data, ret;
Jeenu Viswambharan2e2e8812017-12-08 15:38:21 +000026 struct err_record_info *info;
27
28 const struct err_handler_data err_data = {
29 .version = ERR_HANDLER_VERSION,
30 .ea_reason = ea_reason,
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +000031 .interrupt = 0,
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010032 .syndrome = (uint32_t) syndrome,
Jeenu Viswambharan2e2e8812017-12-08 15:38:21 +000033 .flags = flags,
34 .cookie = cookie,
35 .handle = handle
36 };
37
38 for_each_err_record_info(i, info) {
39 assert(info->probe != NULL);
40 assert(info->handler != NULL);
41
42 /* Continue probing until the record group signals no error */
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010043 while (true) {
Jeenu Viswambharan2e2e8812017-12-08 15:38:21 +000044 if (info->probe(info, &probe_data) == 0)
45 break;
46
47 /* Handle error */
48 ret = info->handler(info, probe_data, &err_data);
49 if (ret != 0)
50 return ret;
51
52 n_handled++;
53 }
54 }
55
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010056 return (n_handled != 0U) ? 1 : 0;
Jeenu Viswambharan2e2e8812017-12-08 15:38:21 +000057}
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +000058
59#if ENABLE_ASSERTIONS
60static void assert_interrupts_sorted(void)
61{
62 unsigned int i, last;
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010063 struct ras_interrupt *start = ras_interrupt_mappings.intrs;
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +000064
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010065 if (ras_interrupt_mappings.num_intrs == 0UL)
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +000066 return;
67
68 last = start[0].intr_number;
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010069 for (i = 1; i < ras_interrupt_mappings.num_intrs; i++) {
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +000070 assert(start[i].intr_number > last);
71 last = start[i].intr_number;
72 }
73}
74#endif
75
76/*
77 * Given an RAS interrupt number, locate the registered handler and call it. If
78 * no handler was found for the interrupt number, this function panics.
79 */
80static int ras_interrupt_handler(uint32_t intr_raw, uint32_t flags,
81 void *handle, void *cookie)
82{
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010083 struct ras_interrupt *ras_inrs = ras_interrupt_mappings.intrs;
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +000084 struct ras_interrupt *selected = NULL;
85 int start, end, mid, probe_data, ret __unused;
86
87 const struct err_handler_data err_data = {
88 .version = ERR_HANDLER_VERSION,
89 .interrupt = intr_raw,
90 .flags = flags,
91 .cookie = cookie,
92 .handle = handle
93 };
94
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010095 assert(ras_interrupt_mappings.num_intrs > 0UL);
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +000096
97 start = 0;
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +010098 end = (int) ras_interrupt_mappings.num_intrs;
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +000099 while (start <= end) {
100 mid = ((end + start) / 2);
101 if (intr_raw == ras_inrs[mid].intr_number) {
102 selected = &ras_inrs[mid];
103 break;
104 } else if (intr_raw < ras_inrs[mid].intr_number) {
105 /* Move left */
106 end = mid - 1;
107 } else {
108 /* Move right */
109 start = mid + 1;
110 }
111 }
112
113 if (selected == NULL) {
114 ERROR("RAS interrupt %u has no handler!\n", intr_raw);
115 panic();
116 }
117
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +0100118 if (selected->err_record->probe != NULL) {
Sughosh Ganud51f80f2018-05-12 11:02:31 +0530119 ret = selected->err_record->probe(selected->err_record, &probe_data);
120 assert(ret != 0);
121 }
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +0000122
123 /* Call error handler for the record group */
124 assert(selected->err_record->handler != NULL);
Jeenu Viswambharan31ac01e2018-08-02 10:14:12 +0100125 (void) selected->err_record->handler(selected->err_record, probe_data,
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +0000126 &err_data);
127
128 return 0;
129}
130
Daniel Boulby5753e492018-09-20 14:12:46 +0100131void __init ras_init(void)
Jeenu Viswambharand86cc5b2017-12-12 10:34:58 +0000132{
133#if ENABLE_ASSERTIONS
134 /* Check RAS interrupts are sorted */
135 assert_interrupts_sorted();
136#endif
137
138 /* Register RAS priority handler */
139 ehf_register_priority_handler(PLAT_RAS_PRI, ras_interrupt_handler);
140}