[v2,13/15] opal/hmi: check thread 0 tfmr to validate latched tfmr errors.

Message ID 152390006303.2566.6880660025273037550.stgit@jupiter.in.ibm.com
State Accepted
Headers show
Series
  • opal/hmi: Rework HMI handling.
Related show

Commit Message

Mahesh Jagannath Salgaonkar April 16, 2018, 5:34 p.m.
From: Mahesh Salgaonkar <mahesh@linux.vnet.ibm.com>

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 <mahesh@linux.vnet.ibm.com>
---
 core/hmi.c              |   61 ++++++++++++++++++++++++++++++++---------------
 include/xscom-p9-regs.h |    8 ++++++
 2 files changed, 50 insertions(+), 19 deletions(-)

Patch

diff --git a/core/hmi.c b/core/hmi.c
index b062428a3..9b98fbd98 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 4738e812c..c3322499f 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__ */