| /* |
| * Copyright (c) 2018, Arm Limited and Contributors. All rights reserved. |
| * Copyright (c) 2020, NVIDIA Corporation. All rights reserved. |
| * |
| * SPDX-License-Identifier: BSD-3-Clause |
| */ |
| |
| #ifndef RAS_H |
| #define RAS_H |
| |
| #define ERR_HANDLER_VERSION 1U |
| |
| /* Error record access mechanism */ |
| #define ERR_ACCESS_SYSREG 0 |
| #define ERR_ACCESS_MEMMAP 1 |
| |
| /* |
| * Register all error records on the platform. |
| * |
| * This macro must be used in the same file as the array of error record info |
| * are declared. Only then would ARRAY_SIZE() yield a meaningful value. |
| */ |
| #define REGISTER_ERR_RECORD_INFO(_records) \ |
| const struct err_record_mapping err_record_mappings = { \ |
| .err_records = (_records), \ |
| .num_err_records = ARRAY_SIZE(_records), \ |
| } |
| |
| /* Error record info iterator */ |
| #define for_each_err_record_info(_i, _info) \ |
| for ((_i) = 0, (_info) = err_record_mappings.err_records; \ |
| (_i) < err_record_mappings.num_err_records; \ |
| (_i)++, (_info)++) |
| |
| #define ERR_RECORD_COMMON_(_probe, _handler, _aux) \ |
| .probe = _probe, \ |
| .handler = _handler, \ |
| .aux_data = _aux, |
| |
| #define ERR_RECORD_SYSREG_V1(_idx_start, _num_idx, _probe, _handler, _aux) \ |
| { \ |
| .version = 1, \ |
| .sysreg.idx_start = _idx_start, \ |
| .sysreg.num_idx = _num_idx, \ |
| .access = ERR_ACCESS_SYSREG, \ |
| ERR_RECORD_COMMON_(_probe, _handler, _aux) \ |
| } |
| |
| #define ERR_RECORD_MEMMAP_V1(_base_addr, _size_num_k, _probe, _handler, _aux) \ |
| { \ |
| .version = 1, \ |
| .memmap.base_addr = _base_addr, \ |
| .memmap.size_num_k = _size_num_k, \ |
| .access = ERR_ACCESS_MEMMAP, \ |
| ERR_RECORD_COMMON_(_probe, _handler, _aux) \ |
| } |
| |
| /* |
| * Macro to be used to name and declare an array of RAS interrupts along with |
| * their handlers. |
| * |
| * This macro must be used in the same file as the array of interrupts are |
| * declared. Only then would ARRAY_SIZE() yield a meaningful value. Also, the |
| * array is expected to be sorted in the increasing order of interrupt number. |
| */ |
| #define REGISTER_RAS_INTERRUPTS(_array) \ |
| const struct ras_interrupt_mapping ras_interrupt_mappings = { \ |
| .intrs = (_array), \ |
| .num_intrs = ARRAY_SIZE(_array), \ |
| } |
| |
| #ifndef __ASSEMBLER__ |
| |
| #include <assert.h> |
| |
| #include <lib/extensions/ras_arch.h> |
| |
| struct err_record_info; |
| |
| struct ras_interrupt { |
| /* Interrupt number, and the associated error record info */ |
| unsigned int intr_number; |
| struct err_record_info *err_record; |
| void *cookie; |
| }; |
| |
| /* Function to probe a error record group for error */ |
| typedef int (*err_record_probe_t)(const struct err_record_info *info, |
| int *probe_data); |
| |
| /* Data passed to error record group handler */ |
| struct err_handler_data { |
| /* Info passed on from top-level exception handler */ |
| uint64_t flags; |
| void *cookie; |
| void *handle; |
| |
| /* Data structure version */ |
| unsigned int version; |
| |
| /* Reason for EA: one the ERROR_* constants */ |
| unsigned int ea_reason; |
| |
| /* |
| * For EAs received at vector, the value read from ESR; for an EA |
| * synchronized by ESB, the value of DISR. |
| */ |
| uint32_t syndrome; |
| |
| /* For errors signalled via interrupt, the raw interrupt ID; otherwise, 0. */ |
| unsigned int interrupt; |
| }; |
| |
| /* Function to handle error from an error record group */ |
| typedef int (*err_record_handler_t)(const struct err_record_info *info, |
| int probe_data, const struct err_handler_data *const data); |
| |
| /* Error record information */ |
| struct err_record_info { |
| /* Function to probe error record group for errors */ |
| err_record_probe_t probe; |
| |
| /* Function to handle error record group errors */ |
| err_record_handler_t handler; |
| |
| /* Opaque group-specific data */ |
| void *aux_data; |
| |
| /* Additional information for Standard Error Records */ |
| union { |
| struct { |
| /* |
| * For a group accessed via memory-mapped register, |
| * base address of the page hosting error records, and |
| * the size of the record group. |
| */ |
| uintptr_t base_addr; |
| |
| /* Size of group in number of KBs */ |
| unsigned int size_num_k; |
| } memmap; |
| |
| struct { |
| /* |
| * For error records accessed via system register, index of |
| * the error record. |
| */ |
| unsigned int idx_start; |
| unsigned int num_idx; |
| } sysreg; |
| }; |
| |
| /* Data structure version */ |
| unsigned int version; |
| |
| /* Error record access mechanism */ |
| unsigned int access:1; |
| }; |
| |
| struct err_record_mapping { |
| struct err_record_info *err_records; |
| size_t num_err_records; |
| }; |
| |
| struct ras_interrupt_mapping { |
| struct ras_interrupt *intrs; |
| size_t num_intrs; |
| }; |
| |
| extern const struct err_record_mapping err_record_mappings; |
| extern const struct ras_interrupt_mapping ras_interrupt_mappings; |
| |
| |
| /* |
| * Helper functions to probe memory-mapped and system registers implemented in |
| * Standard Error Record format |
| */ |
| static inline int ras_err_ser_probe_memmap(const struct err_record_info *info, |
| int *probe_data) |
| { |
| assert(info->version == ERR_HANDLER_VERSION); |
| |
| return ser_probe_memmap(info->memmap.base_addr, info->memmap.size_num_k, |
| probe_data); |
| } |
| |
| static inline int ras_err_ser_probe_sysreg(const struct err_record_info *info, |
| int *probe_data) |
| { |
| assert(info->version == ERR_HANDLER_VERSION); |
| |
| return ser_probe_sysreg(info->sysreg.idx_start, info->sysreg.num_idx, |
| probe_data); |
| } |
| |
| const char *ras_serr_to_str(unsigned int serr); |
| int ras_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie, |
| void *handle, uint64_t flags); |
| void ras_init(void); |
| |
| #endif /* __ASSEMBLER__ */ |
| |
| #endif /* RAS_H */ |