diff --git a/arch/mips/include/asm/mips-cm.h b/arch/mips/include/asm/mips-cm.h index 2e4180797b21..cfdbab015769 100644 --- a/arch/mips/include/asm/mips-cm.h +++ b/arch/mips/include/asm/mips-cm.h @@ -187,6 +187,7 @@ BUILD_CM_R_(config, MIPS_CM_GCB_OFS + 0x00) BUILD_CM_RW(base, MIPS_CM_GCB_OFS + 0x08) BUILD_CM_RW(access, MIPS_CM_GCB_OFS + 0x20) BUILD_CM_R_(rev, MIPS_CM_GCB_OFS + 0x30) +BUILD_CM_RW(err_control, MIPS_CM_GCB_OFS + 0x38) BUILD_CM_RW(error_mask, MIPS_CM_GCB_OFS + 0x40) BUILD_CM_RW(error_cause, MIPS_CM_GCB_OFS + 0x48) BUILD_CM_RW(error_addr, MIPS_CM_GCB_OFS + 0x50) @@ -266,6 +267,12 @@ BUILD_CM_Cx_R_(tcid_8_priority, 0x80) #define CM_REV_CM2_5 CM_ENCODE_REV(7, 0) #define CM_REV_CM3 CM_ENCODE_REV(8, 0) +/* GCR_ERR_CONTROL register fields */ +#define CM_GCR_ERR_CONTROL_L2_ECC_EN_SHF 1 +#define CM_GCR_ERR_CONTROL_L2_ECC_EN_MSK (_ULCAST_(0x1) << 1) +#define CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_SHF 0 +#define CM_GCR_ERR_CONTROL_L2_ECC_SUPPORT_MSK (_ULCAST_(0x1) << 0) + /* GCR_ERROR_CAUSE register fields */ #define CM_GCR_ERROR_CAUSE_ERRTYPE_SHF 27 #define CM_GCR_ERROR_CAUSE_ERRTYPE_MSK (_ULCAST_(0x1f) << 27) 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 #include #include +#include #include #include #include @@ -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;