1362599ecSJeenu Viswambharan /* 2362599ecSJeenu Viswambharan * Copyright (c) 2018, ARM Limited and Contributors. All rights reserved. 3362599ecSJeenu Viswambharan * 4362599ecSJeenu Viswambharan * SPDX-License-Identifier: BSD-3-Clause 5362599ecSJeenu Viswambharan */ 6362599ecSJeenu Viswambharan 7362599ecSJeenu Viswambharan #include <arch_helpers.h> 8362599ecSJeenu Viswambharan #include <debug.h> 9362599ecSJeenu Viswambharan #include <ea_handle.h> 10362599ecSJeenu Viswambharan #include <ehf.h> 11362599ecSJeenu Viswambharan #include <platform.h> 12362599ecSJeenu Viswambharan #include <ras.h> 13362599ecSJeenu Viswambharan #include <ras_arch.h> 14362599ecSJeenu Viswambharan 15*ca6d9185SJeenu Viswambharan #ifndef PLAT_RAS_PRI 16*ca6d9185SJeenu Viswambharan # error Platform must define RAS priority value 17*ca6d9185SJeenu Viswambharan #endif 18*ca6d9185SJeenu Viswambharan 19362599ecSJeenu Viswambharan /* Handler that receives External Aborts on RAS-capable systems */ 20362599ecSJeenu Viswambharan int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, 21362599ecSJeenu Viswambharan void *handle, uint64_t flags) 22362599ecSJeenu Viswambharan { 23362599ecSJeenu Viswambharan unsigned int i, n_handled = 0, ret; 24362599ecSJeenu Viswambharan int probe_data; 25362599ecSJeenu Viswambharan struct err_record_info *info; 26362599ecSJeenu Viswambharan 27362599ecSJeenu Viswambharan const struct err_handler_data err_data = { 28362599ecSJeenu Viswambharan .version = ERR_HANDLER_VERSION, 29362599ecSJeenu Viswambharan .ea_reason = ea_reason, 30*ca6d9185SJeenu Viswambharan .interrupt = 0, 31362599ecSJeenu Viswambharan .syndrome = syndrome, 32362599ecSJeenu Viswambharan .flags = flags, 33362599ecSJeenu Viswambharan .cookie = cookie, 34362599ecSJeenu Viswambharan .handle = handle 35362599ecSJeenu Viswambharan }; 36362599ecSJeenu Viswambharan 37362599ecSJeenu Viswambharan for_each_err_record_info(i, info) { 38362599ecSJeenu Viswambharan assert(info->probe != NULL); 39362599ecSJeenu Viswambharan assert(info->handler != NULL); 40362599ecSJeenu Viswambharan 41362599ecSJeenu Viswambharan /* Continue probing until the record group signals no error */ 42362599ecSJeenu Viswambharan while (1) { 43362599ecSJeenu Viswambharan if (info->probe(info, &probe_data) == 0) 44362599ecSJeenu Viswambharan break; 45362599ecSJeenu Viswambharan 46362599ecSJeenu Viswambharan /* Handle error */ 47362599ecSJeenu Viswambharan ret = info->handler(info, probe_data, &err_data); 48362599ecSJeenu Viswambharan if (ret != 0) 49362599ecSJeenu Viswambharan return ret; 50362599ecSJeenu Viswambharan 51362599ecSJeenu Viswambharan n_handled++; 52362599ecSJeenu Viswambharan } 53362599ecSJeenu Viswambharan } 54362599ecSJeenu Viswambharan 55362599ecSJeenu Viswambharan return (n_handled != 0); 56362599ecSJeenu Viswambharan } 57*ca6d9185SJeenu Viswambharan 58*ca6d9185SJeenu Viswambharan #if ENABLE_ASSERTIONS 59*ca6d9185SJeenu Viswambharan static void assert_interrupts_sorted(void) 60*ca6d9185SJeenu Viswambharan { 61*ca6d9185SJeenu Viswambharan unsigned int i, last; 62*ca6d9185SJeenu Viswambharan struct ras_interrupt *start = ras_interrupt_mapping.intrs; 63*ca6d9185SJeenu Viswambharan 64*ca6d9185SJeenu Viswambharan if (ras_interrupt_mapping.num_intrs == 0) 65*ca6d9185SJeenu Viswambharan return; 66*ca6d9185SJeenu Viswambharan 67*ca6d9185SJeenu Viswambharan last = start[0].intr_number; 68*ca6d9185SJeenu Viswambharan for (i = 1; i < ras_interrupt_mapping.num_intrs; i++) { 69*ca6d9185SJeenu Viswambharan assert(start[i].intr_number > last); 70*ca6d9185SJeenu Viswambharan last = start[i].intr_number; 71*ca6d9185SJeenu Viswambharan } 72*ca6d9185SJeenu Viswambharan } 73*ca6d9185SJeenu Viswambharan #endif 74*ca6d9185SJeenu Viswambharan 75*ca6d9185SJeenu Viswambharan /* 76*ca6d9185SJeenu Viswambharan * Given an RAS interrupt number, locate the registered handler and call it. If 77*ca6d9185SJeenu Viswambharan * no handler was found for the interrupt number, this function panics. 78*ca6d9185SJeenu Viswambharan */ 79*ca6d9185SJeenu Viswambharan static int ras_interrupt_handler(uint32_t intr_raw, uint32_t flags, 80*ca6d9185SJeenu Viswambharan void *handle, void *cookie) 81*ca6d9185SJeenu Viswambharan { 82*ca6d9185SJeenu Viswambharan struct ras_interrupt *ras_inrs = ras_interrupt_mapping.intrs; 83*ca6d9185SJeenu Viswambharan struct ras_interrupt *selected = NULL; 84*ca6d9185SJeenu Viswambharan int start, end, mid, probe_data, ret __unused; 85*ca6d9185SJeenu Viswambharan 86*ca6d9185SJeenu Viswambharan const struct err_handler_data err_data = { 87*ca6d9185SJeenu Viswambharan .version = ERR_HANDLER_VERSION, 88*ca6d9185SJeenu Viswambharan .interrupt = intr_raw, 89*ca6d9185SJeenu Viswambharan .flags = flags, 90*ca6d9185SJeenu Viswambharan .cookie = cookie, 91*ca6d9185SJeenu Viswambharan .handle = handle 92*ca6d9185SJeenu Viswambharan }; 93*ca6d9185SJeenu Viswambharan 94*ca6d9185SJeenu Viswambharan assert(ras_interrupt_mapping.num_intrs > 0); 95*ca6d9185SJeenu Viswambharan 96*ca6d9185SJeenu Viswambharan start = 0; 97*ca6d9185SJeenu Viswambharan end = ras_interrupt_mapping.num_intrs; 98*ca6d9185SJeenu Viswambharan while (start <= end) { 99*ca6d9185SJeenu Viswambharan mid = ((end + start) / 2); 100*ca6d9185SJeenu Viswambharan if (intr_raw == ras_inrs[mid].intr_number) { 101*ca6d9185SJeenu Viswambharan selected = &ras_inrs[mid]; 102*ca6d9185SJeenu Viswambharan break; 103*ca6d9185SJeenu Viswambharan } else if (intr_raw < ras_inrs[mid].intr_number) { 104*ca6d9185SJeenu Viswambharan /* Move left */ 105*ca6d9185SJeenu Viswambharan end = mid - 1; 106*ca6d9185SJeenu Viswambharan } else { 107*ca6d9185SJeenu Viswambharan /* Move right */ 108*ca6d9185SJeenu Viswambharan start = mid + 1; 109*ca6d9185SJeenu Viswambharan } 110*ca6d9185SJeenu Viswambharan } 111*ca6d9185SJeenu Viswambharan 112*ca6d9185SJeenu Viswambharan if (selected == NULL) { 113*ca6d9185SJeenu Viswambharan ERROR("RAS interrupt %u has no handler!\n", intr_raw); 114*ca6d9185SJeenu Viswambharan panic(); 115*ca6d9185SJeenu Viswambharan } 116*ca6d9185SJeenu Viswambharan 117*ca6d9185SJeenu Viswambharan 118*ca6d9185SJeenu Viswambharan ret = selected->err_record->probe(selected->err_record, &probe_data); 119*ca6d9185SJeenu Viswambharan assert(ret != 0); 120*ca6d9185SJeenu Viswambharan 121*ca6d9185SJeenu Viswambharan /* Call error handler for the record group */ 122*ca6d9185SJeenu Viswambharan assert(selected->err_record->handler != NULL); 123*ca6d9185SJeenu Viswambharan selected->err_record->handler(selected->err_record, probe_data, 124*ca6d9185SJeenu Viswambharan &err_data); 125*ca6d9185SJeenu Viswambharan 126*ca6d9185SJeenu Viswambharan return 0; 127*ca6d9185SJeenu Viswambharan } 128*ca6d9185SJeenu Viswambharan 129*ca6d9185SJeenu Viswambharan void ras_init(void) 130*ca6d9185SJeenu Viswambharan { 131*ca6d9185SJeenu Viswambharan #if ENABLE_ASSERTIONS 132*ca6d9185SJeenu Viswambharan /* Check RAS interrupts are sorted */ 133*ca6d9185SJeenu Viswambharan assert_interrupts_sorted(); 134*ca6d9185SJeenu Viswambharan #endif 135*ca6d9185SJeenu Viswambharan 136*ca6d9185SJeenu Viswambharan /* Register RAS priority handler */ 137*ca6d9185SJeenu Viswambharan ehf_register_priority_handler(PLAT_RAS_PRI, ras_interrupt_handler); 138*ca6d9185SJeenu Viswambharan } 139