aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--core/hmi.c61
-rw-r--r--include/xscom-p9-regs.h8
2 files changed, 50 insertions, 19 deletions
diff --git a/core/hmi.c b/core/hmi.c
index b062428..9b98fbd 100644
--- a/core/hmi.c
+++ b/core/hmi.c
@@ -22,6 +22,7 @@
#include <processor.h>
#include <chiptod.h>
#include <xscom.h>
+#include <xscom-p9-regs.h>
#include <pci.h>
#include <cpu.h>
#include <chip.h>
@@ -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 4738e81..c332249 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__ */