GK SDK 源码库: XMIPCLinuxV100R005C00SPC030 (kernel/tools/open_source excluded)
This commit is contained in:
@@ -0,0 +1,184 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2021, ARM Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2020, NVIDIA Corporation. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <stdbool.h>
|
||||
|
||||
#include <arch_helpers.h>
|
||||
#include <bl31/ea_handle.h>
|
||||
#include <bl31/ehf.h>
|
||||
#include <common/debug.h>
|
||||
#include <lib/extensions/ras.h>
|
||||
#include <lib/extensions/ras_arch.h>
|
||||
#include <plat/common/platform.h>
|
||||
|
||||
#ifndef PLAT_RAS_PRI
|
||||
# error Platform must define RAS priority value
|
||||
#endif
|
||||
|
||||
/*
|
||||
* Function to convert architecturally-defined primary error code SERR,
|
||||
* bits[7:0] from ERR<n>STATUS to its corresponding error string.
|
||||
*/
|
||||
const char *ras_serr_to_str(unsigned int serr)
|
||||
{
|
||||
const char *str[ERROR_STATUS_NUM_SERR] = {
|
||||
"No error",
|
||||
"IMPLEMENTATION DEFINED error",
|
||||
"Data value from (non-associative) internal memory",
|
||||
"IMPLEMENTATION DEFINED pin",
|
||||
"Assertion failure",
|
||||
"Error detected on internal data path",
|
||||
"Data value from associative memory",
|
||||
"Address/control value from associative memory",
|
||||
"Data value from a TLB",
|
||||
"Address/control value from a TLB",
|
||||
"Data value from producer",
|
||||
"Address/control value from producer",
|
||||
"Data value from (non-associative) external memory",
|
||||
"Illegal address (software fault)",
|
||||
"Illegal access (software fault)",
|
||||
"Illegal state (software fault)",
|
||||
"Internal data register",
|
||||
"Internal control register",
|
||||
"Error response from slave",
|
||||
"External timeout",
|
||||
"Internal timeout",
|
||||
"Deferred error from slave not supported at master"
|
||||
};
|
||||
|
||||
/*
|
||||
* All other values are reserved. Reserved values might be defined
|
||||
* in a future version of the architecture
|
||||
*/
|
||||
if (serr >= ERROR_STATUS_NUM_SERR)
|
||||
return "unknown SERR";
|
||||
|
||||
return str[serr];
|
||||
}
|
||||
|
||||
/* 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)
|
||||
{
|
||||
unsigned int i, n_handled = 0;
|
||||
int probe_data, ret;
|
||||
struct err_record_info *info;
|
||||
|
||||
const struct err_handler_data err_data = {
|
||||
.version = ERR_HANDLER_VERSION,
|
||||
.ea_reason = ea_reason,
|
||||
.interrupt = 0,
|
||||
.syndrome = (uint32_t) syndrome,
|
||||
.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 */
|
||||
while (true) {
|
||||
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++;
|
||||
}
|
||||
}
|
||||
|
||||
return (n_handled != 0U) ? 1 : 0;
|
||||
}
|
||||
|
||||
#if ENABLE_ASSERTIONS
|
||||
static void assert_interrupts_sorted(void)
|
||||
{
|
||||
unsigned int i, last;
|
||||
struct ras_interrupt *start = ras_interrupt_mappings.intrs;
|
||||
|
||||
if (ras_interrupt_mappings.num_intrs == 0UL)
|
||||
return;
|
||||
|
||||
last = start[0].intr_number;
|
||||
for (i = 1; i < ras_interrupt_mappings.num_intrs; i++) {
|
||||
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)
|
||||
{
|
||||
struct ras_interrupt *ras_inrs = ras_interrupt_mappings.intrs;
|
||||
struct ras_interrupt *selected = NULL;
|
||||
int probe_data = 0;
|
||||
int start, end, mid, ret __unused;
|
||||
|
||||
const struct err_handler_data err_data = {
|
||||
.version = ERR_HANDLER_VERSION,
|
||||
.interrupt = intr_raw,
|
||||
.flags = flags,
|
||||
.cookie = cookie,
|
||||
.handle = handle
|
||||
};
|
||||
|
||||
assert(ras_interrupt_mappings.num_intrs > 0UL);
|
||||
|
||||
start = 0;
|
||||
end = (int)ras_interrupt_mappings.num_intrs - 1;
|
||||
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();
|
||||
}
|
||||
|
||||
if (selected->err_record->probe != NULL) {
|
||||
ret = selected->err_record->probe(selected->err_record, &probe_data);
|
||||
assert(ret != 0);
|
||||
}
|
||||
|
||||
/* Call error handler for the record group */
|
||||
assert(selected->err_record->handler != NULL);
|
||||
(void) selected->err_record->handler(selected->err_record, probe_data,
|
||||
&err_data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void __init 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);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright (c) 2018, ARM Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
||||
#include <lib/extensions/ras_arch.h>
|
||||
#include <lib/utils_def.h>
|
||||
|
||||
/*
|
||||
* Probe for error in memory-mapped registers containing error records
|
||||
* implemented Standard Error Record format. Upon detecting an error, set probe
|
||||
* data to the index of the record in error, and return 1; otherwise, return 0.
|
||||
*/
|
||||
int ser_probe_memmap(uintptr_t base, unsigned int size_num_k, int *probe_data)
|
||||
{
|
||||
unsigned int num_records, num_group_regs, i;
|
||||
uint64_t gsr;
|
||||
|
||||
assert(base != 0UL);
|
||||
|
||||
/* Only 4K supported for now */
|
||||
assert(size_num_k == STD_ERR_NODE_SIZE_NUM_K);
|
||||
|
||||
num_records = (unsigned int)
|
||||
(mmio_read_32(ERR_DEVID(base, size_num_k)) & ERR_DEVID_MASK);
|
||||
|
||||
/* A group register shows error status for 2^6 error records */
|
||||
num_group_regs = (num_records >> 6U) + 1U;
|
||||
|
||||
/* Iterate through group registers to find a record in error */
|
||||
for (i = 0; i < num_group_regs; i++) {
|
||||
gsr = mmio_read_64(ERR_GSR(base, size_num_k, i));
|
||||
if (gsr == 0ULL)
|
||||
continue;
|
||||
|
||||
/* Return the index of the record in error */
|
||||
if (probe_data != NULL)
|
||||
*probe_data = (((int) (i << 6U)) + __builtin_ctzll(gsr));
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Probe for error in System Registers where error records are implemented in
|
||||
* Standard Error Record format. Upon detecting an error, set probe data to the
|
||||
* index of the record in error, and return 1; otherwise, return 0.
|
||||
*/
|
||||
int ser_probe_sysreg(unsigned int idx_start, unsigned int num_idx, int *probe_data)
|
||||
{
|
||||
unsigned int i;
|
||||
uint64_t status;
|
||||
unsigned int max_idx __unused =
|
||||
((unsigned int) read_erridr_el1()) & ERRIDR_MASK;
|
||||
|
||||
assert(idx_start < max_idx);
|
||||
assert(check_u32_overflow(idx_start, num_idx) == 0);
|
||||
assert((idx_start + num_idx - 1U) < max_idx);
|
||||
|
||||
for (i = 0; i < num_idx; i++) {
|
||||
/* Select the error record */
|
||||
ser_sys_select_record(idx_start + i);
|
||||
|
||||
/* Retrieve status register from the error record */
|
||||
status = read_erxstatus_el1();
|
||||
|
||||
/* Check for valid field in status */
|
||||
if (ERR_STATUS_GET_FIELD(status, V) != 0U) {
|
||||
if (probe_data != NULL)
|
||||
*probe_data = (int) i;
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
Reference in New Issue
Block a user