From 5362f85e04bd1b03d94711c62c20de3111234f25 Mon Sep 17 00:00:00 2001 From: Mahesh Salgaonkar Date: Mon, 16 Apr 2018 23:04:23 +0530 Subject: opal/hmi: check thread 0 tfmr to validate latched tfmr errors. Due to P9 errata, HDEC parity and TB residue errors are latched for non-zero threads 1-3 even if they are cleared. But these are not latched on thread 0. Hence, use xscom SCOMC/SCOMD to read thread 0 tfmr value and ignore them on non-zero threads if they are not present on thread 0. Signed-off-by: Mahesh Salgaonkar Signed-off-by: Stewart Smith --- core/hmi.c | 61 ++++++++++++++++++++++++++++++++++--------------- include/xscom-p9-regs.h | 8 +++++++ 2 files changed, 50 insertions(+), 19 deletions(-) diff --git a/core/hmi.c b/core/hmi.c index b062428a..9b98fbd9 100644 --- a/core/hmi.c +++ b/core/hmi.c @@ -22,6 +22,7 @@ #include #include #include +#include #include #include #include @@ -1047,6 +1048,45 @@ error_out: return recover; } +static uint64_t read_tfmr_t0(void) +{ + uint64_t tfmr_t0; + uint32_t chip_id = this_cpu()->chip_id; + uint32_t core_id = pir_to_core_id(this_cpu()->pir); + + lock(&hmi_lock); + + xscom_write(chip_id, XSCOM_ADDR_P9_EC(core_id, P9_SCOM_SPRC), + SETFIELD(P9_SCOMC_SPR_SELECT, 0, P9_SCOMC_TFMR_T0)); + xscom_read(chip_id, XSCOM_ADDR_P9_EC(core_id, P9_SCOM_SPRD), + &tfmr_t0); + unlock(&hmi_lock); + return tfmr_t0; +} + +/* P9 errata: In theory, an HDEC error is sent to all threads. However, + * due to an errata on P9 where TFMR bit 26 (HDEC parity) cannot be + * cleared on thread 1..3, I am not confident we can do a rendez-vous + * in all cases. + * + * Our current approach is to ignore that error unless it is present + * on thread 0 TFMR. Also, ignore TB residue error due to a similar + * errata as above. + */ +static void validate_latched_errors(uint64_t *tfmr) +{ + if ((*tfmr & (SPR_TFMR_HDEC_PARITY_ERROR | SPR_TFMR_TB_RESIDUE_ERR)) + && this_cpu()->is_secondary) { + uint64_t tfmr_t0 = read_tfmr_t0(); + + if (!(tfmr_t0 & SPR_TFMR_HDEC_PARITY_ERROR)) + *tfmr &= ~SPR_TFMR_HDEC_PARITY_ERROR; + + if (!(tfmr_t0 & SPR_TFMR_TB_RESIDUE_ERR)) + *tfmr &= ~SPR_TFMR_TB_RESIDUE_ERR; + } +} + static int handle_tfac_errors(struct OpalHMIEvent *hmi_evt, uint64_t *out_flags) { int recover = -1; @@ -1063,25 +1103,8 @@ static int handle_tfac_errors(struct OpalHMIEvent *hmi_evt, uint64_t *out_flags) this_cpu()->tb_invalid = !(tfmr & SPR_TFMR_TB_VALID); - /* P9 errata: In theory, an HDEC error is sent to all threads. However, - * due to an errata on P9 where TFMR bit 26 (HDEC parity) cannot be - * cleared on thread 1..3, I am not confident we can do a rendez-vous - * in all cases. - * - * Our current approach is to ignore that error unless no other TFAC - * error is present in the TFMR. The error will be re-detected and - * re-reported if necessary. - */ - if (proc_gen == proc_gen_p9 && (tfmr & SPR_TFMR_HDEC_PARITY_ERROR)) { - if (this_cpu()->tb_invalid || (tfmr & SPR_TFMR_OTHER_ERRORS)) - tfmr &= ~SPR_TFMR_HDEC_PARITY_ERROR; - } - - /* The TB residue error is ignored if TB is valid due to a similar - * errata as above - */ - if ((tfmr & SPR_TFMR_TB_RESIDUE_ERR) && !this_cpu()->tb_invalid) - tfmr &= ~SPR_TFMR_TB_RESIDUE_ERR; + if (proc_gen == proc_gen_p9) + validate_latched_errors(&tfmr); /* First, handle thread local errors */ if (tfmr & SPR_TFMR_THREAD_ERRORS) { diff --git a/include/xscom-p9-regs.h b/include/xscom-p9-regs.h index 4738e812..c3322499 100644 --- a/include/xscom-p9-regs.h +++ b/include/xscom-p9-regs.h @@ -21,4 +21,12 @@ #define P9_GPIO_DATA_OUT_ENABLE 0x00000000000B0054ull #define P9_GPIO_DATA_OUT 0x00000000000B0051ull +/* xscom address for SCOM Control and data Register */ +/* bits 54:60 of SCOM SPRC register is used for core specific SPR selection. */ +#define P9_SCOM_SPRC 0x20010A80 +#define P9_SCOMC_SPR_SELECT PPC_BITMASK(54, 60) +#define P9_SCOMC_TFMR_T0 0x8 /* 0b0001000 TFMR */ + +#define P9_SCOM_SPRD 0x20010A81 + #endif /* __XSCOM_P9_REGS_H__ */ -- cgit v1.2.1