summaryrefslogtreecommitdiff
path: root/drivers/edac
diff options
context:
space:
mode:
authorStepan Moskovchenko <stepanm@codeaurora.org>2015-10-20 18:13:59 -0700
committerJeevan Shriram <jshriram@codeaurora.org>2016-04-05 11:31:58 -0700
commit0763a08bad3ad40cc3f531bd8bfc83332dedacfe (patch)
tree7d38d0bd7b84246f5884e9dc623cc7eedc8585f5 /drivers/edac
parent15a734e879e68f10b941290653a3175b128ad9d3 (diff)
edac: cortex: Support L2 error reporting on Kryo2xx Gold CPUs
Decode and print the L2 error state registers on Kryo2xx Gold CPUs. CRs-Fixed: 969563 Change-Id: If9ec89ab2f2ea341f38d8952c1688d277a5082ed Signed-off-by: Stepan Moskovchenko <stepanm@codeaurora.org>
Diffstat (limited to 'drivers/edac')
-rw-r--r--drivers/edac/cortex_arm64_edac.c88
1 files changed, 87 insertions, 1 deletions
diff --git a/drivers/edac/cortex_arm64_edac.c b/drivers/edac/cortex_arm64_edac.c
index d134e8822c9d..2268bd3fa8f0 100644
--- a/drivers/edac/cortex_arm64_edac.c
+++ b/drivers/edac/cortex_arm64_edac.c
@@ -1,4 +1,4 @@
-/* Copyright (c) 2014-2015, The Linux Foundation. All rights reserved.
+/* Copyright (c) 2014-2016, The Linux Foundation. All rights reserved.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License version 2 and
@@ -63,6 +63,14 @@
#define A57_L2MERRSR_CPUID(a) (((a) >> 18) & 0x0f)
#define A57_L2MERRSR_INDEX(a) ((a) & 0x1ffff)
+#define KRYO2XX_GOLD_L2MERRSR_FATAL(a) ((a) & (1LL << 63))
+#define KRYO2XX_GOLD_L2MERRSR_OTHER(a) (((a) >> 40) & 0x3f)
+#define KRYO2XX_GOLD_L2MERRSR_REPT(a) (((a) >> 32) & 0x3f)
+#define KRYO2XX_GOLD_L2MERRSR_VALID(a) ((a) & (1 << 31))
+#define KRYO2XX_GOLD_L2MERRSR_RAMID(a) ((a) & (1 << 24))
+#define KRYO2XX_GOLD_L2MERRSR_WAY(a) (((a) >> 18) & 0x0f)
+#define KRYO2XX_GOLD_L2MERRSR_INDEX(a) (((a) >> 3) & 0x3fff)
+
#define L2ECTLR_INT_ERR (1 << 30)
#define L2ECTLR_EXT_ERR (1 << 29)
@@ -220,6 +228,32 @@ static void ca53_ca57_print_error_state_regs(void)
"Double bit error on dirty L2 cacheline\n");
}
+static void kryo2xx_gold_print_error_state_regs(void)
+{
+ u64 l2merrsr;
+ u32 esr_el1;
+ u32 l2ectlr;
+
+ l2merrsr = read_l2merrsr_el1;
+ esr_el1 = read_esr_el1;
+ l2ectlr = read_l2ectlr_el1;
+
+ uncached_logk_pc(LOGK_READL, __builtin_return_address(0),
+ (void *)l2merrsr);
+ uncached_logk_pc(LOGK_READL, __builtin_return_address(0),
+ (void *)((u64)esr_el1));
+ uncached_logk_pc(LOGK_READL, __builtin_return_address(0),
+ (void *)((u64)l2ectlr));
+
+ edac_printk(KERN_CRIT, EDAC_CPU, "L2MERRSR value = %#llx\n", l2merrsr);
+
+ edac_printk(KERN_CRIT, EDAC_CPU, "ESR value = %#x\n", esr_el1);
+ edac_printk(KERN_CRIT, EDAC_CPU, "L2ECTLR value = %#x\n", l2ectlr);
+ if (ESR_L2_DBE(esr_el1))
+ edac_printk(KERN_CRIT, EDAC_CPU,
+ "Double bit error on dirty L2 cacheline\n");
+}
+
static void ca53_parse_cpumerrsr(struct erp_local_data *ed)
{
u64 cpumerrsr;
@@ -480,6 +514,50 @@ static void ca57_parse_l2merrsr(struct erp_local_data *ed)
write_l2merrsr_el1(0);
}
+
+static void kryo2xx_gold_parse_l2merrsr(struct erp_local_data *ed)
+{
+ u64 l2merrsr;
+ int ramid, way;
+
+ l2merrsr = read_l2merrsr_el1;
+
+ if (!KRYO2XX_GOLD_L2MERRSR_VALID(l2merrsr))
+ return;
+
+ if (KRYO2XX_GOLD_L2MERRSR_FATAL(l2merrsr))
+ ed->err = DBE;
+
+ edac_printk(KERN_CRIT, EDAC_CPU, "Gold L2 %s Error detected\n",
+ err_name[ed->err]);
+ kryo2xx_gold_print_error_state_regs();
+ if (ed->err == DBE)
+ edac_printk(KERN_CRIT, EDAC_CPU, "Fatal error\n");
+
+ way = KRYO2XX_GOLD_L2MERRSR_WAY(l2merrsr);
+ ramid = KRYO2XX_GOLD_L2MERRSR_RAMID(l2merrsr);
+
+ edac_printk(KERN_CRIT, EDAC_CPU,
+ "L2 %s RAM error in way 0x%02x, index 0x%04x\n",
+ ramid ? "data" : "tag",
+ (int) KRYO2XX_GOLD_L2MERRSR_WAY(l2merrsr),
+ (int) KRYO2XX_GOLD_L2MERRSR_INDEX(l2merrsr));
+
+ edac_printk(KERN_CRIT, EDAC_CPU, "Repeated error count: %d\n",
+ (int) KRYO2XX_GOLD_L2MERRSR_REPT(l2merrsr));
+ edac_printk(KERN_CRIT, EDAC_CPU, "Other error count: %d\n",
+ (int) KRYO2XX_GOLD_L2MERRSR_OTHER(l2merrsr));
+
+ if (ed->err == SBE) {
+ errors[A57_L2_CE].func(ed->drv->edev_ctl, smp_processor_id(),
+ L2_CACHE, errors[A57_L2_CE].msg);
+ } else if (ed->err == DBE) {
+ errors[A57_L2_UE].func(ed->drv->edev_ctl, smp_processor_id(),
+ L2_CACHE, errors[A57_L2_UE].msg);
+ }
+ write_l2merrsr_el1(0);
+}
+
static DEFINE_SPINLOCK(local_handler_lock);
static DEFINE_SPINLOCK(l2ectlr_lock);
@@ -508,6 +586,10 @@ static void arm64_erp_local_handler(void *info)
ca57_parse_l2merrsr(errdata);
break;
+ case ARM_CPU_PART_KRYO2XX_GOLD:
+ kryo2xx_gold_parse_l2merrsr(errdata);
+ break;
+
default:
edac_printk(KERN_CRIT, EDAC_CPU, "Unknown CPU Part Number in MIDR: %#04x (%#08x)\n",
partnum, cpuid);
@@ -675,6 +757,10 @@ static void check_sbe_event(struct erp_drvdata *drv)
ca57_parse_cpumerrsr(&errdata);
ca57_parse_l2merrsr(&errdata);
break;
+
+ case ARM_CPU_PART_KRYO2XX_GOLD:
+ kryo2xx_gold_parse_l2merrsr(&errdata);
+ break;
};
spin_unlock_irqrestore(&local_handler_lock, flags);
}