diff options
author | Stepan Moskovchenko <stepanm@codeaurora.org> | 2015-10-20 18:13:59 -0700 |
---|---|---|
committer | Jeevan Shriram <jshriram@codeaurora.org> | 2016-04-05 11:31:58 -0700 |
commit | 0763a08bad3ad40cc3f531bd8bfc83332dedacfe (patch) | |
tree | 7d38d0bd7b84246f5884e9dc623cc7eedc8585f5 /drivers/edac | |
parent | 15a734e879e68f10b941290653a3175b128ad9d3 (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.c | 88 |
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); } |