123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492 |
- /*
- * Copyright (c) 2020-2021, NVIDIA Corporation. All rights reserved.
- *
- * SPDX-License-Identifier: BSD-3-Clause
- */
- #include <inttypes.h>
- #include <stdbool.h>
- #include <stdint.h>
- #include <common/debug.h>
- #include <lib/bakery_lock.h>
- #include <lib/cassert.h>
- #include <lib/extensions/ras.h>
- #include <lib/utils_def.h>
- #include <services/sdei.h>
- #include <plat/common/platform.h>
- #include <platform_def.h>
- #include <tegra194_ras_private.h>
- #include <tegra_def.h>
- #include <tegra_platform.h>
- #include <tegra_private.h>
- /*
- * ERR<n>FR bits[63:32], it indicates supported RAS errors which can be enabled
- * by setting corresponding bits in ERR<n>CTLR
- */
- #define ERR_FR_EN_BITS_MASK 0xFFFFFFFF00000000ULL
- /*
- * Number of RAS errors will be cleared per 'tegra194_ras_corrected_err_clear'
- * function call.
- */
- #define RAS_ERRORS_PER_CALL 8
- /*
- * the max possible RAS node index value.
- */
- #define RAS_NODE_INDEX_MAX 0x1FFFFFFFU
- /* bakery lock for platform RAS handler. */
- static DEFINE_BAKERY_LOCK(ras_handler_lock);
- #define ras_lock() bakery_lock_get(&ras_handler_lock)
- #define ras_unlock() bakery_lock_release(&ras_handler_lock)
- /*
- * Function to handle an External Abort received at EL3.
- * This function is invoked by RAS framework.
- */
- static void tegra194_ea_handler(unsigned int ea_reason, uint64_t syndrome,
- void *cookie, void *handle, uint64_t flags)
- {
- int32_t ret;
- ras_lock();
- ERROR("MPIDR 0x%lx: exception reason=%u syndrome=0x%" PRIx64 "\n",
- read_mpidr(), ea_reason, syndrome);
- /* Call RAS EA handler */
- ret = ras_ea_handler(ea_reason, syndrome, cookie, handle, flags);
- if (ret != 0) {
- ERROR("RAS error handled!\n");
- ret = sdei_dispatch_event(TEGRA_SDEI_EP_EVENT_0 +
- plat_my_core_pos());
- if (ret != 0)
- ERROR("sdei_dispatch_event returned %d\n", ret);
- } else {
- ERROR("Not a RAS error!\n");
- }
- ras_unlock();
- }
- /*
- * Function to enable all supported RAS error report.
- *
- * Uncorrected errors are set to report as External abort (SError)
- * Corrected errors are set to report as interrupt.
- */
- void tegra194_ras_enable(void)
- {
- VERBOSE("%s\n", __func__);
- /* skip RAS enablement if not a silicon platform. */
- if (!tegra_platform_is_silicon()) {
- return;
- }
- /*
- * Iterate for each group(num_idx ERRSELRs starting from idx_start)
- * use normal for loop instead of for_each_err_record_info to get rid
- * of MISRA noise..
- */
- for (uint32_t i = 0U; i < err_record_mappings.num_err_records; i++) {
- const struct err_record_info *info = &err_record_mappings.err_records[i];
- uint32_t idx_start = info->sysreg.idx_start;
- uint32_t num_idx = info->sysreg.num_idx;
- const struct ras_aux_data *aux_data = (const struct ras_aux_data *)info->aux_data;
- assert(aux_data != NULL);
- for (uint32_t j = 0; j < num_idx; j++) {
- /* ERR<n>CTLR register value. */
- uint64_t err_ctrl = 0ULL;
- /* all supported errors for this node. */
- uint64_t err_fr;
- /* uncorrectable errors */
- uint64_t uncorr_errs;
- /* correctable errors */
- uint64_t corr_errs;
- /*
- * Catch error if something wrong with the RAS aux data
- * record table.
- */
- assert(aux_data[j].err_ctrl != NULL);
- /*
- * Write to ERRSELR_EL1 to select the RAS error node.
- * Always program this at first to select corresponding
- * RAS node before any other RAS register r/w.
- */
- ser_sys_select_record(idx_start + j);
- err_fr = read_erxfr_el1() & ERR_FR_EN_BITS_MASK;
- uncorr_errs = aux_data[j].err_ctrl();
- corr_errs = ~uncorr_errs & err_fr;
- /* enable error reporting */
- ERR_CTLR_ENABLE_FIELD(err_ctrl, ED);
- /* enable SError reporting for uncorrectable errors */
- if ((uncorr_errs & err_fr) != 0ULL) {
- ERR_CTLR_ENABLE_FIELD(err_ctrl, UE);
- }
- /* generate interrupt for corrected errors. */
- if (corr_errs != 0ULL) {
- ERR_CTLR_ENABLE_FIELD(err_ctrl, CFI);
- }
- /* enable the supported errors */
- err_ctrl |= err_fr;
- VERBOSE("errselr_el1:0x%x, erxfr:0x%" PRIx64 ", err_ctrl:0x%" PRIx64 "\n",
- idx_start + j, err_fr, err_ctrl);
- /* enable specified errors, or set to 0 if no supported error */
- write_erxctlr_el1(err_ctrl);
- }
- }
- }
- /*
- * Function to clear RAS ERR<n>STATUS for corrected RAS error.
- *
- * This function clears number of 'RAS_ERRORS_PER_CALL' RAS errors at most.
- * 'cookie' - in/out cookie parameter to specify/store last visited RAS
- * error record index. it is set to '0' to indicate no more RAS
- * error record to clear.
- */
- void tegra194_ras_corrected_err_clear(uint64_t *cookie)
- {
- /*
- * 'last_node' and 'last_idx' represent last visited RAS node index from
- * previous function call. they are set to 0 when first smc call is made
- * or all RAS error are visited by followed multipile smc calls.
- */
- union prev_record {
- struct record {
- uint32_t last_node;
- uint32_t last_idx;
- } rec;
- uint64_t value;
- } prev;
- uint64_t clear_ce_status = 0ULL;
- int32_t nerrs_per_call = RAS_ERRORS_PER_CALL;
- uint32_t i;
- if (cookie == NULL) {
- return;
- }
- prev.value = *cookie;
- if ((prev.rec.last_node >= RAS_NODE_INDEX_MAX) ||
- (prev.rec.last_idx >= RAS_NODE_INDEX_MAX)) {
- return;
- }
- ERR_STATUS_SET_FIELD(clear_ce_status, AV, 0x1UL);
- ERR_STATUS_SET_FIELD(clear_ce_status, V, 0x1UL);
- ERR_STATUS_SET_FIELD(clear_ce_status, OF, 0x1UL);
- ERR_STATUS_SET_FIELD(clear_ce_status, MV, 0x1UL);
- ERR_STATUS_SET_FIELD(clear_ce_status, CE, 0x3UL);
- for (i = prev.rec.last_node; i < err_record_mappings.num_err_records; i++) {
- const struct err_record_info *info = &err_record_mappings.err_records[i];
- uint32_t idx_start = info->sysreg.idx_start;
- uint32_t num_idx = info->sysreg.num_idx;
- uint32_t j;
- j = (i == prev.rec.last_node && prev.value != 0UL) ?
- (prev.rec.last_idx + 1U) : 0U;
- for (; j < num_idx; j++) {
- uint64_t status;
- uint32_t err_idx = idx_start + j;
- if (err_idx >= RAS_NODE_INDEX_MAX) {
- return;
- }
- write_errselr_el1(err_idx);
- status = read_erxstatus_el1();
- if (ERR_STATUS_GET_FIELD(status, CE) != 0U) {
- write_erxstatus_el1(clear_ce_status);
- }
- --nerrs_per_call;
- /* only clear 'nerrs_per_call' errors each time. */
- if (nerrs_per_call <= 0) {
- prev.rec.last_idx = j;
- prev.rec.last_node = i;
- /* save last visited error record index
- * into cookie.
- */
- *cookie = prev.value;
- return;
- }
- }
- }
- /*
- * finish if all ras error records are checked or provided index is out
- * of range.
- */
- *cookie = 0ULL;
- }
- /* Function to probe an error from error record group. */
- static int32_t tegra194_ras_record_probe(const struct err_record_info *info,
- int *probe_data)
- {
- /* Skip probing if not a silicon platform */
- if (!tegra_platform_is_silicon()) {
- return 0;
- }
- return ser_probe_sysreg(info->sysreg.idx_start, info->sysreg.num_idx, probe_data);
- }
- /* Function to handle error from one given node */
- static int32_t tegra194_ras_node_handler(uint32_t errselr, const char *name,
- const struct ras_error *errors, uint64_t status)
- {
- bool found = false;
- uint32_t ierr = (uint32_t)ERR_STATUS_GET_FIELD(status, IERR);
- uint32_t serr = (uint32_t)ERR_STATUS_GET_FIELD(status, SERR);
- uint64_t val = 0;
- /* not a valid error. */
- if (ERR_STATUS_GET_FIELD(status, V) == 0U) {
- return 0;
- }
- ERR_STATUS_SET_FIELD(val, V, 1);
- /* keep the log print same as linux arm64_ras driver. */
- ERROR("**************************************\n");
- ERROR("RAS Error in %s, ERRSELR_EL1=0x%x:\n", name, errselr);
- ERROR("\tStatus = 0x%" PRIx64 "\n", status);
- /* Print uncorrectable error information. */
- if (ERR_STATUS_GET_FIELD(status, UE) != 0U) {
- ERR_STATUS_SET_FIELD(val, UE, 1);
- ERR_STATUS_SET_FIELD(val, UET, 1);
- /* IERR to error message */
- for (uint32_t i = 0; errors[i].error_msg != NULL; i++) {
- if (ierr == errors[i].error_code) {
- ERROR("\tIERR = %s: 0x%x\n",
- errors[i].error_msg, ierr);
- found = true;
- break;
- }
- }
- if (!found) {
- ERROR("\tUnknown IERR: 0x%x\n", ierr);
- }
- ERROR("SERR = %s: 0x%x\n", ras_serr_to_str(serr), serr);
- /* Overflow, multiple errors have been detected. */
- if (ERR_STATUS_GET_FIELD(status, OF) != 0U) {
- ERROR("\tOverflow (there may be more errors) - "
- "Uncorrectable\n");
- ERR_STATUS_SET_FIELD(val, OF, 1);
- }
- ERROR("\tUncorrectable (this is fatal)\n");
- /* Miscellaneous Register Valid. */
- if (ERR_STATUS_GET_FIELD(status, MV) != 0U) {
- ERROR("\tMISC0 = 0x%lx\n", read_erxmisc0_el1());
- ERROR("\tMISC1 = 0x%lx\n", read_erxmisc1_el1());
- ERR_STATUS_SET_FIELD(val, MV, 1);
- }
- /* Address Valid. */
- if (ERR_STATUS_GET_FIELD(status, AV) != 0U) {
- ERROR("\tADDR = 0x%lx\n", read_erxaddr_el1());
- ERR_STATUS_SET_FIELD(val, AV, 1);
- }
- /* Deferred error */
- if (ERR_STATUS_GET_FIELD(status, DE) != 0U) {
- ERROR("\tDeferred error\n");
- ERR_STATUS_SET_FIELD(val, DE, 1);
- }
- } else {
- /* For corrected error, simply clear it. */
- VERBOSE("corrected RAS error is cleared: ERRSELR_EL1:0x%x, "
- "IERR:0x%x, SERR:0x%x\n", errselr, ierr, serr);
- ERR_STATUS_SET_FIELD(val, CE, 1);
- }
- ERROR("**************************************\n");
- /* Write to clear reported errors. */
- write_erxstatus_el1(val);
- /* error handled */
- return 0;
- }
- /* Function to handle one error node from an error record group. */
- static int32_t tegra194_ras_record_handler(const struct err_record_info *info,
- int probe_data, const struct err_handler_data *const data __unused)
- {
- uint32_t num_idx = info->sysreg.num_idx;
- uint32_t idx_start = info->sysreg.idx_start;
- const struct ras_aux_data *aux_data = info->aux_data;
- const struct ras_error *errors;
- uint32_t offset;
- const char *node_name;
- uint64_t status = 0ULL;
- VERBOSE("%s\n", __func__);
- assert(probe_data >= 0);
- assert((uint32_t)probe_data < num_idx);
- offset = (uint32_t)probe_data;
- errors = aux_data[offset].error_records;
- node_name = aux_data[offset].name;
- assert(errors != NULL);
- /* Write to ERRSELR_EL1 to select the error record */
- ser_sys_select_record(idx_start + offset);
- /* Retrieve status register from the error record */
- status = read_erxstatus_el1();
- return tegra194_ras_node_handler(idx_start + offset, node_name,
- errors, status);
- }
- /* Instantiate RAS nodes */
- PER_CORE_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
- PER_CLUSTER_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
- SCF_L3_BANK_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
- CCPLEX_RAS_NODE_LIST(DEFINE_ONE_RAS_NODE)
- /* Instantiate RAS node groups */
- static struct ras_aux_data per_core_ras_group[] = {
- PER_CORE_RAS_GROUP_NODES
- };
- CASSERT(ARRAY_SIZE(per_core_ras_group) < RAS_NODE_INDEX_MAX,
- assert_max_per_core_ras_group_size);
- static struct ras_aux_data per_cluster_ras_group[] = {
- PER_CLUSTER_RAS_GROUP_NODES
- };
- CASSERT(ARRAY_SIZE(per_cluster_ras_group) < RAS_NODE_INDEX_MAX,
- assert_max_per_cluster_ras_group_size);
- static struct ras_aux_data scf_l3_ras_group[] = {
- SCF_L3_BANK_RAS_GROUP_NODES
- };
- CASSERT(ARRAY_SIZE(scf_l3_ras_group) < RAS_NODE_INDEX_MAX,
- assert_max_scf_l3_ras_group_size);
- static struct ras_aux_data ccplex_ras_group[] = {
- CCPLEX_RAS_GROUP_NODES
- };
- CASSERT(ARRAY_SIZE(ccplex_ras_group) < RAS_NODE_INDEX_MAX,
- assert_max_ccplex_ras_group_size);
- /*
- * We have same probe and handler for each error record group, use a macro to
- * simply the record definition.
- */
- #define ADD_ONE_ERR_GROUP(errselr_start, group) \
- ERR_RECORD_SYSREG_V1((errselr_start), (uint32_t)ARRAY_SIZE((group)), \
- &tegra194_ras_record_probe, \
- &tegra194_ras_record_handler, (group))
- /* RAS error record group information */
- static struct err_record_info carmel_ras_records[] = {
- /*
- * Per core ras error records
- * ERRSELR starts from 0*256 + Logical_CPU_ID*16 + 0 to
- * 0*256 + Logical_CPU_ID*16 + 5 for each group.
- * 8 cores/groups, 6 * 8 nodes in total.
- */
- ADD_ONE_ERR_GROUP(0x000, per_core_ras_group),
- ADD_ONE_ERR_GROUP(0x010, per_core_ras_group),
- ADD_ONE_ERR_GROUP(0x020, per_core_ras_group),
- ADD_ONE_ERR_GROUP(0x030, per_core_ras_group),
- ADD_ONE_ERR_GROUP(0x040, per_core_ras_group),
- ADD_ONE_ERR_GROUP(0x050, per_core_ras_group),
- ADD_ONE_ERR_GROUP(0x060, per_core_ras_group),
- ADD_ONE_ERR_GROUP(0x070, per_core_ras_group),
- /*
- * Per cluster ras error records
- * ERRSELR starts from 2*256 + Logical_Cluster_ID*16 + 0 to
- * 2*256 + Logical_Cluster_ID*16 + 3.
- * 4 clusters/groups, 3 * 4 nodes in total.
- */
- ADD_ONE_ERR_GROUP(0x200, per_cluster_ras_group),
- ADD_ONE_ERR_GROUP(0x210, per_cluster_ras_group),
- ADD_ONE_ERR_GROUP(0x220, per_cluster_ras_group),
- ADD_ONE_ERR_GROUP(0x230, per_cluster_ras_group),
- /*
- * SCF L3_Bank ras error records
- * ERRSELR: 3*256 + L3_Bank_ID, L3_Bank_ID: 0-3
- * 1 groups, 4 nodes in total.
- */
- ADD_ONE_ERR_GROUP(0x300, scf_l3_ras_group),
- /*
- * CCPLEX ras error records
- * ERRSELR: 4*256 + Unit_ID, Unit_ID: 0 - 4
- * 1 groups, 5 nodes in total.
- */
- ADD_ONE_ERR_GROUP(0x400, ccplex_ras_group),
- };
- CASSERT(ARRAY_SIZE(carmel_ras_records) < RAS_NODE_INDEX_MAX,
- assert_max_carmel_ras_records_size);
- REGISTER_ERR_RECORD_INFO(carmel_ras_records);
- /* dummy RAS interrupt */
- static struct ras_interrupt carmel_ras_interrupts[] = {};
- REGISTER_RAS_INTERRUPTS(carmel_ras_interrupts);
- /*******************************************************************************
- * RAS handler for the platform
- ******************************************************************************/
- void plat_ea_handler(unsigned int ea_reason, uint64_t syndrome, void *cookie,
- void *handle, uint64_t flags)
- {
- #if ENABLE_FEAT_RAS
- tegra194_ea_handler(ea_reason, syndrome, cookie, handle, flags);
- #else
- plat_default_ea_handler(ea_reason, syndrome, cookie, handle, flags);
- #endif
- }
|