summaryrefslogtreecommitdiff
path: root/arch/mips/kernel/traps.c
diff options
context:
space:
mode:
authorPaul Burton <paul.burton@imgtec.com>2016-10-17 16:01:07 +0100
committerRalf Baechle <ralf@linux-mips.org>2017-01-03 16:34:41 +0100
commit35e6de38858f59b6b65dcfeaf700b5d06fc2b93d (patch)
tree3a4defbbbaedcdb55d53fd2194bea9d8ee69ca57 /arch/mips/kernel/traps.c
parentd65e5677ad5b3a49c43f60ec07644dc1f87bbd2e (diff)
MIPS: traps: Ensure L1 & L2 ECC checking match for CM3 systems
On systems with CM3, we must ensure that the L1 & L2 ECC enables are set to the same value. This is presumed by the hardware & cache corruption can occur when it is not the case. Support enabling & disabling the L2 ECC checking on CM3 systems where this is controlled via a GCR, and ensure that it matches the state of L1 ECC checking. Remove I6400 from the switch statement it will no longer hit, and which was incorrect since the L2 ECC enable bit isn't in the CP0 ErrCtl register. Signed-off-by: Paul Burton <paul.burton@imgtec.com> Cc: linux-mips@linux-mips.org Patchwork: https://patchwork.linux-mips.org/patch/14413/ Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
Diffstat (limited to 'arch/mips/kernel/traps.c')
-rw-r--r--arch/mips/kernel/traps.c63
1 files changed, 60 insertions, 3 deletions
diff --git a/arch/mips/kernel/traps.c b/arch/mips/kernel/traps.c
index 6c7f9d7e92b3..9ea6959cd5bb 100644
--- a/arch/mips/kernel/traps.c
+++ b/arch/mips/kernel/traps.c
@@ -51,6 +51,7 @@
#include <asm/idle.h>
#include <asm/mips-cm.h>
#include <asm/mips-r2-to-r6-emul.h>
+#include <asm/mips-cm.h>
#include <asm/mipsregs.h>
#include <asm/mipsmtregs.h>
#include <asm/module.h>
@@ -1644,6 +1645,65 @@ __setup("nol2par", nol2parity);
*/
static inline void parity_protection_init(void)
{
+#define ERRCTL_PE 0x80000000
+#define ERRCTL_L2P 0x00800000
+
+ if (mips_cm_revision() >= CM_REV_CM3) {
+ ulong gcr_ectl, cp0_ectl;
+
+ /*
+ * With CM3 systems we need to ensure that the L1 & L2
+ * parity enables are set to the same value, since this
+ * is presumed by the hardware engineers.
+ *
+ * If the user disabled either of L1 or L2 ECC checking,
+ * disable both.
+ */
+ l1parity &= l2parity;
+ l2parity &= l1parity;
+
+ /* Probe L1 ECC support */
+ cp0_ectl = read_c0_ecc();
+ write_c0_ecc(cp0_ectl | ERRCTL_PE);
+ back_to_back_c0_hazard();
+ cp0_ectl = read_c0_ecc();
+
+ /* Probe L2 ECC support */
+ gcr_ectl = read_gcr_err_control();
+
+ if (!(gcr_ectl & CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_MSK) ||
+ !(cp0_ectl & ERRCTL_PE)) {
+ /*
+ * One of L1 or L2 ECC checking isn't supported,
+ * so we cannot enable either.
+ */
+ l1parity = l2parity = 0;
+ }
+
+ /* Configure L1 ECC checking */
+ if (l1parity)
+ cp0_ectl |= ERRCTL_PE;
+ else
+ cp0_ectl &= ~ERRCTL_PE;
+ write_c0_ecc(cp0_ectl);
+ back_to_back_c0_hazard();
+ WARN_ON(!!(read_c0_ecc() & ERRCTL_PE) != l1parity);
+
+ /* Configure L2 ECC checking */
+ if (l2parity)
+ gcr_ectl |= CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK;
+ else
+ gcr_ectl &= ~CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK;
+ write_gcr_err_control(gcr_ectl);
+ gcr_ectl = read_gcr_err_control();
+ gcr_ectl &= CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK;
+ WARN_ON(!!gcr_ectl != l2parity);
+
+ pr_info("Cache parity protection %sabled\n",
+ l1parity ? "en" : "dis");
+ return;
+ }
+
switch (current_cpu_type()) {
case CPU_24K:
case CPU_34K:
@@ -1654,11 +1714,8 @@ static inline void parity_protection_init(void)
case CPU_PROAPTIV:
case CPU_P5600:
case CPU_QEMU_GENERIC:
- case CPU_I6400:
case CPU_P6600:
{
-#define ERRCTL_PE 0x80000000
-#define ERRCTL_L2P 0x00800000
unsigned long errctl;
unsigned int l1parity_present, l2parity_present;