Tegra194: ras: verbose prints for SErrors
This patch provides verbose prints for RAS SErrors handled by the firmware, for improved debugging. Change-Id: Iaad8d183054d884f606dc4621da2cc6b2375bcf9 Signed-off-by: David Pu <dpu@nvidia.com> Signed-off-by: Varun Wadekar <vwadekar@nvidia.com>
This commit is contained in:
parent
fbc44bd1bb
commit
fba5cdc695
|
@ -18,6 +18,8 @@ struct ras_error {
|
||||||
|
|
||||||
/* RAS error node-specific auxiliary data */
|
/* RAS error node-specific auxiliary data */
|
||||||
struct ras_aux_data {
|
struct ras_aux_data {
|
||||||
|
/* name for current RAS node. */
|
||||||
|
const char *name;
|
||||||
/* point to null-terminated ras_error array to convert error code to msg. */
|
/* point to null-terminated ras_error array to convert error code to msg. */
|
||||||
const struct ras_error *error_records;
|
const struct ras_error *error_records;
|
||||||
/*
|
/*
|
||||||
|
@ -218,6 +220,7 @@ static inline uint64_t node##_err_ctrl(void) \
|
||||||
|
|
||||||
#define DEFINE_ONE_RAS_AUX_DATA(node) \
|
#define DEFINE_ONE_RAS_AUX_DATA(node) \
|
||||||
{ \
|
{ \
|
||||||
|
.name = #node, \
|
||||||
.error_records = node##_uncorr_ras_errors, \
|
.error_records = node##_uncorr_ras_errors, \
|
||||||
.err_ctrl = &node##_err_ctrl \
|
.err_ctrl = &node##_err_ctrl \
|
||||||
},
|
},
|
||||||
|
|
|
@ -42,8 +42,8 @@ static void tegra194_ea_handler(unsigned int ea_reason, uint64_t syndrome,
|
||||||
|
|
||||||
ras_lock();
|
ras_lock();
|
||||||
|
|
||||||
ERROR("exception reason=%u syndrome=0x%llx on 0x%lx at EL3.\n",
|
ERROR("MPIDR 0x%lx: exception reason=%u syndrome=0x%llx\n",
|
||||||
ea_reason, syndrome, read_mpidr_el1());
|
read_mpidr(), ea_reason, syndrome);
|
||||||
|
|
||||||
/* Call RAS EA handler */
|
/* Call RAS EA handler */
|
||||||
ret = ras_ea_handler(ea_reason, syndrome, cookie, handle, flags);
|
ret = ras_ea_handler(ea_reason, syndrome, cookie, handle, flags);
|
||||||
|
@ -198,47 +198,90 @@ static int32_t tegra194_ras_record_probe(const struct err_record_info *info,
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Function to handle error from one given node */
|
/* Function to handle error from one given node */
|
||||||
static int32_t tegra194_ras_node_handler(uint32_t errselr,
|
static int32_t tegra194_ras_node_handler(uint32_t errselr, const char *name,
|
||||||
const struct ras_error *errors, uint64_t status)
|
const struct ras_error *errors, uint64_t status)
|
||||||
{
|
{
|
||||||
bool found = false;
|
bool found = false;
|
||||||
uint32_t ierr = (uint32_t)ERR_STATUS_GET_FIELD(status, IERR);
|
uint32_t ierr = (uint32_t)ERR_STATUS_GET_FIELD(status, IERR);
|
||||||
uint32_t serr = (uint32_t)ERR_STATUS_GET_FIELD(status, SERR);
|
uint32_t serr = (uint32_t)ERR_STATUS_GET_FIELD(status, SERR);
|
||||||
|
uint64_t val = 0;
|
||||||
|
|
||||||
/* not a valid error. */
|
/* not a valid error. */
|
||||||
if (ERR_STATUS_GET_FIELD(status, V) == 0U) {
|
if (ERR_STATUS_GET_FIELD(status, V) == 0U) {
|
||||||
return 0;
|
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%llx\n", status);
|
||||||
|
|
||||||
/* Print uncorrectable errror information. */
|
/* Print uncorrectable errror information. */
|
||||||
if (ERR_STATUS_GET_FIELD(status, UE) != 0U) {
|
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 */
|
/* IERR to error message */
|
||||||
for (uint32_t i = 0; errors[i].error_msg != NULL; i++) {
|
for (uint32_t i = 0; errors[i].error_msg != NULL; i++) {
|
||||||
if (ierr == errors[i].error_code) {
|
if (ierr == errors[i].error_code) {
|
||||||
ERROR("ERRSELR_EL1:0x%x\n, IERR = %s(0x%x)\n",
|
ERROR("\tIERR = %s: 0x%x\n",
|
||||||
errselr, errors[i].error_msg,
|
errors[i].error_msg, ierr);
|
||||||
errors[i].error_code);
|
|
||||||
found = true;
|
found = true;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found) {
|
if (!found) {
|
||||||
ERROR("unknown uncorrectable eror, "
|
ERROR("\tUnknown IERR: 0x%x\n", ierr);
|
||||||
"ERRSELR_EL1:0x%x, IERR: 0x%x\n", errselr, 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);
|
||||||
}
|
}
|
||||||
|
|
||||||
ERROR("SERR = %s(0x%x)\n", ras_serr_to_str(serr), serr);
|
|
||||||
} else {
|
} else {
|
||||||
/* For corrected error, simply clear it. */
|
/* For corrected error, simply clear it. */
|
||||||
VERBOSE("corrected RAS error is cleared: ERRSELR_EL1:0x%x, "
|
VERBOSE("corrected RAS error is cleared: ERRSELR_EL1:0x%x, "
|
||||||
"IERR:0x%x, SERR:0x%x\n", errselr, ierr, serr);
|
"IERR:0x%x, SERR:0x%x\n", errselr, ierr, serr);
|
||||||
|
ERR_STATUS_SET_FIELD(val, CE, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write to clear reported errors. */
|
ERROR("**************************************\n");
|
||||||
write_erxstatus_el1(status);
|
|
||||||
|
|
||||||
|
/* Write to clear reported errors. */
|
||||||
|
write_erxstatus_el1(val);
|
||||||
|
|
||||||
|
/* error handled */
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,6 +294,7 @@ static int32_t tegra194_ras_record_handler(const struct err_record_info *info,
|
||||||
const struct ras_aux_data *aux_data = info->aux_data;
|
const struct ras_aux_data *aux_data = info->aux_data;
|
||||||
const struct ras_error *errors;
|
const struct ras_error *errors;
|
||||||
uint32_t offset;
|
uint32_t offset;
|
||||||
|
const char *node_name;
|
||||||
|
|
||||||
uint64_t status = 0ULL;
|
uint64_t status = 0ULL;
|
||||||
|
|
||||||
|
@ -261,6 +305,7 @@ static int32_t tegra194_ras_record_handler(const struct err_record_info *info,
|
||||||
|
|
||||||
offset = (uint32_t)probe_data;
|
offset = (uint32_t)probe_data;
|
||||||
errors = aux_data[offset].error_records;
|
errors = aux_data[offset].error_records;
|
||||||
|
node_name = aux_data[offset].name;
|
||||||
|
|
||||||
assert(errors != NULL);
|
assert(errors != NULL);
|
||||||
|
|
||||||
|
@ -270,7 +315,8 @@ static int32_t tegra194_ras_record_handler(const struct err_record_info *info,
|
||||||
/* Retrieve status register from the error record */
|
/* Retrieve status register from the error record */
|
||||||
status = read_erxstatus_el1();
|
status = read_erxstatus_el1();
|
||||||
|
|
||||||
return tegra194_ras_node_handler(idx_start + offset, errors, status);
|
return tegra194_ras_node_handler(idx_start + offset, node_name,
|
||||||
|
errors, status);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue