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